@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.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import http from 'http';
2
- import { isObject, singleshot, pickDocuments, str, memoize, errorData, getErrorMessage } from 'functools-kit';
2
+ import { isObject, singleshot, pickDocuments, str, memoize, BehaviorSubject, waitForNext, errorData, getErrorMessage } from 'functools-kit';
3
3
  import micro from 'micro';
4
4
  import Router from 'router';
5
5
  import finalhandler from 'finalhandler';
6
6
  import serveHandler from 'serve-handler';
7
7
  import os from 'os';
8
8
  import { createActivator } from 'di-kit';
9
- import { Exchange, Notification, Storage } from 'backtest-kit';
9
+ import { Exchange, Notification, Storage, listenSignal } from 'backtest-kit';
10
10
  import fs, { readdir, readFile } from 'fs/promises';
11
11
  import path, { join, dirname } from 'path';
12
12
  import { createRequire } from 'module';
@@ -17,10 +17,10 @@ const CC_WWWROOT_HOST = process.env.CC_WWWROOT_HOST || "0.0.0.0";
17
17
  const CC_WWWROOT_PORT = parseInt(process.env.CC_WWWROOT_PORT) || 60050;
18
18
  const CC_ENABLE_MOCK = !!parseInt(process.env.CC_ENABLE_MOCK) || false;
19
19
 
