@backtest-kit/cli 3.8.0 → 5.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.
- package/README.md +81 -56
- package/build/index.cjs +65 -209
- package/build/index.mjs +67 -211
- package/package.json +13 -13
- package/template/average-buy.mustache +6 -1
- package/template/breakeven.mustache +7 -3
- package/template/cancelled.mustache +5 -1
- package/template/closed.mustache +7 -2
- package/template/opened.mustache +5 -1
- package/template/partial-loss.mustache +6 -2
- package/template/partial-profit.mustache +6 -2
- package/template/risk.mustache +5 -5
- package/template/scheduled.mustache +5 -1
- package/template/signal-close.mustache +21 -0
- package/template/signal-open.mustache +21 -0
- package/template/trailing-stop.mustache +5 -2
- package/template/trailing-take.mustache +5 -2
- package/types.d.ts +10 -41
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 { Storage, Notification, Markdown, Report, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit } from 'backtest-kit';
|
|
4
|
-
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, execpool, queued, sleep, randomString, createAwaiter, TIMEOUT_SYMBOL, typo, retry,
|
|
3
|
+
import { Storage, Notification, Markdown, Report, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync } from 'backtest-kit';
|
|
4
|
+
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, execpool, queued, sleep, randomString, createAwaiter, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize } from 'functools-kit';
|
|
5
5
|
import fs, { constants } from 'fs';
|
|
6
6
|
import * as stackTrace from 'stack-trace';
|
|
7
7
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -200,7 +200,6 @@ const schemaServices$1 = {
|
|
|
200
200
|
const providerServices$1 = {
|
|
201
201
|
frontendProviderService: Symbol('frontendProviderService'),
|
|
202
202
|
telegramProviderService: Symbol('telegramProviderService'),
|
|
203
|
-
liveProviderService: Symbol('liveProviderService'),
|
|
204
203
|
};
|
|
205
204
|
const webServices$1 = {
|
|
206
205
|
telegramWebService: Symbol('telegramWebService'),
|
|
@@ -586,6 +585,7 @@ class BacktestMainService {
|
|
|
586
585
|
this.cacheLogicService = inject(TYPES.cacheLogicService);
|
|
587
586
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
588
587
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
588
|
+
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
589
589
|
this.run = singleshot(async (payload) => {
|
|
590
590
|
this.loggerService.log("backtestMainService run", {
|
|
591
591
|
payload,
|
|
@@ -634,6 +634,7 @@ class BacktestMainService {
|
|
|
634
634
|
});
|
|
635
635
|
notifyVerbose();
|
|
636
636
|
}
|
|
637
|
+
await this.moduleConnectionService.loadModule("./backtest.module");
|
|
637
638
|
Backtest.background(symbol, {
|
|
638
639
|
strategyName,
|
|
639
640
|
frameName,
|
|
@@ -677,7 +678,7 @@ class LiveMainService {
|
|
|
677
678
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
678
679
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
679
680
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
680
|
-
this.
|
|
681
|
+
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
681
682
|
this.run = singleshot(async (payload) => {
|
|
682
683
|
this.loggerService.log("liveMainService run", {
|
|
683
684
|
payload,
|
|
@@ -685,7 +686,6 @@ class LiveMainService {
|
|
|
685
686
|
{
|
|
686
687
|
this.frontendProviderService.connect();
|
|
687
688
|
this.telegramProviderService.connect();
|
|
688
|
-
this.liveProviderService.connect();
|
|
689
689
|
}
|
|
690
690
|
await this.resolveService.attachEntryPoint(payload.entryPoint);
|
|
691
691
|
{
|
|
@@ -714,6 +714,7 @@ class LiveMainService {
|
|
|
714
714
|
});
|
|
715
715
|
notifyVerbose();
|
|
716
716
|
}
|
|
717
|
+
await this.moduleConnectionService.loadModule("./live.module");
|
|
717
718
|
Live.background(symbol, {
|
|
718
719
|
strategyName,
|
|
719
720
|
exchangeName,
|
|
@@ -752,6 +753,7 @@ class PaperMainService {
|
|
|
752
753
|
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
753
754
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
754
755
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
756
|
+
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
755
757
|
this.run = singleshot(async (payload) => {
|
|
756
758
|
this.loggerService.log("paperMainService init");
|
|
757
759
|
{
|
|
@@ -785,6 +787,7 @@ class PaperMainService {
|
|
|
785
787
|
});
|
|
786
788
|
notifyVerbose();
|
|
787
789
|
}
|
|
790
|
+
await this.moduleConnectionService.loadModule("./paper.module");
|
|
788
791
|
Live.background(symbol, {
|
|
789
792
|
strategyName,
|
|
790
793
|
exchangeName,
|
|
@@ -1487,6 +1490,26 @@ class TelegramLogicService {
|
|
|
1487
1490
|
markdown,
|
|
1488
1491
|
});
|
|
1489
1492
|
};
|
|
1493
|
+
this.notifySignalOpen = trycatch(async (event) => {
|
|
1494
|
+
this.loggerService.log("telegramLogicService notifySignalOpen", {
|
|
1495
|
+
event,
|
|
1496
|
+
});
|
|
1497
|
+
const markdown = await this.telegramTemplateService.getSignalOpenMarkdown(event);
|
|
1498
|
+
await this.telegramWebService.publishNotify({
|
|
1499
|
+
symbol: event.symbol,
|
|
1500
|
+
markdown,
|
|
1501
|
+
});
|
|
1502
|
+
});
|
|
1503
|
+
this.notifySignalClose = trycatch(async (event) => {
|
|
1504
|
+
this.loggerService.log("telegramLogicService notifySignalClose", {
|
|
1505
|
+
event,
|
|
1506
|
+
});
|
|
1507
|
+
const markdown = await this.telegramTemplateService.getSignalCloseMarkdown(event);
|
|
1508
|
+
await this.telegramWebService.publishNotify({
|
|
1509
|
+
symbol: event.symbol,
|
|
1510
|
+
markdown,
|
|
1511
|
+
});
|
|
1512
|
+
});
|
|
1490
1513
|
this.connect = singleshot(() => {
|
|
1491
1514
|
this.loggerService.log("telegramLogicService connect");
|
|
1492
1515
|
const unRisk = listenRisk(async (event) => {
|
|
@@ -1536,8 +1559,18 @@ class TelegramLogicService {
|
|
|
1536
1559
|
return;
|
|
1537
1560
|
}
|
|
1538
1561
|
});
|
|
1562
|
+
const unSync = listenSync(async (event) => {
|
|
1563
|
+
if (event.action === "signal-open") {
|
|
1564
|
+
await this.notifySignalOpen(event);
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
if (event.action === "signal-close") {
|
|
1568
|
+
await this.notifySignalClose(event);
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1539
1572
|
const unConnect = () => this.connect.clear();
|
|
1540
|
-
const unListen = compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unConnect());
|
|
1573
|
+
const unListen = compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unSync(), () => unConnect());
|
|
1541
1574
|
return () => {
|
|
1542
1575
|
STOP_BOT_FN();
|
|
1543
1576
|
unListen();
|
|
@@ -1632,6 +1665,18 @@ class TelegramTemplateService {
|
|
|
1632
1665
|
});
|
|
1633
1666
|
return await RENDER_TEMPLATE_FN("average-buy.mustache", event, this);
|
|
1634
1667
|
};
|
|
1668
|
+
this.getSignalOpenMarkdown = async (event) => {
|
|
1669
|
+
this.loggerService.log("telegramTemplateService getSignalOpenMarkdown", {
|
|
1670
|
+
event,
|
|
1671
|
+
});
|
|
1672
|
+
return await RENDER_TEMPLATE_FN("signal-open.mustache", event, this);
|
|
1673
|
+
};
|
|
1674
|
+
this.getSignalCloseMarkdown = async (event) => {
|
|
1675
|
+
this.loggerService.log("telegramTemplateService getSignalCloseMarkdown", {
|
|
1676
|
+
event,
|
|
1677
|
+
});
|
|
1678
|
+
return await RENDER_TEMPLATE_FN("signal-close.mustache", event, this);
|
|
1679
|
+
};
|
|
1635
1680
|
}
|
|
1636
1681
|
}
|
|
1637
1682
|
|
|
@@ -1650,39 +1695,36 @@ const getExtVariants = (fileName) => {
|
|
|
1650
1695
|
};
|
|
1651
1696
|
const REQUIRE_MODULE_FACTORY = (fileName) => {
|
|
1652
1697
|
{
|
|
1653
|
-
return
|
|
1698
|
+
return false;
|
|
1654
1699
|
}
|
|
1655
1700
|
};
|
|
1656
1701
|
const IMPORT_MODULE_FACTORY = async (fileName) => {
|
|
1657
1702
|
for (const variant of getExtVariants(fileName)) {
|
|
1658
1703
|
try {
|
|
1659
|
-
|
|
1704
|
+
await import(pathToFileURL(variant).href);
|
|
1705
|
+
return true;
|
|
1660
1706
|
}
|
|
1661
1707
|
catch {
|
|
1662
1708
|
continue;
|
|
1663
1709
|
}
|
|
1664
1710
|
}
|
|
1665
|
-
return
|
|
1711
|
+
return false;
|
|
1666
1712
|
};
|
|
1667
1713
|
const BABEL_MODULE_FACTORY = async (fileName, self) => {
|
|
1668
1714
|
for (const variant of getExtVariants(fileName)) {
|
|
1669
1715
|
try {
|
|
1670
1716
|
const code = await fs$1.readFile(variant, "utf-8");
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
return exports.default;
|
|
1674
|
-
}
|
|
1675
|
-
return exports;
|
|
1717
|
+
self.babelService.transpileAndRun(code);
|
|
1718
|
+
return true;
|
|
1676
1719
|
}
|
|
1677
1720
|
catch (error) {
|
|
1678
1721
|
console.log(getErrorMessage(error));
|
|
1679
1722
|
continue;
|
|
1680
1723
|
}
|
|
1681
1724
|
}
|
|
1682
|
-
return
|
|
1725
|
+
return false;
|
|
1683
1726
|
};
|
|
1684
1727
|
const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
|
|
1685
|
-
let Ctor = null;
|
|
1686
1728
|
const overridePath = path.join(self.resolveService.OVERRIDE_MODULES_DIR, fileName);
|
|
1687
1729
|
const targetPath = path.join(process.cwd(), "modules", fileName);
|
|
1688
1730
|
const hasOverride = await fs$1
|
|
@@ -1690,212 +1732,29 @@ const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
|
|
|
1690
1732
|
.then(() => true)
|
|
1691
1733
|
.catch(() => false);
|
|
1692
1734
|
const resolvedFile = hasOverride ? overridePath : targetPath;
|
|
1693
|
-
if (
|
|
1694
|
-
return
|
|
1735
|
+
if (REQUIRE_MODULE_FACTORY()) {
|
|
1736
|
+
return true;
|
|
1695
1737
|
}
|
|
1696
|
-
if (
|
|
1697
|
-
return
|
|
1738
|
+
if (await IMPORT_MODULE_FACTORY(resolvedFile)) {
|
|
1739
|
+
return true;
|
|
1698
1740
|
}
|
|
1699
|
-
if (
|
|
1700
|
-
return
|
|
1741
|
+
if (await BABEL_MODULE_FACTORY(resolvedFile, self)) {
|
|
1742
|
+
return true;
|
|
1701
1743
|
}
|
|
1702
|
-
|
|
1744
|
+
console.warn(`Module module import failed for file: ${resolvedFile}`);
|
|
1745
|
+
return false;
|
|
1703
1746
|
};
|
|
1704
1747
|
class ModuleConnectionService {
|
|
1705
1748
|
constructor() {
|
|
1706
1749
|
this.loggerService = inject(TYPES.loggerService);
|
|
1707
1750
|
this.resolveService = inject(TYPES.resolveService);
|
|
1708
1751
|
this.babelService = inject(TYPES.babelService);
|
|
1709
|
-
this.
|
|
1752
|
+
this.loadModule = async (fileName) => {
|
|
1710
1753
|
this.loggerService.log("moduleConnectionService getInstance", {
|
|
1711
1754
|
fileName,
|
|
1712
1755
|
});
|
|
1713
1756
|
return await LOAD_MODULE_MODULE_FN(fileName, this);
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
const LOAD_INSTANCE_FN = singleshot(trycatch(async (self) => {
|
|
1719
|
-
const module = (await self.moduleConnectionService.getInstance("./live.module"));
|
|
1720
|
-
return module;
|
|
1721
|
-
}, { defaultValue: null }));
|
|
1722
|
-
class LiveProviderService {
|
|
1723
|
-
constructor() {
|
|
1724
|
-
this.loggerService = inject(TYPES.loggerService);
|
|
1725
|
-
this.moduleConnectionService = inject(TYPES.moduleConnectionService);
|
|
1726
|
-
this.handleTrailingTake = async (event) => {
|
|
1727
|
-
this.loggerService.log("liveProviderService handleTrailingTake", {
|
|
1728
|
-
event,
|
|
1729
|
-
});
|
|
1730
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1731
|
-
if (instance?.onTrailingTake) {
|
|
1732
|
-
await instance.onTrailingTake(event);
|
|
1733
|
-
}
|
|
1734
|
-
};
|
|
1735
|
-
this.handleTrailingStop = async (event) => {
|
|
1736
|
-
this.loggerService.log("liveProviderService handleTrailingStop", {
|
|
1737
|
-
event,
|
|
1738
|
-
});
|
|
1739
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1740
|
-
if (instance?.onTrailingStop) {
|
|
1741
|
-
await instance.onTrailingStop(event);
|
|
1742
|
-
}
|
|
1743
|
-
};
|
|
1744
|
-
this.handleBreakeven = async (event) => {
|
|
1745
|
-
this.loggerService.log("liveProviderService handleBreakeven", {
|
|
1746
|
-
event,
|
|
1747
|
-
});
|
|
1748
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1749
|
-
if (instance?.onBreakeven) {
|
|
1750
|
-
await instance.onBreakeven(event);
|
|
1751
|
-
}
|
|
1752
1757
|
};
|
|
1753
|
-
this.handlePartialProfit = async (event) => {
|
|
1754
|
-
this.loggerService.log("liveProviderService handlePartialProfit", {
|
|
1755
|
-
event,
|
|
1756
|
-
});
|
|
1757
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1758
|
-
if (instance?.onPartialProfit) {
|
|
1759
|
-
await instance.onPartialProfit(event);
|
|
1760
|
-
}
|
|
1761
|
-
};
|
|
1762
|
-
this.handlePartialLoss = async (event) => {
|
|
1763
|
-
this.loggerService.log("liveProviderService handlePartialLoss", {
|
|
1764
|
-
event,
|
|
1765
|
-
});
|
|
1766
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1767
|
-
if (instance?.onPartialLoss) {
|
|
1768
|
-
await instance.onPartialLoss(event);
|
|
1769
|
-
}
|
|
1770
|
-
};
|
|
1771
|
-
this.handleScheduled = async (event) => {
|
|
1772
|
-
this.loggerService.log("liveProviderService handleScheduled", {
|
|
1773
|
-
event,
|
|
1774
|
-
});
|
|
1775
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1776
|
-
if (instance?.onScheduled) {
|
|
1777
|
-
await instance.onScheduled(event);
|
|
1778
|
-
}
|
|
1779
|
-
};
|
|
1780
|
-
this.handleCancelled = async (event) => {
|
|
1781
|
-
this.loggerService.log("liveProviderService handleCancelled", {
|
|
1782
|
-
event,
|
|
1783
|
-
});
|
|
1784
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1785
|
-
if (instance?.onCancelled) {
|
|
1786
|
-
await instance.onCancelled(event);
|
|
1787
|
-
}
|
|
1788
|
-
};
|
|
1789
|
-
this.handleOpened = async (event) => {
|
|
1790
|
-
this.loggerService.log("liveProviderService handleOpened", {
|
|
1791
|
-
event,
|
|
1792
|
-
});
|
|
1793
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1794
|
-
if (instance?.onOpened) {
|
|
1795
|
-
await instance.onOpened(event);
|
|
1796
|
-
}
|
|
1797
|
-
};
|
|
1798
|
-
this.handleClosed = async (event) => {
|
|
1799
|
-
this.loggerService.log("liveProviderService handleClosed", {
|
|
1800
|
-
event,
|
|
1801
|
-
});
|
|
1802
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1803
|
-
if (instance?.onClosed) {
|
|
1804
|
-
await instance.onClosed(event);
|
|
1805
|
-
}
|
|
1806
|
-
};
|
|
1807
|
-
this.handleRisk = async (event) => {
|
|
1808
|
-
this.loggerService.log("liveProviderService handleClosed", {
|
|
1809
|
-
event,
|
|
1810
|
-
});
|
|
1811
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1812
|
-
if (instance?.onRisk) {
|
|
1813
|
-
await instance.onRisk(event);
|
|
1814
|
-
}
|
|
1815
|
-
};
|
|
1816
|
-
this.handleAverageBuy = async (event) => {
|
|
1817
|
-
this.loggerService.log("liveProviderService handleAverageBuy", {
|
|
1818
|
-
event,
|
|
1819
|
-
});
|
|
1820
|
-
const instance = await LOAD_INSTANCE_FN(this);
|
|
1821
|
-
if (instance?.onAverageBuy) {
|
|
1822
|
-
await instance.onAverageBuy(event);
|
|
1823
|
-
}
|
|
1824
|
-
};
|
|
1825
|
-
this.enable = singleshot(() => {
|
|
1826
|
-
this.loggerService.log("liveProviderService enable");
|
|
1827
|
-
LOAD_INSTANCE_FN(this).then((module) => {
|
|
1828
|
-
if (module) {
|
|
1829
|
-
this.loggerService.log("Live trading initialized successfully with ./modules/live.module.mjs");
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
console.log("No ./modules/live.module.mjs found, live trading failed to initialize");
|
|
1833
|
-
process.exit(-1);
|
|
1834
|
-
});
|
|
1835
|
-
const unRisk = listenRisk(async (event) => {
|
|
1836
|
-
await this.handleRisk(event);
|
|
1837
|
-
});
|
|
1838
|
-
const unSignal = listenSignal(async (event) => {
|
|
1839
|
-
if (event.action === "scheduled") {
|
|
1840
|
-
await this.handleScheduled(event);
|
|
1841
|
-
return;
|
|
1842
|
-
}
|
|
1843
|
-
if (event.action === "cancelled") {
|
|
1844
|
-
await this.handleCancelled(event);
|
|
1845
|
-
return;
|
|
1846
|
-
}
|
|
1847
|
-
if (event.action === "opened") {
|
|
1848
|
-
await this.handleOpened(event);
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
if (event.action === "closed") {
|
|
1852
|
-
await this.handleClosed(event);
|
|
1853
|
-
return;
|
|
1854
|
-
}
|
|
1855
|
-
});
|
|
1856
|
-
const unCommit = listenStrategyCommit(async (event) => {
|
|
1857
|
-
if (event.action === "trailing-take") {
|
|
1858
|
-
await this.handleTrailingTake(event);
|
|
1859
|
-
return;
|
|
1860
|
-
}
|
|
1861
|
-
if (event.action === "trailing-stop") {
|
|
1862
|
-
await this.handleTrailingStop(event);
|
|
1863
|
-
return;
|
|
1864
|
-
}
|
|
1865
|
-
if (event.action === "breakeven") {
|
|
1866
|
-
await this.handleBreakeven(event);
|
|
1867
|
-
return;
|
|
1868
|
-
}
|
|
1869
|
-
if (event.action === "partial-profit") {
|
|
1870
|
-
await this.handlePartialProfit(event);
|
|
1871
|
-
return;
|
|
1872
|
-
}
|
|
1873
|
-
if (event.action === "partial-loss") {
|
|
1874
|
-
await this.handlePartialLoss(event);
|
|
1875
|
-
return;
|
|
1876
|
-
}
|
|
1877
|
-
if (event.action === "average-buy") {
|
|
1878
|
-
await this.handleAverageBuy(event);
|
|
1879
|
-
return;
|
|
1880
|
-
}
|
|
1881
|
-
});
|
|
1882
|
-
const unConnect = () => this.enable.clear();
|
|
1883
|
-
return compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unConnect());
|
|
1884
|
-
});
|
|
1885
|
-
this.disable = () => {
|
|
1886
|
-
this.loggerService.log("liveProviderService disable");
|
|
1887
|
-
if (this.enable.hasValue()) {
|
|
1888
|
-
const lastSubscription = this.enable();
|
|
1889
|
-
lastSubscription();
|
|
1890
|
-
}
|
|
1891
|
-
};
|
|
1892
|
-
this.connect = singleshot(async () => {
|
|
1893
|
-
this.loggerService.log("liveProviderService connect");
|
|
1894
|
-
if (!getArgs().values.live) {
|
|
1895
|
-
return;
|
|
1896
|
-
}
|
|
1897
|
-
return entrySubject.subscribe(this.enable);
|
|
1898
|
-
});
|
|
1899
1758
|
}
|
|
1900
1759
|
}
|
|
1901
1760
|
|
|
@@ -2018,7 +1877,6 @@ globalThis.BacktestKitSignals = BacktestKitSignals;
|
|
|
2018
1877
|
{
|
|
2019
1878
|
provide(TYPES.telegramProviderService, () => new TelegramProviderService());
|
|
2020
1879
|
provide(TYPES.frontendProviderService, () => new FrontendProviderService());
|
|
2021
|
-
provide(TYPES.liveProviderService, () => new LiveProviderService());
|
|
2022
1880
|
}
|
|
2023
1881
|
{
|
|
2024
1882
|
provide(TYPES.telegramWebService, () => new TelegramWebService());
|
|
@@ -2057,7 +1915,6 @@ const schemaServices = {
|
|
|
2057
1915
|
const providerServices = {
|
|
2058
1916
|
frontendProviderService: inject(TYPES.frontendProviderService),
|
|
2059
1917
|
telegramProviderService: inject(TYPES.telegramProviderService),
|
|
2060
|
-
liveProviderService: inject(TYPES.liveProviderService),
|
|
2061
1918
|
};
|
|
2062
1919
|
const webServices = {
|
|
2063
1920
|
telegramWebService: inject(TYPES.telegramWebService),
|
|
@@ -2162,7 +2019,6 @@ const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
|
2162
2019
|
exchangeName,
|
|
2163
2020
|
strategyName,
|
|
2164
2021
|
});
|
|
2165
|
-
listenDoneLive(cli.liveProviderService.disable);
|
|
2166
2022
|
});
|
|
2167
2023
|
const listenGracefulShutdown$2 = singleshot(() => {
|
|
2168
2024
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Zero-boilerplate CLI runner for backtest-kit strategies. Run backtests, paper trading, and live bots with candle cache warming, web dashboard, and Telegram notifications — no setup code required.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Petr Tripolsky",
|
|
@@ -60,11 +60,11 @@
|
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@babel/plugin-transform-modules-umd": "7.27.1",
|
|
62
62
|
"@babel/standalone": "7.29.1",
|
|
63
|
-
"@backtest-kit/ui": "
|
|
64
|
-
"@backtest-kit/graph": "
|
|
65
|
-
"@backtest-kit/ollama": "
|
|
66
|
-
"@backtest-kit/pinets": "
|
|
67
|
-
"@backtest-kit/signals": "
|
|
63
|
+
"@backtest-kit/ui": "5.0.0",
|
|
64
|
+
"@backtest-kit/graph": "5.0.0",
|
|
65
|
+
"@backtest-kit/ollama": "5.0.0",
|
|
66
|
+
"@backtest-kit/pinets": "5.0.0",
|
|
67
|
+
"@backtest-kit/signals": "5.0.0",
|
|
68
68
|
"@rollup/plugin-replace": "6.0.3",
|
|
69
69
|
"@rollup/plugin-typescript": "11.1.6",
|
|
70
70
|
"@types/image-size": "0.7.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@types/mustache": "4.2.6",
|
|
73
73
|
"@types/node": "22.9.0",
|
|
74
74
|
"@types/stack-trace": "0.0.33",
|
|
75
|
-
"backtest-kit": "
|
|
75
|
+
"backtest-kit": "5.0.0",
|
|
76
76
|
"glob": "11.0.1",
|
|
77
77
|
"markdown-it": "14.1.1",
|
|
78
78
|
"rimraf": "6.0.1",
|
|
@@ -87,12 +87,12 @@
|
|
|
87
87
|
"peerDependencies": {
|
|
88
88
|
"@babel/plugin-transform-modules-umd": "^7.27.1",
|
|
89
89
|
"@babel/standalone": "^7.29.1",
|
|
90
|
-
"@backtest-kit/ui": "^
|
|
91
|
-
"@backtest-kit/graph": "^
|
|
92
|
-
"@backtest-kit/ollama": "^
|
|
93
|
-
"@backtest-kit/pinets": "^
|
|
94
|
-
"@backtest-kit/signals": "^
|
|
95
|
-
"backtest-kit": "^
|
|
90
|
+
"@backtest-kit/ui": "^5.0.0",
|
|
91
|
+
"@backtest-kit/graph": "^5.0.0",
|
|
92
|
+
"@backtest-kit/ollama": "^5.0.0",
|
|
93
|
+
"@backtest-kit/pinets": "^5.0.0",
|
|
94
|
+
"@backtest-kit/signals": "^5.0.0",
|
|
95
|
+
"backtest-kit": "^5.0.0",
|
|
96
96
|
"markdown-it": "^14.1.1",
|
|
97
97
|
"typescript": "^5.0.0"
|
|
98
98
|
},
|
|
@@ -5,12 +5,17 @@
|
|
|
5
5
|
**Current:** `{{currentPrice}}`
|
|
6
6
|
**New Avg Entry:** `{{effectivePriceOpen}}`
|
|
7
7
|
**Orig Entry:** `{{originalPriceOpen}}`
|
|
8
|
+
**Cost:** `{{cost}}`
|
|
8
9
|
**DCA Entries:** `{{totalEntries}}`
|
|
10
|
+
**Partials Done:** `{{totalPartials}}`
|
|
9
11
|
**Take Profit:** `{{priceTakeProfit}}`
|
|
10
12
|
**Stop Loss:** `{{priceStopLoss}}`
|
|
13
|
+
**Orig TP:** `{{originalPriceTakeProfit}}`
|
|
14
|
+
**Orig SL:** `{{originalPriceStopLoss}}`
|
|
15
|
+
**PnL:** {{pnl.pnlPercentage}}% ({{pnl.pnlCost}} / {{pnl.pnlEntries}})
|
|
11
16
|
**Signal ID:** `{{signalId}}`
|
|
12
17
|
**Time:** `{{timestamp}}`
|
|
13
18
|
|
|
14
19
|
{{#backtest}}
|
|
15
20
|
_🧪 Backtest_
|
|
16
|
-
{{/backtest}}
|
|
21
|
+
{{/backtest}}
|
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
**Current:** `{{currentPrice}}`
|
|
6
6
|
**Entry:** `{{priceOpen}}`
|
|
7
|
-
**Take Profit:** `{{priceTakeProfit}}`
|
|
8
|
-
**Stop Loss:** `{{priceStopLoss}}`
|
|
9
7
|
**Orig Entry:** `{{originalPriceOpen}}`
|
|
10
8
|
**DCA Entries:** `{{totalEntries}}`
|
|
9
|
+
**Partials Done:** `{{totalPartials}}`
|
|
10
|
+
**Take Profit:** `{{priceTakeProfit}}`
|
|
11
|
+
**Stop Loss:** `{{priceStopLoss}}`
|
|
12
|
+
**Orig TP:** `{{originalPriceTakeProfit}}`
|
|
13
|
+
**Orig SL:** `{{originalPriceStopLoss}}`
|
|
14
|
+
**PnL:** {{pnl.pnlPercentage}}% ({{pnl.pnlCost}} / {{pnl.pnlEntries}})
|
|
11
15
|
**Signal ID:** `{{signalId}}`
|
|
12
16
|
**Time:** `{{timestamp}}`
|
|
13
17
|
|
|
14
18
|
{{#backtest}}
|
|
15
19
|
_🧪 Backtest_
|
|
16
|
-
{{/backtest}}
|
|
20
|
+
{{/backtest}}
|
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
**Entry:** `{{signal.priceOpen}}`
|
|
7
7
|
**Current:** `{{currentPrice}}`
|
|
8
8
|
**Orig Entry:** `{{signal.originalPriceOpen}}`
|
|
9
|
+
**Orig TP:** `{{signal.originalPriceTakeProfit}}`
|
|
10
|
+
**Orig SL:** `{{signal.originalPriceStopLoss}}`
|
|
9
11
|
**DCA Entries:** `{{signal.totalEntries}}`
|
|
12
|
+
**Partials Done:** `{{signal.totalPartials}}`
|
|
13
|
+
**Partial Executed:** {{signal.partialExecuted}}%
|
|
10
14
|
**Signal ID:** `{{signal.id}}`
|
|
11
15
|
{{#cancelId}}**Cancel ID:** `{{cancelId}}`
|
|
12
16
|
{{/cancelId}}**Time:** `{{createdAt}}`
|
|
13
17
|
|
|
14
18
|
{{#backtest}}
|
|
15
19
|
_🧪 Backtest_
|
|
16
|
-
{{/backtest}}
|
|
20
|
+
{{/backtest}}
|
package/template/closed.mustache
CHANGED
|
@@ -3,15 +3,20 @@
|
|
|
3
3
|
**Symbol:** `{{symbol}}` ({{signal.position}})
|
|
4
4
|
|
|
5
5
|
**Reason:** `{{closeReason}}`
|
|
6
|
+
**Current:** `{{currentPrice}}`
|
|
6
7
|
**Entry:** `{{pnl.priceOpen}}`
|
|
7
8
|
**Exit:** `{{pnl.priceClose}}`
|
|
8
|
-
**PnL:** {{pnl.pnlPercentage}}%
|
|
9
|
+
**PnL:** {{pnl.pnlPercentage}}% ({{pnl.pnlCost}} / {{pnl.pnlEntries}})
|
|
9
10
|
**Orig Entry:** `{{signal.originalPriceOpen}}`
|
|
11
|
+
**Orig TP:** `{{signal.originalPriceTakeProfit}}`
|
|
12
|
+
**Orig SL:** `{{signal.originalPriceStopLoss}}`
|
|
10
13
|
**DCA Entries:** `{{signal.totalEntries}}`
|
|
14
|
+
**Partials Done:** `{{signal.totalPartials}}`
|
|
15
|
+
**Partial Executed:** {{signal.partialExecuted}}%
|
|
11
16
|
**Signal ID:** `{{signal.id}}`
|
|
12
17
|
{{#closeId}}**Close ID:** `{{closeId}}`
|
|
13
18
|
{{/closeId}}**Time:** `{{createdAt}}`
|
|
14
19
|
|
|
15
20
|
{{#backtest}}
|
|
16
21
|
_🧪 Backtest_
|
|
17
|
-
{{/backtest}}
|
|
22
|
+
{{/backtest}}
|
package/template/opened.mustache
CHANGED
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
**Take Profit:** `{{signal.priceTakeProfit}}`
|
|
8
8
|
**Stop Loss:** `{{signal.priceStopLoss}}`
|
|
9
9
|
**Orig Entry:** `{{signal.originalPriceOpen}}`
|
|
10
|
+
**Orig TP:** `{{signal.originalPriceTakeProfit}}`
|
|
11
|
+
**Orig SL:** `{{signal.originalPriceStopLoss}}`
|
|
12
|
+
**Cost:** `{{signal.cost}}`
|
|
10
13
|
**DCA Entries:** `{{signal.totalEntries}}`
|
|
14
|
+
**Partials Done:** `{{signal.totalPartials}}`
|
|
11
15
|
**TTL:** {{signal.minuteEstimatedTime}} min
|
|
12
16
|
**Signal ID:** `{{signal.id}}`
|
|
13
17
|
**Time:** `{{createdAt}}`
|
|
14
18
|
|
|
15
19
|
{{#backtest}}
|
|
16
20
|
_🧪 Backtest_
|
|
17
|
-
{{/backtest}}
|
|
21
|
+
{{/backtest}}
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
**Current:** `{{currentPrice}}`
|
|
6
6
|
**Entry:** `{{priceOpen}}`
|
|
7
|
+
**Orig Entry:** `{{originalPriceOpen}}`
|
|
7
8
|
**Closed:** {{percentToClose}}%
|
|
8
9
|
**Take Profit:** `{{priceTakeProfit}}`
|
|
9
10
|
**Stop Loss:** `{{priceStopLoss}}`
|
|
10
|
-
**Orig
|
|
11
|
+
**Orig TP:** `{{originalPriceTakeProfit}}`
|
|
12
|
+
**Orig SL:** `{{originalPriceStopLoss}}`
|
|
11
13
|
**DCA Entries:** `{{totalEntries}}`
|
|
14
|
+
**Partials Done:** `{{totalPartials}}`
|
|
15
|
+
**PnL:** {{pnl.pnlPercentage}}% ({{pnl.pnlCost}} / {{pnl.pnlEntries}})
|
|
12
16
|
**Signal ID:** `{{signalId}}`
|
|
13
17
|
**Time:** `{{timestamp}}`
|
|
14
18
|
|
|
15
19
|
{{#backtest}}
|
|
16
20
|
_🧪 Backtest_
|
|
17
|
-
{{/backtest}}
|
|
21
|
+
{{/backtest}}
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
**Current:** `{{currentPrice}}`
|
|
6
6
|
**Entry:** `{{priceOpen}}`
|
|
7
|
+
**Orig Entry:** `{{originalPriceOpen}}`
|
|
7
8
|
**Closed:** {{percentToClose}}%
|
|
8
9
|
**Take Profit:** `{{priceTakeProfit}}`
|
|
9
10
|
**Stop Loss:** `{{priceStopLoss}}`
|
|
10
|
-
**Orig
|
|
11
|
+
**Orig TP:** `{{originalPriceTakeProfit}}`
|
|
12
|
+
**Orig SL:** `{{originalPriceStopLoss}}`
|
|
11
13
|
**DCA Entries:** `{{totalEntries}}`
|
|
14
|
+
**Partials Done:** `{{totalPartials}}`
|
|
15
|
+
**PnL:** {{pnl.pnlPercentage}}% ({{pnl.pnlCost}} / {{pnl.pnlEntries}})
|
|
12
16
|
**Signal ID:** `{{signalId}}`
|
|
13
17
|
**Time:** `{{timestamp}}`
|
|
14
18
|
|
|
15
19
|
{{#backtest}}
|
|
16
20
|
_🧪 Backtest_
|
|
17
|
-
{{/backtest}}
|
|
21
|
+
{{/backtest}}
|
package/template/risk.mustache
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
**Entry:** `{{currentSignal.priceOpen}}`
|
|
7
7
|
**Take Profit:** `{{currentSignal.priceTakeProfit}}`
|
|
8
8
|
**Stop Loss:** `{{currentSignal.priceStopLoss}}`
|
|
9
|
-
**
|
|
10
|
-
**
|
|
11
|
-
**
|
|
12
|
-
{{#rejectionId}}**Rejection ID:** `{{rejectionId}}`
|
|
9
|
+
**TTL:** {{currentSignal.minuteEstimatedTime}} min
|
|
10
|
+
**Active Positions:** {{activePositionCount}}
|
|
11
|
+
{{#currentSignal.note}}**Note:** {{currentSignal.note}}
|
|
12
|
+
{{/currentSignal.note}}{{#rejectionId}}**Rejection ID:** `{{rejectionId}}`
|
|
13
13
|
{{/rejectionId}}**Time:** `{{timestamp}}`
|
|
14
14
|
|
|
15
15
|
**Reason:**
|
|
@@ -17,4 +17,4 @@
|
|
|
17
17
|
|
|
18
18
|
{{#backtest}}
|
|
19
19
|
_🧪 Backtest_
|
|
20
|
-
{{/backtest}}
|
|
20
|
+
{{/backtest}}
|
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
**Take Profit:** `{{signal.priceTakeProfit}}`
|
|
8
8
|
**Stop Loss:** `{{signal.priceStopLoss}}`
|
|
9
9
|
**Orig Entry:** `{{signal.originalPriceOpen}}`
|
|
10
|
+
**Orig TP:** `{{signal.originalPriceTakeProfit}}`
|
|
11
|
+
**Orig SL:** `{{signal.originalPriceStopLoss}}`
|
|
12
|
+
**Cost:** `{{signal.cost}}`
|
|
10
13
|
**DCA Entries:** `{{signal.totalEntries}}`
|
|
14
|
+
**Partials Done:** `{{signal.totalPartials}}`
|
|
11
15
|
**TTL:** {{signal.minuteEstimatedTime}} min
|
|
12
16
|
**Signal ID:** `{{signal.id}}`
|
|
13
17
|
**Time:** `{{createdAt}}`
|
|
14
18
|
|
|
15
19
|
{{#backtest}}
|
|
16
20
|
_🧪 Backtest_
|
|
17
|
-
{{/backtest}}
|
|
21
|
+
{{/backtest}}
|