@backtest-kit/ui 3.1.1 → 3.2.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/build/index.cjs CHANGED
@@ -20,10 +20,10 @@ const CC_WWWROOT_HOST = process.env.CC_WWWROOT_HOST || "0.0.0.0";
20
20
  const CC_WWWROOT_PORT = parseInt(process.env.CC_WWWROOT_PORT) || 60050;
21
21
  const CC_ENABLE_MOCK = !!parseInt(process.env.CC_ENABLE_MOCK) || false;
22
22
 
23
- const router$6 = Router({
23
+ const router$7 = Router({
24
24
  params: true,
25
25
  });
26
- router$6.get("/api/v1/health/health_check", async (req, res) => {
26
+ router$7.get("/api/v1/health/health_check", async (req, res) => {
27
27
  const [cpuLoad] = os.loadavg();
28
28
  return await micro.send(res, 200, {
29
29
  uptime: process.uptime(),
@@ -58,6 +58,7 @@ const baseServices$1 = {
58
58
  };
59
59
  const connectionServices$1 = {
60
60
  symbolConnectionService: Symbol("symbolConnectionService"),
61
+ priceConnectionService: Symbol("priceConnectionService"),
61
62
  };
62
63
  const metaServices$1 = {
63
64
  symbolMetaService: Symbol("symbolMetaService"),
@@ -597,12 +598,56 @@ class SymbolMetaService {
597
598
  }
598
599
  }
599
600
 
601
+ const PRICE_TIMEOUT = 120000;
602
+ const CREATE_KEY_FN = (symbol, strategyName, exchangeName, frameName, backtest) => {
603
+ const parts = [symbol, strategyName, exchangeName];
604
+ if (frameName)
605
+ parts.push(frameName);
606
+ parts.push(backtest ? "backtest" : "live");
607
+ return parts.join(":");
608
+ };
609
+ const GET_SUBJECT_FN = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
610
+ const GET_PRICE_FN = async (symbol, strategyName, exchangeName, frameName, backtest) => {
611
+ const priceSubject = GET_SUBJECT_FN(symbol, strategyName, exchangeName, frameName, backtest);
612
+ if (priceSubject.data) {
613
+ return priceSubject.data;
614
+ }
615
+ return await functoolsKit.waitForNext(priceSubject, (data) => !!data, PRICE_TIMEOUT);
616
+ };
617
+ class PriceConnectionService {
618
+ constructor() {
619
+ this.loggerService = inject(TYPES.loggerService);
620
+ this.getSignalPendingPrice = async (symbol, strategyName, exchangeName, frameName, backtest) => {
621
+ this.loggerService.log("priceConnectionService getSignalPendingPrice", {
622
+ symbol,
623
+ strategyName,
624
+ exchangeName,
625
+ frameName,
626
+ backtest,
627
+ });
628
+ const currentPrice = await GET_PRICE_FN(symbol, strategyName, exchangeName, frameName, backtest);
629
+ if (typeof currentPrice === "symbol") {
630
+ throw new Error(`Price for ${CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest)} not received within timeout`);
631
+ }
632
+ return currentPrice;
633
+ };
634
+ this.init = functoolsKit.singleshot(async () => {
635
+ this.loggerService.log("priceConnectionService init");
636
+ backtestKit.listenSignal((event) => {
637
+ const priceSubject = GET_SUBJECT_FN(event.symbol, event.strategyName, event.exchangeName, event.frameName, event.backtest);
638
+ event.currentPrice && priceSubject.next(event.currentPrice);
639
+ });
640
+ });
641
+ }
642
+ }
643
+
600
644
  {
601
645
  provide(TYPES.loggerService, () => new LoggerService());
602
646
  provide(TYPES.exchangeService, () => new ExchangeService());
603
647
  }
604
648
  {
605
649
  provide(TYPES.symbolConnectionService, () => new SymbolConnectionService());
650
+ provide(TYPES.priceConnectionService, () => new PriceConnectionService());
606
651
  }
607
652
  {
608
653
  provide(TYPES.symbolMetaService, () => new SymbolMetaService());
@@ -624,6 +669,7 @@ const baseServices = {
624
669
  };
625
670
  const connectionServices = {
626
671
  symbolConnectionService: inject(TYPES.symbolConnectionService),
672
+ priceConnectionService: inject(TYPES.priceConnectionService),
627
673
  };
628
674
  const metaServices = {
629
675
  symbolMetaService: inject(TYPES.symbolMetaService),
@@ -647,11 +693,11 @@ const ioc = {
647
693
  };
648
694
  init();
649
695
 
650
- const router$5 = Router({
696
+ const router$6 = Router({
651
697
  params: true,
652
698
  });
653
699
  // ExchangeMockService endpoints
654
- router$5.post("/api/v1/mock/candles_signal", async (req, res) => {
700
+ router$6.post("/api/v1/mock/candles_signal", async (req, res) => {
655
701
  try {
656
702
  const request = await micro.json(req);
657
703
  const { signalId, interval, requestId, serviceName } = request;
@@ -679,7 +725,7 @@ router$5.post("/api/v1/mock/candles_signal", async (req, res) => {
679
725
  });
680
726
  }
681
727
  });
682
- router$5.post("/api/v1/mock/candles_point", async (req, res) => {
728
+ router$6.post("/api/v1/mock/candles_point", async (req, res) => {
683
729
  try {
684
730
  const request = await micro.json(req);
685
731
  const { currentTime, interval, requestId, serviceName, symbol, exchangeName } = request;
@@ -713,7 +759,7 @@ router$5.post("/api/v1/mock/candles_point", async (req, res) => {
713
759
  }
714
760
  });
715
761
  // NotificationMockService endpoints
716
- router$5.post("/api/v1/mock/notification_list", async (req, res) => {
762
+ router$6.post("/api/v1/mock/notification_list", async (req, res) => {
717
763
  try {
718
764
  const request = await micro.json(req);
719
765
  const { requestId, serviceName } = request;
@@ -741,7 +787,7 @@ router$5.post("/api/v1/mock/notification_list", async (req, res) => {
741
787
  });
742
788
  }
743
789
  });
744
- router$5.post("/api/v1/mock/notification_one/:id", async (req, res) => {
790
+ router$6.post("/api/v1/mock/notification_one/:id", async (req, res) => {
745
791
  try {
746
792
  const request = await micro.json(req);
747
793
  const { requestId, serviceName } = request;
@@ -770,7 +816,7 @@ router$5.post("/api/v1/mock/notification_one/:id", async (req, res) => {
770
816
  });
771
817
  }
772
818
  });
773
- router$5.post("/api/v1/mock/notification_filter", async (req, res) => {
819
+ router$6.post("/api/v1/mock/notification_filter", async (req, res) => {
774
820
  try {
775
821
  const request = await micro.json(req);
776
822
  const { requestId, serviceName, filterData, limit, offset } = request;
@@ -799,7 +845,7 @@ router$5.post("/api/v1/mock/notification_filter", async (req, res) => {
799
845
  }
800
846
  });
801
847
  // StorageMockService endpoints
802
- router$5.post("/api/v1/mock/storage_one/:id", async (req, res) => {
848
+ router$6.post("/api/v1/mock/storage_one/:id", async (req, res) => {
803
849
  try {
804
850
  const request = await micro.json(req);
805
851
  const { requestId, serviceName } = request;
@@ -828,7 +874,7 @@ router$5.post("/api/v1/mock/storage_one/:id", async (req, res) => {
828
874
  });
829
875
  }
830
876
  });
831
- router$5.post("/api/v1/mock/storage_list/live", async (req, res) => {
877
+ router$6.post("/api/v1/mock/storage_list/live", async (req, res) => {
832
878
  try {
833
879
  const request = await micro.json(req);
834
880
  const { requestId, serviceName } = request;
@@ -856,7 +902,7 @@ router$5.post("/api/v1/mock/storage_list/live", async (req, res) => {
856
902
  });
857
903
  }
858
904
  });
859
- router$5.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
905
+ router$6.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
860
906
  try {
861
907
  const request = await micro.json(req);
862
908
  const { requestId, serviceName } = request;
@@ -885,11 +931,11 @@ router$5.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
885
931
  }
886
932
  });
887
933
 
888
- const router$4 = Router({
934
+ const router$5 = Router({
889
935
  params: true,
890
936
  });
891
937
  // ExchangeViewService endpoints
892
- router$4.post("/api/v1/view/candles_signal", async (req, res) => {
938
+ router$5.post("/api/v1/view/candles_signal", async (req, res) => {
893
939
  try {
894
940
  const request = await micro.json(req);
895
941
  const { signalId, interval, requestId, serviceName } = request;
@@ -917,7 +963,7 @@ router$4.post("/api/v1/view/candles_signal", async (req, res) => {
917
963
  });
918
964
  }
919
965
  });
920
- router$4.post("/api/v1/view/candles_point", async (req, res) => {
966
+ router$5.post("/api/v1/view/candles_point", async (req, res) => {
921
967
  try {
922
968
  const request = await micro.json(req);
923
969
  const { currentTime, interval, requestId, serviceName, symbol, exchangeName } = request;
@@ -951,7 +997,7 @@ router$4.post("/api/v1/view/candles_point", async (req, res) => {
951
997
  }
952
998
  });
953
999
  // NotificationViewService endpoints
954
- router$4.post("/api/v1/view/notification_list", async (req, res) => {
1000
+ router$5.post("/api/v1/view/notification_list", async (req, res) => {
955
1001
  try {
956
1002
  const request = await micro.json(req);
957
1003
  const { requestId, serviceName } = request;
@@ -979,7 +1025,7 @@ router$4.post("/api/v1/view/notification_list", async (req, res) => {
979
1025
  });
980
1026
  }
981
1027
  });
982
- router$4.post("/api/v1/view/notification_one/:id", async (req, res) => {
1028
+ router$5.post("/api/v1/view/notification_one/:id", async (req, res) => {
983
1029
  try {
984
1030
  const request = await micro.json(req);
985
1031
  const { requestId, serviceName } = request;
@@ -1008,7 +1054,7 @@ router$4.post("/api/v1/view/notification_one/:id", async (req, res) => {
1008
1054
  });
1009
1055
  }
1010
1056
  });
1011
- router$4.post("/api/v1/view/notification_filter", async (req, res) => {
1057
+ router$5.post("/api/v1/view/notification_filter", async (req, res) => {
1012
1058
  try {
1013
1059
  const request = await micro.json(req);
1014
1060
  const { requestId, serviceName, filterData, limit, offset } = request;
@@ -1037,7 +1083,7 @@ router$4.post("/api/v1/view/notification_filter", async (req, res) => {
1037
1083
  }
1038
1084
  });
1039
1085
  // StorageViewService endpoints
1040
- router$4.post("/api/v1/view/storage_one/:id", async (req, res) => {
1086
+ router$5.post("/api/v1/view/storage_one/:id", async (req, res) => {
1041
1087
  try {
1042
1088
  const request = await micro.json(req);
1043
1089
  const { requestId, serviceName } = request;
@@ -1066,7 +1112,7 @@ router$4.post("/api/v1/view/storage_one/:id", async (req, res) => {
1066
1112
  });
1067
1113
  }
1068
1114
  });
1069
- router$4.post("/api/v1/view/storage_list/live", async (req, res) => {
1115
+ router$5.post("/api/v1/view/storage_list/live", async (req, res) => {
1070
1116
  try {
1071
1117
  const request = await micro.json(req);
1072
1118
  const { requestId, serviceName } = request;
@@ -1094,7 +1140,7 @@ router$4.post("/api/v1/view/storage_list/live", async (req, res) => {
1094
1140
  });
1095
1141
  }
1096
1142
  });
1097
- router$4.post("/api/v1/view/storage_list/backtest", async (req, res) => {
1143
+ router$5.post("/api/v1/view/storage_list/backtest", async (req, res) => {
1098
1144
  try {
1099
1145
  const request = await micro.json(req);
1100
1146
  const { requestId, serviceName } = request;
@@ -1130,7 +1176,7 @@ function getModulesPath() {
1130
1176
  return path.join(basePath, "../../../");
1131
1177
  }
1132
1178
 
1133
- const router$3 = Router({
1179
+ const router$4 = Router({
1134
1180
  params: true,
1135
1181
  });
1136
1182
  // getModulesPath
@@ -1147,7 +1193,7 @@ const ASSET_32 = CC_ENABLE_MOCK
1147
1193
  const cache128 = new Map();
1148
1194
  const cache32 = new Map();
1149
1195
  const cacheSvg = new Map();
1150
- router$3.get("/icon/128/:filename", async (req, res) => {
1196
+ router$4.get("/icon/128/:filename", async (req, res) => {
1151
1197
  const filename = req.params.filename;
1152
1198
  // Check cache first
1153
1199
  if (cache128.has(filename)) {
@@ -1163,7 +1209,7 @@ router$3.get("/icon/128/:filename", async (req, res) => {
1163
1209
  }
1164
1210
  return await micro.send(res, 404, "File not found (128)");
1165
1211
  });
1166
- router$3.get("/icon/32/:filename", async (req, res) => {
1212
+ router$4.get("/icon/32/:filename", async (req, res) => {
1167
1213
  const filename = req.params.filename;
1168
1214
  // Check cache first
1169
1215
  if (cache32.has(filename)) {
@@ -1179,7 +1225,7 @@ router$3.get("/icon/32/:filename", async (req, res) => {
1179
1225
  }
1180
1226
  return await micro.send(res, 404, "File not found (32)");
1181
1227
  });
1182
- router$3.get("/icon/svg/:filename", async (req, res) => {
1228
+ router$4.get("/icon/svg/:filename", async (req, res) => {
1183
1229
  const filename = req.params.filename;
1184
1230
  // Check cache first
1185
1231
  if (cacheSvg.has(filename)) {
@@ -1195,7 +1241,7 @@ router$3.get("/icon/svg/:filename", async (req, res) => {
1195
1241
  }
1196
1242
  return await micro.send(res, 404, "File not found (svg)");
1197
1243
  });
1198
- router$3.get("/icon/:filename", async (req, res) => {
1244
+ router$4.get("/icon/:filename", async (req, res) => {
1199
1245
  const filename = req.params.filename;
1200
1246
  // Check cache first
1201
1247
  if (cache32.has(filename)) {
@@ -1212,10 +1258,10 @@ router$3.get("/icon/:filename", async (req, res) => {
1212
1258
  return await micro.send(res, 404, "File not found (root)");
1213
1259
  });
1214
1260
 
1215
- const router$2 = Router({
1261
+ const router$3 = Router({
1216
1262
  params: true,
1217
1263
  });
1218
- router$2.post("/api/v1/dict/symbol/list", async (req, res) => {
1264
+ router$3.post("/api/v1/dict/symbol/list", async (req, res) => {
1219
1265
  try {
1220
1266
  const request = await micro.json(req);
1221
1267
  const { requestId, serviceName } = request;
@@ -1243,7 +1289,7 @@ router$2.post("/api/v1/dict/symbol/list", async (req, res) => {
1243
1289
  });
1244
1290
  }
1245
1291
  });
1246
- router$2.post("/api/v1/dict/symbol/map", async (req, res) => {
1292
+ router$3.post("/api/v1/dict/symbol/map", async (req, res) => {
1247
1293
  try {
1248
1294
  const request = await micro.json(req);
1249
1295
  const { requestId, serviceName } = request;
@@ -1271,7 +1317,7 @@ router$2.post("/api/v1/dict/symbol/map", async (req, res) => {
1271
1317
  });
1272
1318
  }
1273
1319
  });
1274
- router$2.post("/api/v1/dict/symbol/one", async (req, res) => {
1320
+ router$3.post("/api/v1/dict/symbol/one", async (req, res) => {
1275
1321
  try {
1276
1322
  const request = await micro.json(req);
1277
1323
  const { requestId, serviceName, id } = request;
@@ -1300,6 +1346,38 @@ router$2.post("/api/v1/dict/symbol/one", async (req, res) => {
1300
1346
  }
1301
1347
  });
1302
1348
 
1349
+ const router$2 = Router({
1350
+ params: true,
1351
+ });
1352
+ router$2.post("/api/v1/global/signal_pending_price", async (req, res) => {
1353
+ try {
1354
+ const request = await micro.json(req);
1355
+ const { symbol, strategyName, exchangeName, frameName, backtest, requestId, serviceName } = request;
1356
+ const data = await ioc.priceConnectionService.getSignalPendingPrice(symbol, strategyName, exchangeName, frameName, backtest);
1357
+ const result = {
1358
+ data,
1359
+ status: "ok",
1360
+ error: "",
1361
+ requestId,
1362
+ serviceName,
1363
+ };
1364
+ ioc.loggerService.log("/api/v1/global/signal_pending_price ok", {
1365
+ request,
1366
+ result: omit(result, "data"),
1367
+ });
1368
+ return await micro.send(res, 200, result);
1369
+ }
1370
+ catch (error) {
1371
+ ioc.loggerService.log("/api/v1/global/signal_pending_price error", {
1372
+ error: functoolsKit.errorData(error),
1373
+ });
1374
+ return await micro.send(res, 200, {
1375
+ status: "error",
1376
+ error: functoolsKit.getErrorMessage(error),
1377
+ });
1378
+ }
1379
+ });
1380
+
1303
1381
  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)));
1304
1382
  function getPublicPath() {
1305
1383
  const modulePath = require$1.resolve('@backtest-kit/ui');
@@ -1311,18 +1389,21 @@ const router = Router({
1311
1389
  params: true,
1312
1390
  });
1313
1391
  router.all("/api/v1/health/*", (req, res) => {
1314
- return router$6(req, res, finalhandler(req, res));
1392
+ return router$7(req, res, finalhandler(req, res));
1315
1393
  });
1316
1394
  router.all("/api/v1/mock/*", (req, res) => {
1317
- return router$5(req, res, finalhandler(req, res));
1395
+ return router$6(req, res, finalhandler(req, res));
1318
1396
  });
1319
1397
  router.all("/api/v1/view/*", (req, res) => {
1320
- return router$4(req, res, finalhandler(req, res));
1398
+ return router$5(req, res, finalhandler(req, res));
1321
1399
  });
1322
1400
  router.all("/icon/*", (req, res) => {
1323
- return router$3(req, res, finalhandler(req, res));
1401
+ return router$4(req, res, finalhandler(req, res));
1324
1402
  });
1325
1403
  router.all("/api/v1/dict/*", (req, res) => {
1404
+ return router$3(req, res, finalhandler(req, res));
1405
+ });
1406
+ router.all("/api/v1/global/*", (req, res) => {
1326
1407
  return router$2(req, res, finalhandler(req, res));
1327
1408
  });
1328
1409
  router.get("/*", (req, res) => serveHandler(req, res, {