@backtest-kit/ui 6.15.0 → 7.0.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.
Files changed (42) hide show
  1. package/README.md +3 -1
  2. package/build/index.cjs +108 -16
  3. package/build/index.mjs +109 -17
  4. package/build/modules/frontend/build/3rdparty/qfchart_0.8.7/echarts.min.js +45 -0
  5. package/build/modules/frontend/build/3rdparty/qfchart_0.8.7/pinets.js +122 -0
  6. package/build/modules/frontend/build/3rdparty/qfchart_0.8.7/qfchart.js +58 -0
  7. package/build/modules/frontend/build/assets/Article-CUKUVtNn.js +1 -0
  8. package/build/modules/frontend/build/assets/Background-Cm7NWjYf.js +1 -0
  9. package/build/modules/frontend/build/assets/{IconPhoto-CNX0t203.js → IconPhoto-VQJtz-we.js} +1 -1
  10. package/build/modules/frontend/build/assets/{KeyboardArrowLeft-5ogjRzwF.js → KeyboardArrowLeft-Bx3w5JlP.js} +1 -1
  11. package/build/modules/frontend/build/assets/Refresh-BkaYn01m.js +1 -0
  12. package/build/modules/frontend/build/assets/emitters-DFr8bMD1.js +1 -0
  13. package/build/modules/frontend/build/assets/hasRouteMatch-F5OIUGjU.js +1 -0
  14. package/build/modules/frontend/build/assets/{html2canvas-BnarC1H-.js → html2canvas-D9EezEc_.js} +1 -1
  15. package/build/modules/frontend/build/assets/index-ApVR6Ifc.js +1 -0
  16. package/build/modules/frontend/build/assets/index-BTuorlT_.js +1 -0
  17. package/build/modules/frontend/build/assets/index-BdOvXECv.js +1 -0
  18. package/build/modules/frontend/build/assets/index-Bo9eE7UW.js +1 -0
  19. package/build/modules/frontend/build/assets/{index-CYHbLqvS.js → index-C6MJd2e7.js} +1 -1
  20. package/build/modules/frontend/build/assets/index-CROpLyTo.js +1 -0
  21. package/build/modules/frontend/build/assets/{index-BY7xx8Qo.js → index-ChbT-tDv.js} +1 -1
  22. package/build/modules/frontend/build/assets/index-Cx2iXzXi.js +1 -0
  23. package/build/modules/frontend/build/assets/{index-DLH5bivm.js → index-D4lcxG8i.js} +1 -1
  24. package/build/modules/frontend/build/assets/{index-eYCKhqo-.js → index-D5q-xBp8.js} +1 -1
  25. package/build/modules/frontend/build/assets/{index-BMzg4t4L.js → index-Mr3SEWze.js} +6 -6
  26. package/build/modules/frontend/build/assets/index-XWTSQlQH.js +1 -0
  27. package/build/modules/frontend/build/assets/{index.es-XkghWdRJ.js → index.es-Dy9r9ja5.js} +1 -1
  28. package/build/modules/frontend/build/assets/{markdownit-CFUj-lOk.js → markdownit-CaCiS1m5.js} +1 -1
  29. package/build/modules/frontend/build/index.html +4 -1
  30. package/package.json +4 -4
  31. package/types.d.ts +11 -2
  32. package/build/modules/frontend/build/assets/Article-BFiJ1grS.js +0 -1
  33. package/build/modules/frontend/build/assets/Background-C4tJEFCD.js +0 -1
  34. package/build/modules/frontend/build/assets/Refresh-DPMpKmUf.js +0 -1
  35. package/build/modules/frontend/build/assets/emitters-BxM0853t.js +0 -1
  36. package/build/modules/frontend/build/assets/hasRouteMatch-DvMTRSzL.js +0 -1
  37. package/build/modules/frontend/build/assets/index-2cnF0R3L.js +0 -1
  38. package/build/modules/frontend/build/assets/index-B9jcFvZN.js +0 -1
  39. package/build/modules/frontend/build/assets/index-C-XjS3CF.js +0 -1
  40. package/build/modules/frontend/build/assets/index-C1SBiwRD.js +0 -1
  41. package/build/modules/frontend/build/assets/index-C5kEItX6.js +0 -1
  42. package/build/modules/frontend/build/assets/index-Dl9D9lt4.js +0 -1
