@backtest-kit/cli 7.1.0 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/build/index.cjs +376 -149
- package/build/index.mjs +379 -152
- package/config/notification.config.mjs +13 -0
- package/config/symbol.config.mjs +460 -0
- package/package.json +16 -15
- package/template/average-buy.mustache +2 -0
- package/template/breakeven.mustache +2 -0
- package/template/cancel-scheduled.mustache +1 -1
- package/template/cancelled.mustache +2 -0
- package/template/close-pending.mustache +2 -0
- package/template/closed.mustache +2 -0
- package/template/opened.mustache +2 -0
- package/template/partial-loss.mustache +2 -0
- package/template/partial-profit.mustache +2 -0
- package/template/project/package.mustache +7 -7
- package/template/scheduled.mustache +2 -0
- package/template/signal-close.mustache +2 -0
- package/template/signal-info.mustache +21 -0
- package/template/signal-open.mustache +2 -0
- package/template/trailing-stop.mustache +2 -0
- package/template/trailing-take.mustache +2 -0
- package/types.d.ts +149 -39
- /package/template/project/config/{symbol.config.cjs → symbol.config.ts} +0 -0
package/build/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as BacktestKit from 'backtest-kit';
|
|
3
|
-
import { Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal,
|
|
4
|
-
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, createAwaiter, execpool, queued, sleep, randomString, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize } from 'functools-kit';
|
|
3
|
+
import { setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, Notification, Recent, Storage, Markdown, Report, Dump, Memory, StorageLive, StorageBacktest, RecentLive, RecentBacktest, NotificationLive, NotificationBacktest, MarkdownWriter, ReportWriter, PersistSignalAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistPartialAdapter, PersistBreakevenAdapter, PersistCandleAdapter, PersistStorageAdapter, PersistNotificationAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistIntervalAdapter, PersistMemoryAdapter, PersistRecentAdapter, listStrategySchema, overrideExchangeSchema, Backtest, Session, Cache, Interval, alignToInterval, addWalkerSchema, overrideWalkerSchema, Walker, listenDoneWalker, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync, listenSignalNotify, Exchange } from 'backtest-kit';
|
|
4
|
+
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, createAwaiter, execpool, queued, sleep, randomString, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize, isObject } from 'functools-kit';
|
|
5
5
|
import fs, { constants } from 'fs';
|
|
6
6
|
import * as stackTrace from 'stack-trace';
|
|
7
7
|
import path, { join, resolve, dirname, basename, extname } from 'path';
|
|
@@ -12,7 +12,7 @@ import { fileURLToPath } from 'url';
|
|
|
12
12
|
import ccxt from 'ccxt';
|
|
13
13
|
import { parseArgs } from 'util';
|
|
14
14
|
import * as BacktestKitUi from '@backtest-kit/ui';
|
|
15
|
-
import { serve } from '@backtest-kit/ui';
|
|
15
|
+
import { lib, serve } from '@backtest-kit/ui';
|
|
16
16
|
import QuickChart from 'quickchart-js';
|
|
17
17
|
import { Telegraf, Input } from 'telegraf';
|
|
18
18
|
import imageSize from 'image-size';
|
|
@@ -63,6 +63,38 @@ import { spawn } from 'child_process';
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
setConfig({
|
|
67
|
+
CC_MAX_NOTIFICATIONS: 5000,
|
|
68
|
+
CC_MAX_SIGNALS: 750,
|
|
69
|
+
});
|
|
70
|
+
setConfig({
|
|
71
|
+
CC_ENABLE_DCA_EVERYWHERE: true,
|
|
72
|
+
CC_ENABLE_PPPL_EVERYWHERE: true,
|
|
73
|
+
CC_ENABLE_TRAILING_EVERYWHERE: true,
|
|
74
|
+
});
|
|
75
|
+
setConfig({
|
|
76
|
+
CC_MAX_SIGNAL_GENERATION_SECONDS: 15 * 60,
|
|
77
|
+
});
|
|
78
|
+
setConfig({
|
|
79
|
+
CC_MAX_BACKTEST_MARKDOWN_ROWS: 1000,
|
|
80
|
+
CC_MAX_BREAKEVEN_MARKDOWN_ROWS: 1000,
|
|
81
|
+
CC_MAX_HEATMAP_MARKDOWN_ROWS: 1000,
|
|
82
|
+
CC_MAX_HIGHEST_PROFIT_MARKDOWN_ROWS: 1000,
|
|
83
|
+
CC_MAX_LIVE_MARKDOWN_ROWS: 1000,
|
|
84
|
+
CC_MAX_PARTIAL_MARKDOWN_ROWS: 1000,
|
|
85
|
+
CC_MAX_RISK_MARKDOWN_ROWS: 1000,
|
|
86
|
+
CC_MAX_SCHEDULE_MARKDOWN_ROWS: 1000,
|
|
87
|
+
CC_MAX_STRATEGY_MARKDOWN_ROWS: 1000,
|
|
88
|
+
CC_MAX_SYNC_MARKDOWN_ROWS: 1000,
|
|
89
|
+
CC_MAX_PERFORMANCE_MARKDOWN_ROWS: 1000,
|
|
90
|
+
});
|
|
91
|
+
setConfig({
|
|
92
|
+
CC_MAX_SIGNAL_LIFETIME_MINUTES: Infinity,
|
|
93
|
+
});
|
|
94
|
+
setConfig({
|
|
95
|
+
CC_WALKER_MARKDOWN_TOP_N: 10,
|
|
96
|
+
});
|
|
97
|
+
|
|
66
98
|
const ERROR_HANDLER_INSTALLED = Symbol.for("error-handler-installed");
|
|
67
99
|
function dumpStackTrace() {
|
|
68
100
|
const trace = stackTrace.get();
|
|
@@ -158,12 +190,16 @@ const apiServices$1 = {
|
|
|
158
190
|
const baseServices$1 = {
|
|
159
191
|
errorService: Symbol('errorService'),
|
|
160
192
|
loggerService: Symbol('loggerService'),
|
|
193
|
+
};
|
|
194
|
+
const coreServices$1 = {
|
|
161
195
|
resolveService: Symbol('resolveService'),
|
|
162
196
|
loaderService: Symbol('loaderService'),
|
|
197
|
+
configService: Symbol('configService'),
|
|
163
198
|
babelService: Symbol('babelService'),
|
|
164
199
|
};
|
|
165
200
|
const connectionServices$1 = {
|
|
166
201
|
moduleConnectionService: Symbol('moduleConnectionService'),
|
|
202
|
+
configConnectionService: Symbol('configConnectionService'),
|
|
167
203
|
};
|
|
168
204
|
const mainServices$1 = {
|
|
169
205
|
backtestMainService: Symbol('backtestMainService'),
|
|
@@ -193,6 +229,7 @@ const templateServices$1 = {
|
|
|
193
229
|
const TYPES = {
|
|
194
230
|
...apiServices$1,
|
|
195
231
|
...baseServices$1,
|
|
232
|
+
...coreServices$1,
|
|
196
233
|
...connectionServices$1,
|
|
197
234
|
...mainServices$1,
|
|
198
235
|
...logicServices$1,
|
|
@@ -213,8 +250,10 @@ class ResolveService {
|
|
|
213
250
|
this.loaderService = inject(TYPES.loaderService);
|
|
214
251
|
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$1, '..', 'template');
|
|
215
252
|
this.DEFAULT_MODULES_DIR = path.resolve(__dirname$1, '..', 'modules');
|
|
253
|
+
this.DEFAULT_CONFIG_DIR = path.resolve(__dirname$1, '..', 'config');
|
|
216
254
|
this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
|
|
217
255
|
this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
|
|
256
|
+
this.OVERRIDE_CONFIG_DIR = path.resolve(process.cwd(), 'config');
|
|
218
257
|
this.PROJECT_ROOT_DIR = process.cwd();
|
|
219
258
|
this.getIsLaunched = () => {
|
|
220
259
|
this.loggerService.log("resolveService getIsLaunched");
|
|
@@ -391,6 +430,10 @@ const ALLOWED_EXTENSIONS = [
|
|
|
391
430
|
const DISALLOWED_PATHS = [
|
|
392
431
|
"node_modules",
|
|
393
432
|
"@backtest-kit",
|
|
433
|
+
"build/index.mjs",
|
|
434
|
+
"build/index.js",
|
|
435
|
+
"build\\index.mjs",
|
|
436
|
+
"build\\index.js",
|
|
394
437
|
];
|
|
395
438
|
const getArgs = singleshot(() => {
|
|
396
439
|
const { values, positionals } = parseArgs({
|
|
@@ -632,6 +675,105 @@ const notifyVerbose = singleshot(() => {
|
|
|
632
675
|
});
|
|
633
676
|
});
|
|
634
677
|
|
|
678
|
+
class SetupUtils {
|
|
679
|
+
constructor() {
|
|
680
|
+
this.enable = singleshot(() => {
|
|
681
|
+
cli.loggerService.debug("SetupUtils enable");
|
|
682
|
+
{
|
|
683
|
+
const config = cli.configService.getNotificationConfig();
|
|
684
|
+
Notification.enable(config);
|
|
685
|
+
}
|
|
686
|
+
{
|
|
687
|
+
Recent.enable();
|
|
688
|
+
Storage.enable();
|
|
689
|
+
}
|
|
690
|
+
{
|
|
691
|
+
Markdown.enable();
|
|
692
|
+
Report.enable();
|
|
693
|
+
Dump.enable();
|
|
694
|
+
Memory.enable();
|
|
695
|
+
}
|
|
696
|
+
{
|
|
697
|
+
Dump.useMarkdown();
|
|
698
|
+
Memory.usePersist();
|
|
699
|
+
}
|
|
700
|
+
{
|
|
701
|
+
StorageLive.usePersist();
|
|
702
|
+
StorageBacktest.useMemory();
|
|
703
|
+
}
|
|
704
|
+
{
|
|
705
|
+
RecentLive.usePersist();
|
|
706
|
+
RecentBacktest.useMemory();
|
|
707
|
+
}
|
|
708
|
+
{
|
|
709
|
+
NotificationLive.usePersist();
|
|
710
|
+
NotificationBacktest.useMemory();
|
|
711
|
+
}
|
|
712
|
+
{
|
|
713
|
+
Markdown.useDummy();
|
|
714
|
+
Log.useJsonl();
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
this.clear = () => {
|
|
718
|
+
cli.loggerService.debug("SetupUtils clear");
|
|
719
|
+
if (!this.enable.hasValue()) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
this.enable.clear();
|
|
723
|
+
{
|
|
724
|
+
Recent.disable();
|
|
725
|
+
Storage.disable();
|
|
726
|
+
Notification.disable();
|
|
727
|
+
}
|
|
728
|
+
{
|
|
729
|
+
Markdown.disable();
|
|
730
|
+
Report.disable();
|
|
731
|
+
Dump.disable();
|
|
732
|
+
Memory.disable();
|
|
733
|
+
}
|
|
734
|
+
{
|
|
735
|
+
Markdown.clear();
|
|
736
|
+
Report.clear();
|
|
737
|
+
MarkdownWriter.clear();
|
|
738
|
+
ReportWriter.clear();
|
|
739
|
+
}
|
|
740
|
+
{
|
|
741
|
+
PersistSignalAdapter.clear();
|
|
742
|
+
PersistRiskAdapter.clear();
|
|
743
|
+
PersistScheduleAdapter.clear();
|
|
744
|
+
PersistPartialAdapter.clear();
|
|
745
|
+
PersistBreakevenAdapter.clear();
|
|
746
|
+
PersistCandleAdapter.clear();
|
|
747
|
+
PersistStorageAdapter.clear();
|
|
748
|
+
PersistNotificationAdapter.clear();
|
|
749
|
+
PersistLogAdapter.clear();
|
|
750
|
+
PersistMeasureAdapter.clear();
|
|
751
|
+
PersistIntervalAdapter.clear();
|
|
752
|
+
PersistMemoryAdapter.clear();
|
|
753
|
+
PersistRecentAdapter.clear();
|
|
754
|
+
}
|
|
755
|
+
{
|
|
756
|
+
Dump.clear();
|
|
757
|
+
Log.clear();
|
|
758
|
+
Markdown.clear();
|
|
759
|
+
}
|
|
760
|
+
{
|
|
761
|
+
StorageLive.clear();
|
|
762
|
+
StorageBacktest.clear();
|
|
763
|
+
}
|
|
764
|
+
{
|
|
765
|
+
NotificationLive.clear();
|
|
766
|
+
NotificationBacktest.clear();
|
|
767
|
+
}
|
|
768
|
+
{
|
|
769
|
+
RecentLive.clear();
|
|
770
|
+
RecentBacktest.clear();
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
const Setup = new SetupUtils();
|
|
776
|
+
|
|
635
777
|
const DEFAULT_CACHE_LIST$1 = ["1m", "15m", "30m", "1h", "4h"];
|
|
636
778
|
const GET_CACHE_INTERVAL_LIST_FN$1 = () => {
|
|
637
779
|
const { values } = getArgs();
|
|
@@ -646,6 +788,7 @@ class BacktestMainService {
|
|
|
646
788
|
constructor() {
|
|
647
789
|
this.loggerService = inject(TYPES.loggerService);
|
|
648
790
|
this.resolveService = inject(TYPES.resolveService);
|
|
791
|
+
this.configService = inject(TYPES.configService);
|
|
649
792
|
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
650
793
|
this.frameSchemaService = inject(TYPES.frameSchemaService);
|
|
651
794
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
@@ -657,6 +800,10 @@ class BacktestMainService {
|
|
|
657
800
|
this.loggerService.log("backtestMainService run", {
|
|
658
801
|
payload,
|
|
659
802
|
});
|
|
803
|
+
{
|
|
804
|
+
await this.configService.waitForInit();
|
|
805
|
+
Setup.enable();
|
|
806
|
+
}
|
|
660
807
|
{
|
|
661
808
|
this.frontendProviderService.connect();
|
|
662
809
|
this.telegramProviderService.connect();
|
|
@@ -759,12 +906,17 @@ class WalkerMainService {
|
|
|
759
906
|
constructor() {
|
|
760
907
|
this.loggerService = inject(TYPES.loggerService);
|
|
761
908
|
this.resolveService = inject(TYPES.resolveService);
|
|
909
|
+
this.configService = inject(TYPES.configService);
|
|
762
910
|
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
763
911
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
764
912
|
this.cacheLogicService = inject(TYPES.cacheLogicService);
|
|
765
913
|
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
766
914
|
this.run = singleshot(async (payload) => {
|
|
767
915
|
this.loggerService.log("walkerMainService run", { payload });
|
|
916
|
+
{
|
|
917
|
+
await this.configService.waitForInit();
|
|
918
|
+
Setup.enable();
|
|
919
|
+
}
|
|
768
920
|
const strategyMap = new Map();
|
|
769
921
|
const sessionMap = new Map();
|
|
770
922
|
const cwd = process.cwd();
|
|
@@ -970,6 +1122,7 @@ class LiveMainService {
|
|
|
970
1122
|
constructor() {
|
|
971
1123
|
this.loggerService = inject(TYPES.loggerService);
|
|
972
1124
|
this.resolveService = inject(TYPES.resolveService);
|
|
1125
|
+
this.configService = inject(TYPES.configService);
|
|
973
1126
|
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
974
1127
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
975
1128
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
@@ -979,6 +1132,10 @@ class LiveMainService {
|
|
|
979
1132
|
this.loggerService.log("liveMainService run", {
|
|
980
1133
|
payload,
|
|
981
1134
|
});
|
|
1135
|
+
{
|
|
1136
|
+
await this.configService.waitForInit();
|
|
1137
|
+
Setup.enable();
|
|
1138
|
+
}
|
|
982
1139
|
{
|
|
983
1140
|
this.frontendProviderService.connect();
|
|
984
1141
|
this.telegramProviderService.connect();
|
|
@@ -1047,6 +1204,7 @@ class PaperMainService {
|
|
|
1047
1204
|
constructor() {
|
|
1048
1205
|
this.loggerService = inject(TYPES.loggerService);
|
|
1049
1206
|
this.resolveService = inject(TYPES.resolveService);
|
|
1207
|
+
this.configService = inject(TYPES.configService);
|
|
1050
1208
|
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
1051
1209
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
1052
1210
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
@@ -1054,6 +1212,10 @@ class PaperMainService {
|
|
|
1054
1212
|
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
1055
1213
|
this.run = singleshot(async (payload) => {
|
|
1056
1214
|
this.loggerService.log("paperMainService init");
|
|
1215
|
+
{
|
|
1216
|
+
await this.configService.waitForInit();
|
|
1217
|
+
Setup.enable();
|
|
1218
|
+
}
|
|
1057
1219
|
{
|
|
1058
1220
|
this.frontendProviderService.connect();
|
|
1059
1221
|
this.telegramProviderService.connect();
|
|
@@ -1131,16 +1293,72 @@ const getEnv = singleshot(() => {
|
|
|
1131
1293
|
};
|
|
1132
1294
|
});
|
|
1133
1295
|
|
|
1296
|
+
const GET_SYMBOL_EXPORTS_FN = async (self) => {
|
|
1297
|
+
const exports = await self.configConnectionService.loadConfig("symbol.config");
|
|
1298
|
+
if (!exports) {
|
|
1299
|
+
return null;
|
|
1300
|
+
}
|
|
1301
|
+
return "default" in exports
|
|
1302
|
+
? exports.default
|
|
1303
|
+
: exports;
|
|
1304
|
+
};
|
|
1305
|
+
const GET_SYMBOL_CONFIG_FN = async (self) => {
|
|
1306
|
+
const config = await GET_SYMBOL_EXPORTS_FN(self);
|
|
1307
|
+
if (!config) {
|
|
1308
|
+
throw new Error("FrontendProviderService getSymbolConfig `symbol.config` is not found");
|
|
1309
|
+
}
|
|
1310
|
+
if (Array.isArray(config)) {
|
|
1311
|
+
return config;
|
|
1312
|
+
}
|
|
1313
|
+
if ("symbol_list" in config) {
|
|
1314
|
+
return config.symbol_list;
|
|
1315
|
+
}
|
|
1316
|
+
throw new Error("FrontendProviderService getSymbolConfig `symbol.config` is not found");
|
|
1317
|
+
};
|
|
1318
|
+
const MAP_SYMBOL_CONFIG_FN = (config) => {
|
|
1319
|
+
const uniqueSymbols = new Set();
|
|
1320
|
+
const symbolList = config
|
|
1321
|
+
.filter((item) => {
|
|
1322
|
+
if (uniqueSymbols.has(item.symbol)) {
|
|
1323
|
+
return false;
|
|
1324
|
+
}
|
|
1325
|
+
uniqueSymbols.add(item.symbol);
|
|
1326
|
+
return true;
|
|
1327
|
+
})
|
|
1328
|
+
.map(({ priority, displayName, symbol, logo, icon, ...other }, idx) => ({
|
|
1329
|
+
symbol,
|
|
1330
|
+
icon,
|
|
1331
|
+
logo: logo ?? icon,
|
|
1332
|
+
priority: priority ?? idx,
|
|
1333
|
+
displayName: displayName ?? symbol,
|
|
1334
|
+
index: idx,
|
|
1335
|
+
...other,
|
|
1336
|
+
}));
|
|
1337
|
+
symbolList.sort(({ priority: a_p, index: a_x }, { priority: b_p, index: b_x }) => b_p - a_p || a_x - b_x);
|
|
1338
|
+
return symbolList;
|
|
1339
|
+
};
|
|
1134
1340
|
class FrontendProviderService {
|
|
1135
1341
|
constructor() {
|
|
1136
1342
|
this.loggerService = inject(TYPES.loggerService);
|
|
1137
1343
|
this.resolveService = inject(TYPES.resolveService);
|
|
1344
|
+
this.configConnectionService = inject(TYPES.configConnectionService);
|
|
1138
1345
|
this.enable = singleshot(() => {
|
|
1139
1346
|
this.loggerService.log("frontendProviderService enable");
|
|
1140
1347
|
const { CC_WWWROOT_HOST, CC_WWWROOT_PORT } = getEnv();
|
|
1141
|
-
|
|
1348
|
+
let unServer;
|
|
1349
|
+
const init = async () => {
|
|
1350
|
+
{
|
|
1351
|
+
const config = await GET_SYMBOL_CONFIG_FN(this);
|
|
1352
|
+
if (config) {
|
|
1353
|
+
const symbolList = MAP_SYMBOL_CONFIG_FN(config);
|
|
1354
|
+
lib.symbolConnectionService.getSymbolList.setValue(Promise.resolve(symbolList));
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
unServer = serve(CC_WWWROOT_HOST, CC_WWWROOT_PORT, this.resolveService.PROJECT_ROOT_DIR);
|
|
1358
|
+
};
|
|
1359
|
+
init();
|
|
1142
1360
|
return () => {
|
|
1143
|
-
unServer();
|
|
1361
|
+
unServer && unServer();
|
|
1144
1362
|
this.enable.clear();
|
|
1145
1363
|
};
|
|
1146
1364
|
});
|
|
@@ -1811,6 +2029,16 @@ class TelegramLogicService {
|
|
|
1811
2029
|
markdown,
|
|
1812
2030
|
});
|
|
1813
2031
|
});
|
|
2032
|
+
this.notifySignalInfo = trycatch(async (event) => {
|
|
2033
|
+
this.loggerService.log("telegramLogicService notifySignalInfo", {
|
|
2034
|
+
event,
|
|
2035
|
+
});
|
|
2036
|
+
const markdown = await this.telegramTemplateService.getSignalInfoMarkdown(event);
|
|
2037
|
+
await this.telegramWebService.publishNotify({
|
|
2038
|
+
symbol: event.symbol,
|
|
2039
|
+
markdown,
|
|
2040
|
+
});
|
|
2041
|
+
});
|
|
1814
2042
|
this.notifyCancelScheduled = async (event) => {
|
|
1815
2043
|
this.loggerService.log("telegramLogicService notifyCancelScheduled", {
|
|
1816
2044
|
event,
|
|
@@ -1898,8 +2126,11 @@ class TelegramLogicService {
|
|
|
1898
2126
|
return;
|
|
1899
2127
|
}
|
|
1900
2128
|
});
|
|
2129
|
+
const unSignalNotify = listenSignalNotify(async (event) => {
|
|
2130
|
+
await this.notifySignalInfo(event);
|
|
2131
|
+
});
|
|
1901
2132
|
const unConnect = () => this.connect.clear();
|
|
1902
|
-
const unListen = compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unSync(), () => unConnect());
|
|
2133
|
+
const unListen = compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unSync(), () => unSignalNotify(), () => unConnect());
|
|
1903
2134
|
return () => {
|
|
1904
2135
|
STOP_BOT_FN();
|
|
1905
2136
|
unListen();
|
|
@@ -2018,6 +2249,12 @@ class TelegramTemplateService {
|
|
|
2018
2249
|
});
|
|
2019
2250
|
return await RENDER_TEMPLATE_FN("close-pending.mustache", event, this);
|
|
2020
2251
|
};
|
|
2252
|
+
this.getSignalInfoMarkdown = async (event) => {
|
|
2253
|
+
this.loggerService.log("telegramTemplateService getSignalInfoMarkdown", {
|
|
2254
|
+
event,
|
|
2255
|
+
});
|
|
2256
|
+
return await RENDER_TEMPLATE_FN("signal-info.mustache", event, this);
|
|
2257
|
+
};
|
|
2021
2258
|
}
|
|
2022
2259
|
}
|
|
2023
2260
|
|
|
@@ -2058,7 +2295,7 @@ class ModuleConnectionService {
|
|
|
2058
2295
|
this.resolveService = inject(TYPES.resolveService);
|
|
2059
2296
|
this.loaderService = inject(TYPES.loaderService);
|
|
2060
2297
|
this.loadModule = async (fileName) => {
|
|
2061
|
-
this.loggerService.log("moduleConnectionService
|
|
2298
|
+
this.loggerService.log("moduleConnectionService loadModule", {
|
|
2062
2299
|
fileName,
|
|
2063
2300
|
});
|
|
2064
2301
|
return await LOAD_MODULE_MODULE_FN(fileName, this);
|
|
@@ -2105,6 +2342,19 @@ class BabelService {
|
|
|
2105
2342
|
}
|
|
2106
2343
|
}
|
|
2107
2344
|
|
|
2345
|
+
/**
|
|
2346
|
+
* This file is used to define any aliases for imports in the client code. This is useful for mocking modules during testing or for providing alternative implementations of certain modules.
|
|
2347
|
+
* For example, if we want to mock the "pinets" module during testing, we can add an entry to the IMPORT_ALIAS object that points to our mock implementation. Then, when the client code tries to import "pinets", it will receive our mock implementation instead of the actual "pinets" module.
|
|
2348
|
+
* This allows us to isolate the client code from external dependencies and test it more effectively.
|
|
2349
|
+
* Note that the keys in the IMPORT_ALIAS object should match the module names used in the client code, and the values should be the corresponding mock implementations or alternative modules.
|
|
2350
|
+
* @example
|
|
2351
|
+
* // To mock the "pinets" module, we can add the following entry to the IMPORT_ALIAS object:
|
|
2352
|
+
* Object.assign(IMPORT_ALIAS, {
|
|
2353
|
+
* "pinets": require("pinets/dist/pinets.min.browser.js"),
|
|
2354
|
+
* });
|
|
2355
|
+
*/
|
|
2356
|
+
const IMPORT_ALIAS = {};
|
|
2357
|
+
|
|
2108
2358
|
const USE_ESMODULE_DEFAULT = false;
|
|
2109
2359
|
const IMPORT_PATHS_EXCLUDE = new Set(["dump", "logs", "modules", "node_modules"]);
|
|
2110
2360
|
const TRANSPILE_FN = memoize(([path]) => `${path}`, (path, code, self, require) => {
|
|
@@ -2220,6 +2470,8 @@ const CREATE_BASE_REQUIRE_FN = (self, seen) => {
|
|
|
2220
2470
|
return new Proxy(baseRequire, {
|
|
2221
2471
|
apply(_target, _this, args) {
|
|
2222
2472
|
const id = args[0];
|
|
2473
|
+
if (IMPORT_ALIAS[id])
|
|
2474
|
+
return IMPORT_ALIAS[id];
|
|
2223
2475
|
if (id === "backtest-kit")
|
|
2224
2476
|
return globalThis.BacktestKit;
|
|
2225
2477
|
if (id === "@backtest-kit/cli")
|
|
@@ -2323,6 +2575,26 @@ globalThis.BacktestKitOllama = BacktestKitOllama;
|
|
|
2323
2575
|
globalThis.BacktestKitPinets = BacktestKitPinets;
|
|
2324
2576
|
globalThis.BacktestKitSignals = BacktestKitSignals;
|
|
2325
2577
|
|
|
2578
|
+
const GET_ALIAS_EXPORTS_FN = (self) => {
|
|
2579
|
+
const instance = self.getInstance(self.resolveService.OVERRIDE_CONFIG_DIR);
|
|
2580
|
+
if (!instance.check("alias.module")) {
|
|
2581
|
+
return null;
|
|
2582
|
+
}
|
|
2583
|
+
const exports = instance.import("alias.module");
|
|
2584
|
+
return "default" in exports
|
|
2585
|
+
? exports.default
|
|
2586
|
+
: exports;
|
|
2587
|
+
};
|
|
2588
|
+
const INIT_ALIAS_FN = (self) => {
|
|
2589
|
+
const alias = GET_ALIAS_EXPORTS_FN(self);
|
|
2590
|
+
if (!alias) {
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
if (!isObject(alias)) {
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
Object.assign(IMPORT_ALIAS, alias);
|
|
2597
|
+
};
|
|
2326
2598
|
class LoaderService {
|
|
2327
2599
|
constructor() {
|
|
2328
2600
|
this.babelService = inject(TYPES.babelService);
|
|
@@ -2350,6 +2622,90 @@ class LoaderService {
|
|
|
2350
2622
|
const instance = this.getInstance(basePath);
|
|
2351
2623
|
return instance.check(filePath);
|
|
2352
2624
|
};
|
|
2625
|
+
this.init = singleshot(() => {
|
|
2626
|
+
this.loggerService.log("loaderService init");
|
|
2627
|
+
INIT_ALIAS_FN(this);
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
const GET_CONFIG_VARIANTS_FN = (fileName, self) => {
|
|
2633
|
+
const result = [];
|
|
2634
|
+
result.push({
|
|
2635
|
+
filePath: path.join(process.cwd(), "config", fileName),
|
|
2636
|
+
baseDir: path.join(process.cwd(), "config")
|
|
2637
|
+
});
|
|
2638
|
+
result.push({
|
|
2639
|
+
filePath: path.join(self.resolveService.OVERRIDE_CONFIG_DIR, fileName),
|
|
2640
|
+
baseDir: self.resolveService.OVERRIDE_CONFIG_DIR,
|
|
2641
|
+
});
|
|
2642
|
+
result.push({
|
|
2643
|
+
filePath: path.join(self.resolveService.DEFAULT_CONFIG_DIR, fileName),
|
|
2644
|
+
baseDir: self.resolveService.DEFAULT_CONFIG_DIR,
|
|
2645
|
+
});
|
|
2646
|
+
return result;
|
|
2647
|
+
};
|
|
2648
|
+
const LOAD_CONFIG_CONFIG_FN = async (fileName, self) => {
|
|
2649
|
+
for (const { filePath, baseDir } of GET_CONFIG_VARIANTS_FN(fileName, self)) {
|
|
2650
|
+
try {
|
|
2651
|
+
if (await self.loaderService.check(filePath, baseDir)) {
|
|
2652
|
+
return self.loaderService.import(filePath, baseDir);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
catch {
|
|
2656
|
+
console.warn(`Module module import failed filePath=${filePath} baseDir=${baseDir}`);
|
|
2657
|
+
process.exit(-1);
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
return null;
|
|
2661
|
+
};
|
|
2662
|
+
class ConfigConnectionService {
|
|
2663
|
+
constructor() {
|
|
2664
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
2665
|
+
this.resolveService = inject(TYPES.resolveService);
|
|
2666
|
+
this.loaderService = inject(TYPES.loaderService);
|
|
2667
|
+
this.loadConfig = (fileName) => {
|
|
2668
|
+
this.loggerService.log("configConnectionService loadConfig", {
|
|
2669
|
+
fileName,
|
|
2670
|
+
});
|
|
2671
|
+
return LOAD_CONFIG_CONFIG_FN(fileName, this);
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
const GET_NOTIFICATION_EXPORTS_FN = async (self) => {
|
|
2677
|
+
const exports = await self.configConnectionService.loadConfig("notification.config");
|
|
2678
|
+
if (!exports) {
|
|
2679
|
+
return null;
|
|
2680
|
+
}
|
|
2681
|
+
return "default" in exports
|
|
2682
|
+
? exports.default
|
|
2683
|
+
: exports;
|
|
2684
|
+
};
|
|
2685
|
+
const GET_NOTIFICATION_CONFIG_FN = async (self) => {
|
|
2686
|
+
const config = await GET_NOTIFICATION_EXPORTS_FN(self);
|
|
2687
|
+
if (!config) {
|
|
2688
|
+
throw new Error("ConfigService getNotificationConfig `notification.config` is not found");
|
|
2689
|
+
}
|
|
2690
|
+
if ("notification_config" in config) {
|
|
2691
|
+
return config.notification_config;
|
|
2692
|
+
}
|
|
2693
|
+
return config;
|
|
2694
|
+
};
|
|
2695
|
+
class ConfigService {
|
|
2696
|
+
constructor() {
|
|
2697
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
2698
|
+
this.configConnectionService = inject(TYPES.configConnectionService);
|
|
2699
|
+
this.getNotificationConfig = singleshot(() => {
|
|
2700
|
+
throw new Error("ConfigService getNotificationConfig waitForInit is not called");
|
|
2701
|
+
});
|
|
2702
|
+
this.waitForInit = singleshot(async () => {
|
|
2703
|
+
this.loggerService.log("configService waitForInit");
|
|
2704
|
+
{
|
|
2705
|
+
const config = await GET_NOTIFICATION_CONFIG_FN(this);
|
|
2706
|
+
this.getNotificationConfig.setValue(config);
|
|
2707
|
+
}
|
|
2708
|
+
});
|
|
2353
2709
|
}
|
|
2354
2710
|
}
|
|
2355
2711
|
|
|
@@ -2360,12 +2716,16 @@ class LoaderService {
|
|
|
2360
2716
|
{
|
|
2361
2717
|
provide(TYPES.errorService, () => new ErrorService());
|
|
2362
2718
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
2719
|
+
}
|
|
2720
|
+
{
|
|
2363
2721
|
provide(TYPES.resolveService, () => new ResolveService());
|
|
2364
2722
|
provide(TYPES.loaderService, () => new LoaderService());
|
|
2723
|
+
provide(TYPES.configService, () => new ConfigService());
|
|
2365
2724
|
provide(TYPES.babelService, () => new BabelService());
|
|
2366
2725
|
}
|
|
2367
2726
|
{
|
|
2368
2727
|
provide(TYPES.moduleConnectionService, () => new ModuleConnectionService());
|
|
2728
|
+
provide(TYPES.configConnectionService, () => new ConfigConnectionService());
|
|
2369
2729
|
}
|
|
2370
2730
|
{
|
|
2371
2731
|
provide(TYPES.backtestMainService, () => new BacktestMainService());
|
|
@@ -2400,12 +2760,16 @@ const apiServices = {
|
|
|
2400
2760
|
const baseServices = {
|
|
2401
2761
|
errorService: inject(TYPES.errorService),
|
|
2402
2762
|
loggerService: inject(TYPES.loggerService),
|
|
2763
|
+
};
|
|
2764
|
+
const coreServices = {
|
|
2403
2765
|
resolveService: inject(TYPES.resolveService),
|
|
2404
2766
|
loaderService: inject(TYPES.loaderService),
|
|
2767
|
+
configService: inject(TYPES.configService),
|
|
2405
2768
|
babelService: inject(TYPES.babelService),
|
|
2406
2769
|
};
|
|
2407
2770
|
const connectionServices = {
|
|
2408
2771
|
moduleConnectionService: inject(TYPES.moduleConnectionService),
|
|
2772
|
+
configConnectionService: inject(TYPES.configConnectionService),
|
|
2409
2773
|
};
|
|
2410
2774
|
const mainServices = {
|
|
2411
2775
|
backtestMainService: inject(TYPES.backtestMainService),
|
|
@@ -2435,6 +2799,7 @@ const templateServices = {
|
|
|
2435
2799
|
const cli = {
|
|
2436
2800
|
...apiServices,
|
|
2437
2801
|
...baseServices,
|
|
2802
|
+
...coreServices,
|
|
2438
2803
|
...connectionServices,
|
|
2439
2804
|
...mainServices,
|
|
2440
2805
|
...logicServices,
|
|
@@ -2445,148 +2810,6 @@ const cli = {
|
|
|
2445
2810
|
};
|
|
2446
2811
|
init();
|
|
2447
2812
|
|
|
2448
|
-
const NOTIFICATION_CONFIG = {
|
|
2449
|
-
signal: true,
|
|
2450
|
-
risk: true,
|
|
2451
|
-
info: true,
|
|
2452
|
-
breakeven: true,
|
|
2453
|
-
common_error: true,
|
|
2454
|
-
critical_error: true,
|
|
2455
|
-
validation_error: true,
|
|
2456
|
-
partial_loss: false,
|
|
2457
|
-
partial_profit: false,
|
|
2458
|
-
signal_sync: false,
|
|
2459
|
-
strategy_commit: true,
|
|
2460
|
-
};
|
|
2461
|
-
class SetupUtils {
|
|
2462
|
-
constructor() {
|
|
2463
|
-
this.enable = singleshot(() => {
|
|
2464
|
-
cli.loggerService.debug("SetupUtils enable");
|
|
2465
|
-
Notification.enable(NOTIFICATION_CONFIG);
|
|
2466
|
-
{
|
|
2467
|
-
Recent.enable();
|
|
2468
|
-
Storage.enable();
|
|
2469
|
-
}
|
|
2470
|
-
{
|
|
2471
|
-
Markdown.enable();
|
|
2472
|
-
Report.enable();
|
|
2473
|
-
Dump.enable();
|
|
2474
|
-
Memory.enable();
|
|
2475
|
-
}
|
|
2476
|
-
{
|
|
2477
|
-
Dump.useMarkdown();
|
|
2478
|
-
Memory.usePersist();
|
|
2479
|
-
}
|
|
2480
|
-
{
|
|
2481
|
-
StorageLive.usePersist();
|
|
2482
|
-
StorageBacktest.useMemory();
|
|
2483
|
-
}
|
|
2484
|
-
{
|
|
2485
|
-
RecentLive.usePersist();
|
|
2486
|
-
RecentBacktest.useMemory();
|
|
2487
|
-
}
|
|
2488
|
-
{
|
|
2489
|
-
NotificationLive.usePersist();
|
|
2490
|
-
NotificationBacktest.useMemory();
|
|
2491
|
-
}
|
|
2492
|
-
{
|
|
2493
|
-
Markdown.useDummy();
|
|
2494
|
-
Log.useJsonl();
|
|
2495
|
-
}
|
|
2496
|
-
});
|
|
2497
|
-
this.clear = () => {
|
|
2498
|
-
cli.loggerService.debug("SetupUtils clear");
|
|
2499
|
-
if (!this.enable.hasValue()) {
|
|
2500
|
-
return;
|
|
2501
|
-
}
|
|
2502
|
-
this.enable.clear();
|
|
2503
|
-
{
|
|
2504
|
-
Recent.disable();
|
|
2505
|
-
Storage.disable();
|
|
2506
|
-
Notification.disable();
|
|
2507
|
-
}
|
|
2508
|
-
{
|
|
2509
|
-
Markdown.disable();
|
|
2510
|
-
Report.disable();
|
|
2511
|
-
Dump.disable();
|
|
2512
|
-
Memory.disable();
|
|
2513
|
-
}
|
|
2514
|
-
{
|
|
2515
|
-
Markdown.clear();
|
|
2516
|
-
Report.clear();
|
|
2517
|
-
MarkdownWriter.clear();
|
|
2518
|
-
ReportWriter.clear();
|
|
2519
|
-
}
|
|
2520
|
-
{
|
|
2521
|
-
PersistSignalAdapter.clear();
|
|
2522
|
-
PersistRiskAdapter.clear();
|
|
2523
|
-
PersistScheduleAdapter.clear();
|
|
2524
|
-
PersistPartialAdapter.clear();
|
|
2525
|
-
PersistBreakevenAdapter.clear();
|
|
2526
|
-
PersistCandleAdapter.clear();
|
|
2527
|
-
PersistStorageAdapter.clear();
|
|
2528
|
-
PersistNotificationAdapter.clear();
|
|
2529
|
-
PersistLogAdapter.clear();
|
|
2530
|
-
PersistMeasureAdapter.clear();
|
|
2531
|
-
PersistIntervalAdapter.clear();
|
|
2532
|
-
PersistMemoryAdapter.clear();
|
|
2533
|
-
PersistRecentAdapter.clear();
|
|
2534
|
-
}
|
|
2535
|
-
{
|
|
2536
|
-
Dump.clear();
|
|
2537
|
-
Log.clear();
|
|
2538
|
-
Markdown.clear();
|
|
2539
|
-
}
|
|
2540
|
-
{
|
|
2541
|
-
StorageLive.clear();
|
|
2542
|
-
StorageBacktest.clear();
|
|
2543
|
-
}
|
|
2544
|
-
{
|
|
2545
|
-
NotificationLive.clear();
|
|
2546
|
-
NotificationBacktest.clear();
|
|
2547
|
-
}
|
|
2548
|
-
{
|
|
2549
|
-
RecentLive.clear();
|
|
2550
|
-
RecentBacktest.clear();
|
|
2551
|
-
}
|
|
2552
|
-
};
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
const Setup = new SetupUtils();
|
|
2556
|
-
|
|
2557
|
-
Setup.enable();
|
|
2558
|
-
setConfig({
|
|
2559
|
-
CC_MAX_NOTIFICATIONS: 5000,
|
|
2560
|
-
CC_MAX_SIGNALS: 750,
|
|
2561
|
-
});
|
|
2562
|
-
setConfig({
|
|
2563
|
-
CC_ENABLE_DCA_EVERYWHERE: true,
|
|
2564
|
-
CC_ENABLE_PPPL_EVERYWHERE: true,
|
|
2565
|
-
CC_ENABLE_TRAILING_EVERYWHERE: true,
|
|
2566
|
-
});
|
|
2567
|
-
setConfig({
|
|
2568
|
-
CC_MAX_SIGNAL_GENERATION_SECONDS: 15 * 60,
|
|
2569
|
-
});
|
|
2570
|
-
setConfig({
|
|
2571
|
-
CC_MAX_BACKTEST_MARKDOWN_ROWS: 1000,
|
|
2572
|
-
CC_MAX_BREAKEVEN_MARKDOWN_ROWS: 1000,
|
|
2573
|
-
CC_MAX_HEATMAP_MARKDOWN_ROWS: 1000,
|
|
2574
|
-
CC_MAX_HIGHEST_PROFIT_MARKDOWN_ROWS: 1000,
|
|
2575
|
-
CC_MAX_LIVE_MARKDOWN_ROWS: 1000,
|
|
2576
|
-
CC_MAX_PARTIAL_MARKDOWN_ROWS: 1000,
|
|
2577
|
-
CC_MAX_RISK_MARKDOWN_ROWS: 1000,
|
|
2578
|
-
CC_MAX_SCHEDULE_MARKDOWN_ROWS: 1000,
|
|
2579
|
-
CC_MAX_STRATEGY_MARKDOWN_ROWS: 1000,
|
|
2580
|
-
CC_MAX_SYNC_MARKDOWN_ROWS: 1000,
|
|
2581
|
-
CC_MAX_PERFORMANCE_MARKDOWN_ROWS: 1000,
|
|
2582
|
-
});
|
|
2583
|
-
setConfig({
|
|
2584
|
-
CC_MAX_SIGNAL_LIFETIME_MINUTES: Infinity,
|
|
2585
|
-
});
|
|
2586
|
-
setConfig({
|
|
2587
|
-
CC_WALKER_MARKDOWN_TOP_N: 10,
|
|
2588
|
-
});
|
|
2589
|
-
|
|
2590
2813
|
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "flush", "init", "help", "version"];
|
|
2591
2814
|
const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
2592
2815
|
const HELP_TEXT$1 = `
|
|
@@ -2602,7 +2825,7 @@ const main$d = async () => {
|
|
|
2602
2825
|
if (MODES.some((mode) => values[mode])) {
|
|
2603
2826
|
return;
|
|
2604
2827
|
}
|
|
2605
|
-
process.stdout.write(`@backtest-kit/cli ${"7.
|
|
2828
|
+
process.stdout.write(`@backtest-kit/cli ${"7.3.0"}\n`);
|
|
2606
2829
|
process.stdout.write("\n");
|
|
2607
2830
|
process.stdout.write(`Run with --help to see available commands.\n`);
|
|
2608
2831
|
process.stdout.write("\n");
|
|
@@ -2933,6 +3156,10 @@ const main$4 = async () => {
|
|
|
2933
3156
|
console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
|
|
2934
3157
|
process.exit(1);
|
|
2935
3158
|
}
|
|
3159
|
+
{
|
|
3160
|
+
await cli.configService.waitForInit();
|
|
3161
|
+
Setup.enable();
|
|
3162
|
+
}
|
|
2936
3163
|
await cli.moduleConnectionService.loadModule("./editor.module");
|
|
2937
3164
|
{
|
|
2938
3165
|
await cli.exchangeSchemaService.addSchema();
|
|
@@ -3262,7 +3489,7 @@ const main$1 = async () => {
|
|
|
3262
3489
|
if (!values.help) {
|
|
3263
3490
|
return;
|
|
3264
3491
|
}
|
|
3265
|
-
process.stdout.write(`@backtest-kit/cli ${"7.
|
|
3492
|
+
process.stdout.write(`@backtest-kit/cli ${"7.3.0"}\n\n`);
|
|
3266
3493
|
process.stdout.write(HELP_TEXT);
|
|
3267
3494
|
process.exit(0);
|
|
3268
3495
|
};
|
|
@@ -3276,7 +3503,7 @@ const main = async () => {
|
|
|
3276
3503
|
if (!values.version) {
|
|
3277
3504
|
return;
|
|
3278
3505
|
}
|
|
3279
|
-
process.stdout.write(`@backtest-kit/cli ${"7.
|
|
3506
|
+
process.stdout.write(`@backtest-kit/cli ${"7.3.0"}\n`);
|
|
3280
3507
|
process.exit(0);
|
|
3281
3508
|
};
|
|
3282
3509
|
main();
|