20
- const router$6 = Router({
20
+ const router$7 = Router({
21
21
  params: true,
22
22
  });
23
- router$6.get("/api/v1/health/health_check", async (req, res) => {
23
+ router$7.get("/api/v1/health/health_check", async (req, res) => {
24
24
  const [cpuLoad] = os.loadavg();
25
25
  return await micro.send(res, 200, {
26
26
  uptime: process.uptime(),
@@ -55,6 +55,7 @@ const baseServices$1 = {
55
55
  };
56
56
  const connectionServices$1 = {
57
57
  symbolConnectionService: Symbol("symbolConnectionService"),
58
+ priceConnectionService: Symbol("priceConnectionService"),
58
59
  };
59
60
  const metaServices$1 = {
60
61
  symbolMetaService: Symbol("symbolMetaService"),
@@ -594,12 +595,56 @@ class SymbolMetaService {
594
595
  }
595
596
  }
596
597
 
598
+ const PRICE_TIMEOUT = 120000;
599
+ const CREATE_KEY_FN = (symbol, strategyName, exchangeName, frameName, backtest) => {
600
+ const parts = [symbol, strategyName, exchangeName];
601
+ if (frameName)
602
+ parts.push(frameName);
603
+ parts.push(backtest ? "backtest" : "live");
604
+ return parts.join(":");
605
+ };
606
+ const GET_SUBJECT_FN = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
607
+ const GET_PRICE_FN = async (symbol, strategyName, exchangeName, frameName, backtest) => {
608
+ const priceSubject = GET_SUBJECT_FN(symbol, strategyName, exchangeName, frameName, backtest);
609
+ if (priceSubject.data) {
610
+ return priceSubject.data;
611
+ }
612
+ return await waitForNext(priceSubject, (data) => !!data, PRICE_TIMEOUT);
613
+ };
614
+ class PriceConnectionService {
615
+ constructor() {
616
+ this.loggerService = inject(TYPES.loggerService);
617
+ this.getSignalPendingPrice = async (symbol, strategyName, exchangeName, frameName, backtest) => {
618
+ this.loggerService.log("priceConnectionService getSignalPendingPrice", {
619
+ symbol,
620
+ strategyName,
621
+ exchangeName,
622
+ frameName,
623
+ backtest,
624
+ });
625
+ const currentPrice = await GET_PRICE_FN(symbol, strategyName, exchangeName, frameName, backtest);
626
+ if (typeof currentPrice === "symbol") {
627
+ throw new Error(`Price for ${CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest)} not received within timeout`);
628
+ }
629
+ return currentPrice;
630
+ };
631
+ this.init = singleshot(async () => {
632
+ this.loggerService.log("priceConnectionService init");
633
+ listenSignal((event) => {
634
+ const priceSubject = GET_SUBJECT_FN(event.symbol, event.strategyName, event.exchangeName, event.frameName, event.backtest);
635
+ event.currentPrice && priceSubject.next(event.currentPrice);
636
+ });
637
+ });
638
+ }
639
+ }
640
+
597
641
  {
598
642
  provide(TYPES.loggerService, () => new LoggerService());
599
643
  provide(TYPES.exchangeService, () => new ExchangeService());
600
644
  }
601
645
  {
602
646
  provide(TYPES.symbolConnectionService, () => new SymbolConnectionService());
647
+ provide(TYPES.priceConnectionService, () => new PriceConnectionService());
603
648
  }
604
649
  {
605
650
  provide(TYPES.symbolMetaService, () => new SymbolMetaService());
@@ -621,6 +666,7 @@ const baseServices = {
621
666
  };
622
667
  const connectionServices = {
623
668
  symbolConnectionService: inject(TYPES.symbolConnectionService),
669
+ priceConnectionService: inject(TYPES.priceConnectionService),
624
670
  };
625
671
  const metaServices = {
626
672
  symbolMetaService: inject(TYPES.symbolMetaService),
@@ -644,11 +690,11 @@ const ioc = {
644
690
  };
645
691
  init();
646
692
 
647
- const router$5 = Router({
693
+ const router$6 = Router({
648
694
  params: true,
649
695
  });
650
696
  // ExchangeMockService endpoints
651
- router$5.post("/api/v1/mock/candles_signal", async (req, res) => {
697
+ router$6.post("/api/v1/mock/candles_signal", async (req, res) => {
652
698
  try {
653
699
  const request = await micro.json(req);
654
700
  const { signalId, interval, requestId, serviceName } = request;
@@ -676,7 +722,7 @@ router$5.post("/api/v1/mock/candles_signal", async (req, res) => {
676
722
  });
677
723
  }
678
724
  });
679
- router$5.post("/api/v1/mock/candles_point", async (req, res) => {
725
+ router$6.post("/api/v1/mock/candles_point", async (req, res) => {
680
726
  try {
681
727
  const request = await micro.json(req);
682
728
  const { currentTime, interval, requestId, serviceName, symbol, exchangeName } = request;
@@ -710,7 +756,7 @@ router$5.post("/api/v1/mock/candles_point", async (req, res) => {
710
756
  }
711
757
  });
712
758
  // NotificationMockService endpoints
713
- router$5.post("/api/v1/mock/notification_list", async (req, res) => {
759
+ router$6.post("/api/v1/mock/notification_list", async (req, res) => {
714
760
  try {
715
761
  const request = await micro.json(req);
716
762
  const { requestId, serviceName } = request;
@@ -738,7 +784,7 @@ router$5.post("/api/v1/mock/notification_list", async (req, res) => {
738
784
  });
739
785
  }
740
786
  });
741
- router$5.post("/api/v1/mock/notification_one/:id", async (req, res) => {
787
+ router$6.post("/api/v1/mock/notification_one/:id", async (req, res) => {
742
788
  try {
743
789
  const request = await micro.json(req);
744
790
  const { requestId, serviceName } = request;
@@ -767,7 +813,7 @@ router$5.post("/api/v1/mock/notification_one/:id", async (req, res) => {
767
813
  });
768
814
  }
769
815
  });
770
- router$5.post("/api/v1/mock/notification_filter", async (req, res) => {
816
+ router$6.post("/api/v1/mock/notification_filter", async (req, res) => {
771
817
  try {
772
818
  const request = await micro.json(req);
773
819
  const { requestId, serviceName, filterData, limit, offset } = request;
@@ -796,7 +842,7 @@ router$5.post("/api/v1/mock/notification_filter", async (req, res) => {
796
842
  }
797
843
  });
798
844
  // StorageMockService endpoints
799
- router$5.post("/api/v1/mock/storage_one/:id", async (req, res) => {
845
+ router$6.post("/api/v1/mock/storage_one/:id", async (req, res) => {
800
846
  try {
801
847
  const request = await micro.json(req);
802
848
  const { requestId, serviceName } = request;
@@ -825,7 +871,7 @@ router$5.post("/api/v1/mock/storage_one/:id", async (req, res) => {
825
871
  });
826
872
  }
827
873
  });
828
- router$5.post("/api/v1/mock/storage_list/live", async (req, res) => {
874
+ router$6.post("/api/v1/mock/storage_list/live", async (req, res) => {
829
875
  try {
830
876
  const request = await micro.json(req);
831
877
  const { requestId, serviceName } = request;
@@ -853,7 +899,7 @@ router$5.post("/api/v1/mock/storage_list/live", async (req, res) => {
853
899
  });
854
900
  }
855
901
  });
856
- router$5.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
902
+ router$6.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
857
903
  try {
858
904
  const request = await micro.json(req);
859
905
  const { requestId, serviceName } = request;
@@ -882,11 +928,11 @@ router$5.post("/api/v1/mock/storage_list/backtest", async (req, res) => {
882
928
  }
883
929
  });
884
930
 
885
- const router$4 = Router({
931
+ const router$5 = Router({
886
932
  params: true,
887
933
  });
888
934
  // ExchangeViewService endpoints
889
- router$4.post("/api/v1/view/candles_signal", async (req, res) => {
935
+ router$5.post("/api/v1/view/candles_signal", async (req, res) => {
890
936
  try {
891
937
  const request = await micro.json(req);
892
938
  const { signalId, interval, requestId, serviceName } = request;
@@ -914,7 +960,7 @@ router$4.post("/api/v1/view/candles_signal", async (req, res) => {
914
960
  });
915
961
  }
916
962
  });
917
- router$4.post("/api/v1/view/candles_point", async (req, res) => {
963
+ router$5.post("/api/v1/view/candles_point", async (req, res) => {
918
964
  try {
919
965
  const request = await micro.json(req);
920
966
  const { currentTime, interval, requestId, serviceName, symbol, exchangeName } = request;
@@ -948,7 +994,7 @@ router$4.post("/api/v1/view/candles_point", async (req, res) => {
948
994
  }
949
995
  });
950
996
  // NotificationViewService endpoints
951
- router$4.post("/api/v1/view/notification_list", async (req, res) => {
997
+ router$5.post("/api/v1/view/notification_list", async (req, res) => {
952
998
  try {
953
999
  const request = await micro.json(req);
954
1000
  const { requestId, serviceName } = request;
@@ -976,7 +1022,7 @@ router$4.post("/api/v1/view/notification_list", async (req, res) => {
976
1022
  });
977
1023
  }
978
1024
  });
979
- router$4.post("/api/v1/view/notification_one/:id", async (req, res) => {
1025
+ router$5.post("/api/v1/view/notification_one/:id", async (req, res) => {
980
1026
  try {
981
1027
  const request = await micro.json(req);
982
1028
  const { requestId, serviceName } = request;
@@ -1005,7 +1051,7 @@ router$4.post("/api/v1/view/notification_one/:id", async (req, res) => {
1005
1051
  });
1006
1052
  }
1007
1053
  });
1008
- router$4.post("/api/v1/view/notification_filter", async (req, res) => {
1054
+ router$5.post("/api/v1/view/notification_filter", async (req, res) => {
1009
1055
  try {
1010
1056
  const request = await micro.json(req);
1011
1057
  const { requestId, serviceName, filterData, limit, offset } = request;
@@ -1034,7 +1080,7 @@ router$4.post("/api/v1/view/notification_filter", async (req, res) => {
1034
1080
  }
1035
1081
  });
1036
1082
  // StorageViewService endpoints
1037
- router$4.post("/api/v1/view/storage_one/:id", async (req, res) => {
1083
+ router$5.post("/api/v1/view/storage_one/:id", async (req, res) => {
1038
1084
  try {
1039
1085
  const request = await micro.json(req);
1040
1086
  const { requestId, serviceName } = request;
@@ -1063,7 +1109,7 @@ router$4.post("/api/v1/view/storage_one/:id", async (req, res) => {
1063
1109
  });
1064
1110
  }
1065
1111
  });
1066
- router$4.post("/api/v1/view/storage_list/live", async (req, res) => {
1112
+ router$5.post("/api/v1/view/storage_list/live", async (req, res) => {
1067
1113
  try {
1068
1114
  const request = await micro.json(req);
1069
1115
  const { requestId, serviceName } = request;
@@ -1091,7 +1137,7 @@ router$4.post("/api/v1/view/storage_list/live", async (req, res) => {
1091
1137
  });
1092
1138
  }
1093
1139
  });
1094
- router$4.post("/api/v1/view/storage_list/backtest", async (req, res) => {
1140
+ router$5.post("/api/v1/view/storage_list/backtest", async (req, res) => {
1095
1141
  try {
1096
1142
  const request = await micro.json(req);
1097
1143
  const { requestId, serviceName } = request;
@@ -1127,7 +1173,7 @@ function getModulesPath() {
1127
1173
  return join(basePath, "../../../");
1128
1174
  }
1129
1175
 
1130
- const router$3 = Router({
1176
+ const router$4 = Router({
1131
1177
  params: true,
1132
1178
  });
1133
1179
  // getModulesPath
@@ -1144,7 +1190,7 @@ const ASSET_32 = CC_ENABLE_MOCK
1144
1190
  const cache128 = new Map();
1145
1191
  const cache32 = new Map();
1146
1192
  const cacheSvg = new Map();
1147
- router$3.get("/icon/128/:filename", async (req, res) => {
1193
+ router$4.get("/icon/128/:filename", async (req, res) => {
1148
1194
  const filename = req.params.filename;
1149
1195
  // Check cache first
1150
1196
  if (cache128.has(filename)) {
@@ -1160,7 +1206,7 @@ router$3.get("/icon/128/:filename", async (req, res) => {
1160
1206
  }
1161
1207
  return await micro.send(res, 404, "File not found (128)");
1162
1208
  });
1163
- router$3.get("/icon/32/:filename", async (req, res) => {
1209
+ router$4.get("/icon/32/:filename", async (req, res) => {
1164
1210
  const filename = req.params.filename;
1165
1211
  // Check cache first
1166
1212
  if (cache32.has(filename)) {
@@ -1176,7 +1222,7 @@ router$3.get("/icon/32/:filename", async (req, res) => {
1176
1222
  }
1177
1223
  return await micro.send(res, 404, "File not found (32)");
1178
1224
  });
1179
- router$3.get("/icon/svg/:filename", async (req, res) => {
1225
+ router$4.get("/icon/svg/:filename", async (req, res) => {
1180
1226
  const filename = req.params.filename;
1181
1227
  // Check cache first
1182
1228
  if (cacheSvg.has(filename)) {
@@ -1192,7 +1238,7 @@ router$3.get("/icon/svg/:filename", async (req, res) => {
1192
1238
  }
1193
1239
  return await micro.send(res, 404, "File not found (svg)");
1194
1240
  });
1195
- router$3.get("/icon/:filename", async (req, res) => {
1241
+ router$4.get("/icon/:filename", async (req, res) => {
1196
1242
  const filename = req.params.filename;
1197
1243
  // Check cache first
1198
1244
  if (cache32.has(filename)) {
@@ -1209,10 +1255,10 @@ router$3.get("/icon/:filename", async (req, res) => {
1209
1255
  return await micro.send(res, 404, "File not found (root)");
1210
1256
  });
1211
1257
 
1212
- const router$2 = Router({
1258
+ const router$3 = Router({
1213
1259
  params: true,
1214
1260
  });
1215
- router$2.post("/api/v1/dict/symbol/list", async (req, res) => {
1261
+ router$3.post("/api/v1/dict/symbol/list", async (req, res) => {
1216
1262
  try {
1217
1263
  const request = await micro.json(req);
1218
1264
  const { requestId, serviceName } = request;
@@ -1240,7 +1286,7 @@ router$2.post("/api/v1/dict/symbol/list", async (req, res) => {
1240
1286
  });
1241
1287
  }
1242
1288
  });
1243
- router$2.post("/api/v1/dict/symbol/map", async (req, res) => {
1289
+ router$3.post("/api/v1/dict/symbol/map", async (req, res) => {
1244
1290
  try {
1245
1291
  const request = await micro.json(req);
1246
1292
  const { requestId, serviceName } = request;
@@ -1268,7 +1314,7 @@ router$2.post("/api/v1/dict/symbol/map", async (req, res) => {
1268
1314
  });
1269
1315
  }
1270
1316
  });
1271
- router$2.post("/api/v1/dict/symbol/one", async (req, res) => {
1317
+ router$3.post("/api/v1/dict/symbol/one", async (req, res) => {
1272
1318
  try {
1273
1319
  const request = await micro.json(req);
1274
1320
  const { requestId, serviceName, id } = request;
@@ -1297,6 +1343,38 @@ router$2.post("/api/v1/dict/symbol/one", async (req, res) => {
1297
1343
  }
1298
1344
  });
1299
1345
 
1346
+ const router$2 = Router({
1347
+ params: true,
1348
+ });
1349
+ router$2.post("/api/v1/global/signal_pending_price", async (req, res) => {
1350
+ try {
1351
+ const request = await micro.json(req);
1352
+ const { symbol, strategyName, exchangeName, frameName, backtest, requestId, serviceName } = request;
1353
+ const data = await ioc.priceConnectionService.getSignalPendingPrice(symbol, strategyName, exchangeName, frameName, backtest);
1354
+ const result = {
1355
+ data,
1356
+ status: "ok",
1357
+ error: "",
1358
+ requestId,
1359
+ serviceName,
1360
+ };
1361
+ ioc.loggerService.log("/api/v1/global/signal_pending_price ok", {
1362
+ request,
1363
+ result: omit(result, "data"),
1364
+ });
1365
+ return await micro.send(res, 200, result);
1366
+ }
1367
+ catch (error) {
1368
+ ioc.loggerService.log("/api/v1/global/signal_pending_price error", {
1369
+ error: errorData(error),
1370
+ });
1371
+ return await micro.send(res, 200, {
1372
+ status: "error",
1373
+ error: getErrorMessage(error),
1374
+ });
1375
+ }
1376
+ });
1377
+
1300
1378
  const require = createRequire(import.meta.url);
1301
1379
  function getPublicPath() {
1302
1380
  const modulePath = require.resolve('@backtest-kit/ui');
@@ -1308,18 +1386,21 @@ const router = Router({
1308
1386
  params: true,
1309
1387
  });
1310
1388
  router.all("/api/v1/health/*", (req, res) => {
1311
- return router$6(req, res, finalhandler(req, res));
1389
+ return router$7(req, res, finalhandler(req, res));
1312
1390
  });
1313
1391
  router.all("/api/v1/mock/*", (req, res) => {
1314
- return router$5(req, res, finalhandler(req, res));
1392
+ return router$6(req, res, finalhandler(req, res));
1315
1393
  });
1316
1394
  router.all("/api/v1/view/*", (req, res) => {
1317
- return router$4(req, res, finalhandler(req, res));
1395
+ return router$5(req, res, finalhandler(req, res));
1318
1396
  });
1319
1397
  router.all("/icon/*", (req, res) => {
1320
- return router$3(req, res, finalhandler(req, res));
1398
+ return router$4(req, res, finalhandler(req, res));
1321
1399
  });
1322
1400
  router.all("/api/v1/dict/*", (req, res) => {
1401
+ return router$3(req, res, finalhandler(req, res));
1402
+ });
1403
+ router.all("/api/v1/global/*", (req, res) => {
1323
1404
  return router$2(req, res, finalhandler(req, res));
1324
1405
  });
1325
1406
  router.get("/*", (req, res) => serveHandler(req, res, {
@@ -0,0 +1 @@
1
+ import{a7 as e,a8 as t,w as a,a9 as s,f as i,aa as r,ab as n,ac as o,ad as d,ae as c,af as l,ag as u,ah as m,c as h,i as p,B as b,J as x}from"./index-DawE4H64.js";const g=e(),f=["className","component","disableGutters","fixed","maxWidth","classes"],y=c(),k=g("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${n(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),W=e=>o({props:e,name:"MuiContainer",defaultTheme:y});const v=function(e={}){const{createStyledComponent:o=k,useThemeProps:c=W,componentName:u="MuiContainer"}=e,m=o(({theme:e,ownerState:a})=>t({width:"100%",marginLeft:"auto",boxSizing:"border-box",marginRight:"auto",display:"block"},!a.disableGutters&&{paddingLeft:e.spacing(2),paddingRight:e.spacing(2),[e.breakpoints.up("sm")]:{paddingLeft:e.spacing(3),paddingRight:e.spacing(3)}}),({theme:e,ownerState:t})=>t.fixed&&Object.keys(e.breakpoints.values).reduce((t,a)=>{const s=a,i=e.breakpoints.values[s];return 0!==i&&(t[e.breakpoints.up(s)]={maxWidth:`${i}${e.breakpoints.unit}`}),t},{}),({theme:e,ownerState:a})=>t({},"xs"===a.maxWidth&&{[e.breakpoints.up("xs")]:{maxWidth:Math.max(e.breakpoints.values.xs,444)}},a.maxWidth&&"xs"!==a.maxWidth&&{[e.breakpoints.up(a.maxWidth)]:{maxWidth:`${e.breakpoints.values[a.maxWidth]}${e.breakpoints.unit}`}}));return a.forwardRef(function(e,a){const o=c(e),{className:h,component:p="div",disableGutters:b=!1,fixed:x=!1,maxWidth:g="lg"}=o,y=s(o,f),k=t({},o,{component:p,disableGutters:b,fixed:x,maxWidth:g}),W=((e,t)=>{const{classes:a,fixed:s,disableGutters:i,maxWidth:r}=e,o={root:["root",r&&`maxWidth${n(String(r))}`,s&&"fixed",i&&"disableGutters"]};return d(o,e=>l(t,e),a)})(k,u);return i(m,t({as:p,ownerState:k,className:r(W.root,h),ref:a},y))})}({createStyledComponent:m("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${n(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),useThemeProps:e=>u({props:e,name:"MuiContainer"})}),w=h(i("path",{d:"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"}),"Refresh"),R=({className:e,symbol:t,style:a,sx:s})=>i(x,{children:async()=>{try{const r=(await p.symbolGlobalService.getSymbolMap())[t],n=null==r?void 0:r.icon,o=(null==r?void 0:r.color)||"#ccc";return i(b,{className:e,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:n?"transparent":o,...s},style:a,children:n?i("img",{loading:"lazy",crossOrigin:"anonymous",src:n,alt:t,style:{width:"100%",height:"100%",borderRadius:"50%",objectFit:"contain"},onError:e=>{const t=e.target,a=t.parentElement;a&&(a.style.background=o,t.style.display="none")}}):i(b,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}catch(r){return i(b,{className:e,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:"#ccc",...s},style:a,children:i(b,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}}});export{v as C,R as I,w as R};
@@ -0,0 +1 @@
1
+ import{c as e,f as a,a as n,Z as t,q as o,I as i,D as s,b as r,k as l,i as c,z as d,X as p,R as h,J as b,L as u,d as m,e as g,B as y,T as v,v as x,g as f,l as k,h as w,j as S,m as L,n as R,o as F,p as D,r as P,F as W,S as $,x as j,s as C}from"./index-DawE4H64.js";import{R as T,I as z,C as A}from"./IconPhoto-CC-I1xI7.js";const B=e(a("path",{d:"M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"}),"Dashboard"),I=new n,M=[{type:t.Link,action:"back-action",label:"Main"},{type:t.Link,action:"back-action",label:"Dashboard"}],N=[{action:"dashboard-action",label:"Dashboard",icon:()=>a(i,{icon:B,color:"#4caf50"})},{divider:!0},{action:"download-action",label:"Download",icon:()=>a(i,{icon:s,color:"#4caf50"})},{divider:!0},{action:"update-now",label:"Refresh",icon:()=>a(i,{icon:T,color:"#4caf50"})}],O=()=>a(o,{items:M,actions:N,onAction:I.next});const V=({data:{type:e},setLoading:n})=>{const{elementRef:t,size:o}=r({closest:".MuiContainer-root",compute:e=>(e.height-=150,e)}),[i,{loading:s,execute:$}]=l(async()=>"live"===e?await c.storageViewService.listSignalLive():await c.storageViewService.listSignalBacktest(),{onLoadStart:()=>n(!0),onLoadEnd:()=>n(!1),deps:[e]}),j=d(i),C=d(e);p(()=>I.subscribe(e=>{if("update-now"===e&&$(),"download-action"===e){const e=new Blob([JSON.stringify(j.current,null,2)],{type:"application/json"}),a=URL.createObjectURL(e);c.layoutService.downloadFile(a,`signals_${C.current}_${Date.now()}.json`)}"dashboard-action"===e&&c.routerService.push(`/dashboard/${C.current}`)}));const T=h.useMemo(()=>i?i.reduce((e,a)=>(e[a.symbol]||(e[a.symbol]=[]),e[a.symbol].push(a),e),{}):{},[i]),A=e=>{const n=T[e]||[];return n.length?a(W,{children:n.map((n,t)=>{return a(L,{sx:{background:e=>t%2==1?F(e.palette.getContrastText(e.palette.background.paper),.02):void 0},onClick:()=>c.layoutService.pickSignal(n.id),children:[a(m,{primary:a(y,{sx:{display:"flex",gap:2,flexWrap:"wrap",alignItems:"center"},children:[a(v,{variant:"body2",component:"span",sx:{fontWeight:"bold",px:1,py:.5,borderRadius:1,background:"long"===n.position?"#1976D2":"#F57C00",color:"white"},children:"long"===n.position?"LONG":"SHORT"}),a(v,{variant:"body2",component:"span",sx:{fontWeight:"medium"},children:[a(y,{component:"span",sx:{color:"text.secondary",mr:.5},children:"Entry:"}),R(n.priceOpen),"$"]}),a(v,{variant:"body2",component:"span",sx:{fontWeight:"medium",color:"success.main"},children:[a(y,{component:"span",sx:{color:"text.secondary",mr:.5},children:"TP:"}),R(n.priceTakeProfit),"$"]}),a(v,{variant:"body2",component:"span",sx:{fontWeight:"medium",color:"error.main"},children:[a(y,{component:"span",sx:{color:"text.secondary",mr:.5},children:"SL:"}),R(n.priceStopLoss),"$"]}),"pnl"in n&&a(v,{variant:"body2",component:"span",sx:{fontWeight:"bold",px:1,py:.5,borderRadius:1,background:n.pnl.pnlPercentage>=0?F("#4caf50",.15):F("#f44336",.15),color:n.pnl.pnlPercentage>=0?"#2e7d32":"#c62828"},children:["PNL: ",n.pnl.pnlPercentage>=0?"+":"",n.pnl.pnlPercentage.toFixed(2),"%"]}),a(v,{variant:"caption",component:"span",sx:{px:1,py:.25,borderRadius:.5,background:"opened"===n.status?F("#4caf50",.2):"scheduled"===n.status?F("#ff9800",.2):"closed"===n.status?F("#9e9e9e",.2):F("#f44336",.2),color:"opened"===n.status?"#2e7d32":"scheduled"===n.status?"#e65100":"closed"===n.status?"#616161":"#c62828"},children:n.status})]}),secondary:a(v,{pt:.5,variant:"subtitle2",sx:{opacity:.5},children:(o=n.createdAt||n.pendingAt,new Date(o).toLocaleString([],{year:"numeric",month:"numeric",day:"numeric",hourCycle:"h24",hour:"2-digit",minute:"2-digit",second:"2-digit"}))})}),a(D,{disableRipple:!0,children:a(P,{})})]},`item-${e}-${n.id}`);var o})}):a(u,{children:a(m,{sx:{"& .MuiTypography-body2":{maxWidth:"435px"}},primary:"No signals",secondary:"Signals will be displayed here after they appear"})})};return s?null:a(w,{ref:t,sx:{width:"100%",maxHeight:o.height,overflowX:"hidden",overflowY:"auto",scrollbarWidth:"thin",bgcolor:"background.paper",position:"relative","& ul":{padding:0}},subheader:a("li",{}),children:a(b,{deps:[T],children:async()=>{const n=Object.keys(T),t=await c.symbolGlobalService.getSymbolMap();return n.length?n.map(e=>{var n,o,i;const s=null==(n=t[e])?void 0:n.color,r=(null==(o=T[e])?void 0:o.length)||0;return a("li",{children:a("ul",{children:[a(g,{sx:{background:(l=s,S(l,"#000000")>S(l,"#FFFFFF")?f(s,.1):k(s,.1)),color:"white !important",zIndex:9,display:"flex",alignItems:"center",justifyContent:"space-between"},children:[a(y,{sx:{position:"relative",paddingRight:"8px"},children:a(z,{symbol:e})}),(null==(i=t[e])?void 0:i.displayName)||e,a(y,{flex:1}),a(v,{variant:"body2",sx:{fontWeight:"medium"},children:x(r,{one:"Signal",two:"Signals",many:"Signals"})})]}),a(y,{sx:{marginTop:"16px",marginBottom:"16px"},children:A(e)})]})},`section-${e}`);var l}):a(u,{children:a(m,{primary:"No signals yet",secondary:"live"===e?"Live signals will be displayed here":"Backtest signals will be displayed here"})})}})})},H=()=>a($,{children:"\n body {\n background-color: #ddd !important;\n }\n "}),E=C(),G=(e,a)=>e.some(e=>e.includes(a)),J=[{id:"backtest",element:V,isActive:e=>G(["/backtest"],e)},{id:"live",element:V,isActive:e=>G(["/live"],e)}],U=[{id:"backtest",label:"Backtest"},{id:"live",label:"Live"}],X=({symbol:e})=>{p(()=>E.replace("/backtest"));return a(A,{children:[a(j,{withScroll:!0,sx:{height:"calc(100vh - 105px)"},BeforePaper:O,onLoadStart:()=>c.layoutService.setAppbarLoader(!0),onLoadEnd:()=>c.layoutService.setAppbarLoader(!1),routes:J,tabs:U,history:E,initialData:()=>({backtest:{type:"backtest"},live:{type:"live"}}),payload:()=>({symbol:e}),onTabChange:(e,a)=>{"backtest"===e&&a.replace("/backtest"),"live"===e&&a.replace("/live")}}),a(H,{})]})};export{X as MainPage,X as default};