package/README.md CHANGED
@@ -12,7 +12,9 @@
12
12
 
13
13
  Interactive dashboard for backtest-kit with signal visualization, candle charts, risk analysis, and notification management. Built with React 18, Material-UI, and Lightweight Charts.
14
14
 
15
- 📚 **[Backtest Kit Docs](https://backtest-kit.github.io/documents/example_02_first_backtest.html)** | 🌟 **[GitHub](https://github.com/tripolskypetr/backtest-kit)**
15
+ 📚 **[Backtest Kit Docs](https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html)** | 🌟 **[GitHub](https://github.com/tripolskypetr/backtest-kit)**
16
+
17
+ > **New to backtest-kit?** The fastest way to get a real, production-ready setup is to clone the [reference implementation](https://github.com/tripolskypetr/backtest-kit/tree/master/example) — a fully working news-sentiment AI trading system with LLM forecasting, multi-timeframe data, and a documented February 2026 backtest. Start there instead of from scratch.
16
18
 
17
19
  ## ✨ Features
18
20
 
package/build/index.cjs CHANGED
@@ -111,7 +111,6 @@ const INTERVAL_MINUTES = {
111
111
  "6h": 360,
112
112
  "8h": 480,
113
113
  "1d": 1440,
114
- "1w": 10080,
115
114
  };
116
115
  const STEP_TICKS = {
117
116
  "1m": 960,
@@ -125,7 +124,6 @@ const STEP_TICKS = {
125
124
  "6h": 960,
126
125
  "8h": 960,
127
126
  "1d": 960,
128
- "1w": 960,
129
127
  };
130
128
  class ExchangeService {
131
129
  constructor() {
@@ -170,6 +168,18 @@ class ExchangeService {
170
168
  exchangeName: dto.exchangeName,
171
169
  });
172
170
  };
171
+ this.getRawCandles = async (dto) => {
172
+ this.loggerService.log("exchangeService getRawCandles", {
173
+ dto,
174
+ });
175
+ const [exchange = null] = await backtestKit.listExchangeSchema();
176
+ if (exchange === null) {
177
+ throw new Error("exchangeService getRawCandles no exchange registered");
178
+ }
179
+ return await backtestKit.Exchange.getRawCandles(dto.symbol, dto.interval, {
180
+ exchangeName: exchange.exchangeName,
181
+ }, dto.limit, dto.sDate, dto.eDate);
182
+ };
173
183
  }
174
184
  }
175
185
 
@@ -503,6 +513,8 @@ class StatusMockService {
503
513
  positionLevels,
504
514
  positionEntries,
505
515
  positionPartials,
516
+ _peak: status._peak,
517
+ _fall: status._fall,
506
518
  };
507
519
  };
508
520
  }
@@ -797,6 +809,10 @@ class NotificationViewService {
797
809
  if (CC_ENABLE_MOCK) {
798
810
  return await this.notificationMockService.findByFilter(filterData, limit, offset);
799
811
  }
812
+ if (!backtestKit.Notification.enable.hasValue()) {
813
+ console.warn("@backtest-kit/ui notificationViewService findByFilter notifications not enabled");
814
+ return [];
815
+ }
800
816
  const iter = functoolsKit.pickDocuments(limit, offset);
801
817
  const filterList = CREATE_FILTER_LIST_FN$1(filterData);
802
818
  for (const notification of await this.getList()) {
@@ -818,6 +834,10 @@ class NotificationViewService {
818
834
  if (CC_ENABLE_MOCK) {
819
835
  return await this.notificationMockService.getList();
820
836
  }
837
+ if (!backtestKit.Notification.enable.hasValue()) {
838
+ console.warn("@backtest-kit/ui notificationViewService getList notifications not enabled");
839
+ return [];
840
+ }
821
841
  const notificationList = [];
822
842
  for (const notification of await backtestKit.Notification.getData(false)) {
823
843
  notificationList.push(notification);
@@ -847,16 +867,13 @@ class NotificationViewService {
847
867
  if (CC_ENABLE_MOCK) {
848
868
  return await this.notificationMockService.getOne(id);
849
869
  }
870
+ if (!backtestKit.Notification.enable.hasValue()) {
871
+ console.warn("@backtest-kit/ui notificationViewService getOne notifications not enabled");
872
+ return null;
873
+ }
850
874
  const notificationList = await this.getList();
851
875
  return notificationList.find((item) => item.id === id) ?? null;
852
876
  };
853
- this.init = functoolsKit.singleshot(async () => {
854
- this.loggerService.log("notificationViewService init");
855
- if (CC_ENABLE_MOCK) {
856
- return;
857
- }
858
- backtestKit.Notification.enable();
859
- });
860
877
  }
861
878
  }
862
879
 
@@ -871,6 +888,10 @@ class StorageViewService {
871
888
  if (CC_ENABLE_MOCK) {
872
889
  return await this.storageMockService.findSignalById(signalId);
873
890
  }
891
+ if (!backtestKit.Storage.enable.hasValue()) {
892
+ console.warn("@backtest-kit/ui storageViewService findSignalById storage not enabled");
893
+ return null;
894
+ }
874
895
  return await backtestKit.Storage.findSignalById(signalId);
875
896
  };
876
897
  this.listSignalLive = async () => {
@@ -878,6 +899,10 @@ class StorageViewService {
878
899
  if (CC_ENABLE_MOCK) {
879
900
  return await this.storageMockService.listSignalLive();
880
901
  }
902
+ if (!backtestKit.Storage.enable.hasValue()) {
903
+ console.warn("@backtest-kit/ui storageViewService listSignalLive storage not enabled");
904
+ return [];
905
+ }
881
906
  const signalList = await backtestKit.Storage.listSignalLive();
882
907
  signalList.sort((a, b) => {
883
908
  const aHasTime = "createdAt" in a;
@@ -899,6 +924,10 @@ class StorageViewService {
899
924
  if (CC_ENABLE_MOCK) {
900
925
  return await this.storageMockService.listSignalBacktest();
901
926
  }
927
+ if (!backtestKit.Storage.enable.hasValue()) {
928
+ console.warn("@backtest-kit/ui storageViewService listSignalBacktest storage not enabled");
929
+ return [];
930
+ }
902
931
  const signalList = await backtestKit.Storage.listSignalBacktest();
903
932
  signalList.sort((a, b) => {
904
933
  const aHasTime = "createdAt" in a;
@@ -915,13 +944,6 @@ class StorageViewService {
915
944
  });
916
945
  return signalList;
917
946
  };
918
- this.init = functoolsKit.singleshot(async () => {
919
- this.loggerService.log("storageViewService init");
920
- if (CC_ENABLE_MOCK) {
921
- return;
922
- }
923
- backtestKit.Storage.enable();
924
- });
925
947
  }
926
948
  }
927
949
 
@@ -1170,6 +1192,8 @@ class StatusViewService {
1170
1192
  positionEntries,
1171
1193
  positionLevels,
1172
1194
  positionPartials,
1195
+ _peak: pendingSignal._peak,
1196
+ _fall: pendingSignal._fall,
1173
1197
  };
1174
1198
  };
1175
1199
  this.getStatusInfo = async () => {
@@ -1952,6 +1976,40 @@ router$a.post("/api/v1/mock/candles_point", async (req, res) => {
1952
1976
  });
1953
1977
  }
1954
1978
  });
1979
+ router$a.post("/api/v1/mock/candles_range", async (req, res) => {
1980
+ try {
1981
+ const request = await micro.json(req);
1982
+ const { symbol, interval, limit, sDate, eDate, requestId, serviceName } = request;
1983
+ const data = await ioc.exchangeService.getRawCandles({
1984
+ symbol,
1985
+ interval,
1986
+ limit,
1987
+ sDate,
1988
+ eDate,
1989
+ });
1990
+ const result = {
1991
+ data,
1992
+ status: "ok",
1993
+ error: "",
1994
+ requestId,
1995
+ serviceName,
1996
+ };
1997
+ ioc.loggerService.log("/api/v1/mock/candles_range ok", {
1998
+ request,
1999
+ result: omit(result, "data"),
2000
+ });
2001
+ return await micro.send(res, 200, result);
2002
+ }
2003
+ catch (error) {
2004
+ ioc.loggerService.log("/api/v1/mock/candles_range error", {
2005
+ error: functoolsKit.errorData(error),
2006
+ });
2007
+ return await micro.send(res, 200, {
2008
+ status: "error",
2009
+ error: functoolsKit.getErrorMessage(error),
2010
+ });
2011
+ }
2012
+ });
1955
2013
  // NotificationMockService endpoints
1956
2014
  router$a.post("/api/v1/mock/notification_list", async (req, res) => {
1957
2015
  try {
@@ -2533,6 +2591,40 @@ router$9.post("/api/v1/view/candles_point", async (req, res) => {
2533
2591
  });
2534
2592
  }
2535
2593
  });
2594
+ router$9.post("/api/v1/view/candles_range", async (req, res) => {
2595
+ try {
2596
+ const request = await micro.json(req);
2597
+ const { symbol, interval, limit, sDate, eDate, requestId, serviceName } = request;
2598
+ const data = await ioc.exchangeService.getRawCandles({
2599
+ symbol,
2600
+ interval,
2601
+ limit,
2602
+ sDate,
2603
+ eDate,
2604
+ });
2605
+ const result = {
2606
+ data,
2607
+ status: "ok",
2608
+ error: "",
2609
+ requestId,
2610
+ serviceName,
2611
+ };
2612
+ ioc.loggerService.log("/api/v1/view/candles_range ok", {
2613
+ request,
2614
+ result: omit(result, "data"),
2615
+ });
2616
+ return await micro.send(res, 200, result);
2617
+ }
2618
+ catch (error) {
2619
+ ioc.loggerService.log("/api/v1/view/candles_range error", {
2620
+ error: functoolsKit.errorData(error),
2621
+ });
2622
+ return await micro.send(res, 200, {
2623
+ status: "error",
2624
+ error: functoolsKit.getErrorMessage(error),
2625
+ });
2626
+ }
2627
+ });
2536
2628
  router$9.post("/api/v1/view/candles_live", async (req, res) => {
2537
2629
  try {
2538
2630
  const request = await micro.json(req);
package/build/index.mjs CHANGED
@@ -6,7 +6,7 @@ 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 { alignToInterval, Exchange, Backtest, Live, listExchangeSchema, Notification, Storage, Log, lib, Heat, Strategy, Breakeven, Risk, Partial, HighestProfit, MaxDrawdown, Schedule, Performance, Sync, Walker, StorageLive, StorageBacktest } from 'backtest-kit';
9
+ import { alignToInterval, Exchange, listExchangeSchema, Backtest, Live, Notification, Storage, Log, lib, Heat, Strategy, Breakeven, Risk, Partial, HighestProfit, MaxDrawdown, Schedule, Performance, Sync, Walker, StorageLive, StorageBacktest } from 'backtest-kit';
10
10
  import fs, { readdir, readFile } from 'fs/promises';
11
11
  import path, { join, dirname } from 'path';
12
12
  import mime from 'mime-types';
@@ -108,7 +108,6 @@ const INTERVAL_MINUTES = {
108
108
  "6h": 360,
109
109
  "8h": 480,
110
110
  "1d": 1440,
111
- "1w": 10080,
112
111
  };
113
112
  const STEP_TICKS = {
114
113
  "1m": 960,
@@ -122,7 +121,6 @@ const STEP_TICKS = {
122
121
  "6h": 960,
123
122
  "8h": 960,
124
123
  "1d": 960,
125
- "1w": 960,
126
124
  };
127
125
  class ExchangeService {
128
126
  constructor() {
@@ -167,6 +165,18 @@ class ExchangeService {
167
165
  exchangeName: dto.exchangeName,
168
166
  });
169
167
  };
168
+ this.getRawCandles = async (dto) => {
169
+ this.loggerService.log("exchangeService getRawCandles", {
170
+ dto,
171
+ });
172
+ const [exchange = null] = await listExchangeSchema();
173
+ if (exchange === null) {
174
+ throw new Error("exchangeService getRawCandles no exchange registered");
175
+ }
176
+ return await Exchange.getRawCandles(dto.symbol, dto.interval, {
177
+ exchangeName: exchange.exchangeName,
178
+ }, dto.limit, dto.sDate, dto.eDate);
179
+ };
170
180
  }
171
181
  }
172
182
 
@@ -500,6 +510,8 @@ class StatusMockService {
500
510
  positionLevels,
501
511
  positionEntries,
502
512
  positionPartials,
513
+ _peak: status._peak,
514
+ _fall: status._fall,
503
515
  };
504
516
  };
505
517
  }
@@ -794,6 +806,10 @@ class NotificationViewService {
794
806
  if (CC_ENABLE_MOCK) {
795
807
  return await this.notificationMockService.findByFilter(filterData, limit, offset);
796
808
  }
809
+ if (!Notification.enable.hasValue()) {
810
+ console.warn("@backtest-kit/ui notificationViewService findByFilter notifications not enabled");
811
+ return [];
812
+ }
797
813
  const iter = pickDocuments(limit, offset);
798
814
  const filterList = CREATE_FILTER_LIST_FN$1(filterData);
799
815
  for (const notification of await this.getList()) {
@@ -815,6 +831,10 @@ class NotificationViewService {
815
831
  if (CC_ENABLE_MOCK) {
816
832
  return await this.notificationMockService.getList();
817
833
  }
834
+ if (!Notification.enable.hasValue()) {
835
+ console.warn("@backtest-kit/ui notificationViewService getList notifications not enabled");
836
+ return [];
837
+ }
818
838
  const notificationList = [];
819
839
  for (const notification of await Notification.getData(false)) {
820
840
  notificationList.push(notification);
@@ -844,16 +864,13 @@ class NotificationViewService {
844
864
  if (CC_ENABLE_MOCK) {
845
865
  return await this.notificationMockService.getOne(id);
846
866
  }
867
+ if (!Notification.enable.hasValue()) {
868
+ console.warn("@backtest-kit/ui notificationViewService getOne notifications not enabled");
869
+ return null;
870
+ }
847
871
  const notificationList = await this.getList();
848
872
  return notificationList.find((item) => item.id === id) ?? null;
849
873
  };
850
- this.init = singleshot(async () => {
851
- this.loggerService.log("notificationViewService init");
852
- if (CC_ENABLE_MOCK) {
853
- return;
854
- }
855
- Notification.enable();
856
- });
857
874
  }
858
875
  }
859
876
 
@@ -868,6 +885,10 @@ class StorageViewService {
868
885
  if (CC_ENABLE_MOCK) {
869
886
  return await this.storageMockService.findSignalById(signalId);
870
887
  }
888
+ if (!Storage.enable.hasValue()) {
889
+ console.warn("@backtest-kit/ui storageViewService findSignalById storage not enabled");
890
+ return null;
891
+ }
871
892
  return await Storage.findSignalById(signalId);
872
893
  };
873
894
  this.listSignalLive = async () => {
@@ -875,6 +896,10 @@ class StorageViewService {
875
896
  if (CC_ENABLE_MOCK) {
876
897
  return await this.storageMockService.listSignalLive();
877
898
  }
899
+ if (!Storage.enable.hasValue()) {
900
+ console.warn("@backtest-kit/ui storageViewService listSignalLive storage not enabled");
901
+ return [];
902
+ }
878
903
  const signalList = await Storage.listSignalLive();
879
904
  signalList.sort((a, b) => {
880
905
  const aHasTime = "createdAt" in a;
@@ -896,6 +921,10 @@ class StorageViewService {
896
921
  if (CC_ENABLE_MOCK) {
897
922
  return await this.storageMockService.listSignalBacktest();
898
923
  }
924
+ if (!Storage.enable.hasValue()) {
925
+ console.warn("@backtest-kit/ui storageViewService listSignalBacktest storage not enabled");
926
+ return [];
927
+ }
899
928
  const signalList = await Storage.listSignalBacktest();
900
929
  signalList.sort((a, b) => {
901
930
  const aHasTime = "createdAt" in a;
@@ -912,13 +941,6 @@ class StorageViewService {
912
941
  });
913
942
  return signalList;
914
943
  };
915
- this.init = singleshot(async () => {
916
- this.loggerService.log("storageViewService init");
917
- if (CC_ENABLE_MOCK) {
918
- return;
919
- }
920
- Storage.enable();
921
- });
922
944
  }
923
945
  }
924
946
 
@@ -1167,6 +1189,8 @@ class StatusViewService {
1167
1189
  positionEntries,
1168
1190
  positionLevels,
1169
1191
  positionPartials,
1192
+ _peak: pendingSignal._peak,
1193
+ _fall: pendingSignal._fall,
1170
1194
  };
1171
1195
  };
1172
1196
  this.getStatusInfo = async () => {
@@ -1949,6 +1973,40 @@ router$a.post("/api/v1/mock/candles_point", async (req, res) => {
1949
1973
  });
1950
1974
  }
1951
1975
  });
1976
+ router$a.post("/api/v1/mock/candles_range", async (req, res) => {
1977
+ try {
1978
+ const request = await micro.json(req);
1979
+ const { symbol, interval, limit, sDate, eDate, requestId, serviceName } = request;
1980
+ const data = await ioc.exchangeService.getRawCandles({
1981
+ symbol,
1982
+ interval,
1983
+ limit,
1984
+ sDate,
1985
+ eDate,
1986
+ });
1987
+ const result = {
1988
+ data,
1989
+ status: "ok",
1990
+ error: "",
1991
+ requestId,
1992
+ serviceName,
1993
+ };
1994
+ ioc.loggerService.log("/api/v1/mock/candles_range ok", {
1995
+ request,
1996
+ result: omit(result, "data"),
1997
+ });
1998
+ return await micro.send(res, 200, result);
1999
+ }
2000
+ catch (error) {
2001
+ ioc.loggerService.log("/api/v1/mock/candles_range error", {
2002
+ error: errorData(error),
2003
+ });
2004
+ return await micro.send(res, 200, {
2005
+ status: "error",
2006
+ error: getErrorMessage(error),
2007
+ });
2008
+ }
2009
+ });
1952
2010
  // NotificationMockService endpoints
1953
2011
  router$a.post("/api/v1/mock/notification_list", async (req, res) => {
1954
2012
  try {
@@ -2530,6 +2588,40 @@ router$9.post("/api/v1/view/candles_point", async (req, res) => {
2530
2588
  });
2531
2589
  }
2532
2590
  });
2591
+ router$9.post("/api/v1/view/candles_range", async (req, res) => {
2592
+ try {
2593
+ const request = await micro.json(req);
2594
+ const { symbol, interval, limit, sDate, eDate, requestId, serviceName } = request;
2595
+ const data = await ioc.exchangeService.getRawCandles({
2596
+ symbol,
2597
+ interval,
2598
+ limit,
2599
+ sDate,
2600
+ eDate,
2601
+ });
2602
+ const result = {
2603
+ data,
2604
+ status: "ok",
2605
+ error: "",
2606
+ requestId,
2607
+ serviceName,
2608
+ };
2609
+ ioc.loggerService.log("/api/v1/view/candles_range ok", {
2610
+ request,
2611
+ result: omit(result, "data"),
2612
+ });
2613
+ return await micro.send(res, 200, result);
2614
+ }
2615
+ catch (error) {
2616
+ ioc.loggerService.log("/api/v1/view/candles_range error", {
2617
+ error: errorData(error),
2618
+ });
2619
+ return await micro.send(res, 200, {
2620
+ status: "error",
2621
+ error: getErrorMessage(error),
2622
+ });
2623
+ }
2624
+ });
2533
2625
  router$9.post("/api/v1/view/candles_live", async (req, res) => {
2534
2626
  try {
2535
2627
  const request = await micro.json(req);