@tradejs/node 1.0.6 → 1.0.8
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/dist/ai.js +274 -126
- package/dist/ai.mjs +3 -3
- package/dist/backtest.js +345 -42
- package/dist/backtest.mjs +98 -16
- package/dist/chunk-2JKX3DM7.mjs +619 -0
- package/dist/{chunk-XW5L327F.mjs → chunk-JMDYEKIO.mjs} +1 -1
- package/dist/chunk-JRRG3YQG.mjs +154 -0
- package/dist/{chunk-CGJ2UU6H.mjs → chunk-JU77QVJ3.mjs} +8 -1
- package/dist/{chunk-SCMBUEGK.mjs → chunk-KMJQQ53K.mjs} +1 -1
- package/dist/{chunk-GKDBAF3A.mjs → chunk-KZDHZ56N.mjs} +25 -7
- package/dist/{chunk-EOZSJKUM.mjs → chunk-WGOYR6AB.mjs} +1 -1
- package/dist/cli.d.mts +20 -2
- package/dist/cli.d.ts +20 -2
- package/dist/cli.js +456 -183
- package/dist/cli.mjs +155 -49
- package/dist/connectors.js +6 -1
- package/dist/connectors.mjs +2 -2
- package/dist/constants.js +1 -1
- package/dist/constants.mjs +1 -1
- package/dist/registry.js +6 -1
- package/dist/registry.mjs +2 -2
- package/dist/strategies.d.mts +24 -9
- package/dist/strategies.d.ts +24 -9
- package/dist/strategies.js +7465 -6467
- package/dist/strategies.mjs +865 -140
- package/package.json +6 -6
- package/dist/chunk-72FKXJ2I.mjs +0 -473
- package/dist/chunk-PQH5PAFC.mjs +0 -49
package/dist/backtest.mjs
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BUILTIN_CONNECTOR_NAMES,
|
|
3
3
|
getConnectorCreatorByName
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JMDYEKIO.mjs";
|
|
5
5
|
import {
|
|
6
|
-
buildMlPayload
|
|
7
|
-
|
|
6
|
+
buildMlPayload,
|
|
7
|
+
enrichSignalWithDerivativesContext
|
|
8
|
+
} from "./chunk-JRRG3YQG.mjs";
|
|
8
9
|
import {
|
|
9
10
|
buildAiPayload
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2JKX3DM7.mjs";
|
|
11
12
|
import {
|
|
12
13
|
getStrategyCreator
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WGOYR6AB.mjs";
|
|
14
15
|
import {
|
|
15
16
|
getTradejsProjectCwd
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-JU77QVJ3.mjs";
|
|
17
18
|
import "./chunk-6DZX6EAA.mjs";
|
|
18
19
|
|
|
19
20
|
// src/backtest.ts
|
|
@@ -21,8 +22,7 @@ export * from "@tradejs/core/backtest";
|
|
|
21
22
|
|
|
22
23
|
// src/testing.ts
|
|
23
24
|
import { alignSortedCandlesByTimestamp } from "@tradejs/core/indicators";
|
|
24
|
-
import {
|
|
25
|
-
import { getTimestamp } from "@tradejs/core/time";
|
|
25
|
+
import { getBacktestPreloadStart } from "@tradejs/core/time";
|
|
26
26
|
import { appendAiDatasetRow } from "@tradejs/infra/ai";
|
|
27
27
|
import {
|
|
28
28
|
appendMlDatasetRow,
|
|
@@ -92,6 +92,7 @@ var createTestConnector = (connector, context) => {
|
|
|
92
92
|
currentPositionProfit = 0;
|
|
93
93
|
};
|
|
94
94
|
return {
|
|
95
|
+
__tradejsTestConnector: true,
|
|
95
96
|
getState: async () => state,
|
|
96
97
|
setState: async (newState) => {
|
|
97
98
|
state = {
|
|
@@ -114,6 +115,24 @@ var createTestConnector = (connector, context) => {
|
|
|
114
115
|
};
|
|
115
116
|
},
|
|
116
117
|
getPosition: async () => currentPosition || null,
|
|
118
|
+
getOpenPositionPnl: async () => {
|
|
119
|
+
if (typeof connector.getOpenPositionPnl === "function") {
|
|
120
|
+
return connector.getOpenPositionPnl();
|
|
121
|
+
}
|
|
122
|
+
if (!currentPosition) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
return [
|
|
126
|
+
{
|
|
127
|
+
symbol: currentPosition.symbol,
|
|
128
|
+
qty: currentPosition.qty,
|
|
129
|
+
price: currentPosition.price,
|
|
130
|
+
currentPrice: currentPosition.price,
|
|
131
|
+
unrealizedPnl: 0,
|
|
132
|
+
direction: currentPosition.direction
|
|
133
|
+
}
|
|
134
|
+
];
|
|
135
|
+
},
|
|
117
136
|
checkTp: async (candle) => {
|
|
118
137
|
if (!candle || !currentPosition || !currentPosition.qty) {
|
|
119
138
|
return;
|
|
@@ -231,7 +250,6 @@ var createTestConnector = (connector, context) => {
|
|
|
231
250
|
};
|
|
232
251
|
|
|
233
252
|
// src/testing.ts
|
|
234
|
-
var preloadStart = getTimestamp(PRELOAD_DAYS);
|
|
235
253
|
var createTestingKlineCacheState = () => ({
|
|
236
254
|
coinKlineCache: /* @__PURE__ */ new Map(),
|
|
237
255
|
btcKlineCache: /* @__PURE__ */ new Map(),
|
|
@@ -254,7 +272,15 @@ var getTestingKlineCacheState = (cwd = getTradejsProjectCwd()) => {
|
|
|
254
272
|
};
|
|
255
273
|
};
|
|
256
274
|
var getKlineCacheKey = (params) => {
|
|
257
|
-
const {
|
|
275
|
+
const {
|
|
276
|
+
userName,
|
|
277
|
+
connectorName,
|
|
278
|
+
symbol,
|
|
279
|
+
preloadStart,
|
|
280
|
+
end,
|
|
281
|
+
interval,
|
|
282
|
+
cacheOnly
|
|
283
|
+
} = params;
|
|
258
284
|
return [
|
|
259
285
|
userName,
|
|
260
286
|
connectorName,
|
|
@@ -270,6 +296,7 @@ var getPreparedDataCacheKey = (params) => {
|
|
|
270
296
|
userName,
|
|
271
297
|
connectorName,
|
|
272
298
|
symbol,
|
|
299
|
+
preloadStart,
|
|
273
300
|
start,
|
|
274
301
|
end,
|
|
275
302
|
interval,
|
|
@@ -280,6 +307,7 @@ var getPreparedDataCacheKey = (params) => {
|
|
|
280
307
|
userName,
|
|
281
308
|
connectorName,
|
|
282
309
|
symbol,
|
|
310
|
+
preloadStart,
|
|
283
311
|
start,
|
|
284
312
|
end,
|
|
285
313
|
interval,
|
|
@@ -288,7 +316,7 @@ var getPreparedDataCacheKey = (params) => {
|
|
|
288
316
|
].join(":");
|
|
289
317
|
};
|
|
290
318
|
var getConnectorCacheKey = (params) => [params.userName, params.connectorName].join(":");
|
|
291
|
-
var splitCandlesForTesting = (candles, start) => {
|
|
319
|
+
var splitCandlesForTesting = (candles, start, preloadStart) => {
|
|
292
320
|
const prevData = [];
|
|
293
321
|
const testData = [];
|
|
294
322
|
for (const candle of candles) {
|
|
@@ -349,6 +377,7 @@ var testing = async ({
|
|
|
349
377
|
if (!start) {
|
|
350
378
|
throw new Error("no start");
|
|
351
379
|
}
|
|
380
|
+
const preloadStart = getBacktestPreloadStart(start);
|
|
352
381
|
const startedAt = Date.now();
|
|
353
382
|
const formatTimeoutMessage = (stage) => `Test ${name} (${symbol}) timed out after ${timeoutMs}ms during ${stage}`;
|
|
354
383
|
const getRemainingTimeoutMs = (stage) => {
|
|
@@ -435,6 +464,7 @@ var testing = async ({
|
|
|
435
464
|
userName,
|
|
436
465
|
connectorName,
|
|
437
466
|
symbol,
|
|
467
|
+
preloadStart,
|
|
438
468
|
end,
|
|
439
469
|
interval,
|
|
440
470
|
cacheOnly
|
|
@@ -443,6 +473,7 @@ var testing = async ({
|
|
|
443
473
|
userName,
|
|
444
474
|
connectorName,
|
|
445
475
|
symbol: "BTCUSDT",
|
|
476
|
+
preloadStart,
|
|
446
477
|
end,
|
|
447
478
|
interval,
|
|
448
479
|
cacheOnly
|
|
@@ -455,6 +486,7 @@ var testing = async ({
|
|
|
455
486
|
userName,
|
|
456
487
|
connectorName: btcBinanceConnectorName,
|
|
457
488
|
symbol: "BTCUSDT",
|
|
489
|
+
preloadStart,
|
|
458
490
|
end,
|
|
459
491
|
interval,
|
|
460
492
|
cacheOnly
|
|
@@ -463,6 +495,7 @@ var testing = async ({
|
|
|
463
495
|
userName,
|
|
464
496
|
connectorName: btcCoinbaseConnectorName,
|
|
465
497
|
symbol: "BTCUSDT",
|
|
498
|
+
preloadStart,
|
|
466
499
|
end,
|
|
467
500
|
interval,
|
|
468
501
|
cacheOnly
|
|
@@ -473,6 +506,7 @@ var testing = async ({
|
|
|
473
506
|
userName,
|
|
474
507
|
connectorName,
|
|
475
508
|
symbol,
|
|
509
|
+
preloadStart,
|
|
476
510
|
start,
|
|
477
511
|
end,
|
|
478
512
|
interval,
|
|
@@ -530,15 +564,17 @@ var testing = async ({
|
|
|
530
564
|
if (!cachedBtcCoinbaseData) {
|
|
531
565
|
state.btcCoinbaseKlineCache.set(btcCoinbaseCacheKey, btcCoinbaseData);
|
|
532
566
|
}
|
|
533
|
-
const { prevData: prevDataRaw, testData: testDataRaw } = splitCandlesForTesting(data, start);
|
|
534
|
-
const { prevData: btcPrevDataRaw, testData: btcTestDataRaw } = splitCandlesForTesting(btcData, start);
|
|
567
|
+
const { prevData: prevDataRaw, testData: testDataRaw } = splitCandlesForTesting(data, start, preloadStart);
|
|
568
|
+
const { prevData: btcPrevDataRaw, testData: btcTestDataRaw } = splitCandlesForTesting(btcData, start, preloadStart);
|
|
535
569
|
const { prevData: btcBinancePrevDataRaw } = splitCandlesForTesting(
|
|
536
570
|
btcBinanceData,
|
|
537
|
-
start
|
|
571
|
+
start,
|
|
572
|
+
preloadStart
|
|
538
573
|
);
|
|
539
574
|
const { prevData: btcCoinbasePrevDataRaw } = splitCandlesForTesting(
|
|
540
575
|
btcCoinbaseData,
|
|
541
|
-
start
|
|
576
|
+
start,
|
|
577
|
+
preloadStart
|
|
542
578
|
);
|
|
543
579
|
const { alignedCoinCandles: prevData2, alignedBtcCandles: btcPrevData2 } = alignSortedCandlesByTimestamp(prevDataRaw, btcPrevDataRaw);
|
|
544
580
|
const { alignedCoinCandles: testData2, alignedBtcCandles: btcTestData2 } = alignSortedCandlesByTimestamp(testDataRaw, btcTestDataRaw);
|
|
@@ -585,6 +621,7 @@ var testing = async ({
|
|
|
585
621
|
);
|
|
586
622
|
const pendingMlPayloadBySignalId = /* @__PURE__ */ new Map();
|
|
587
623
|
const pendingAiRowBySignalId = /* @__PURE__ */ new Map();
|
|
624
|
+
const replaySignalEvaluations = [];
|
|
588
625
|
const flushClosedResultsBatch = async () => {
|
|
589
626
|
if (!ml && !ai) return;
|
|
590
627
|
const batch = await testConnector.drainMlResultsBatch();
|
|
@@ -629,6 +666,47 @@ var testing = async ({
|
|
|
629
666
|
"strategy signal",
|
|
630
667
|
strategy(candle, btcCandle)
|
|
631
668
|
);
|
|
669
|
+
if (!signal || typeof signal === "string") {
|
|
670
|
+
replaySignalEvaluations.push({
|
|
671
|
+
evaluationId: `${testId}:${strategyName}:${symbol}:${candle.timestamp}`,
|
|
672
|
+
userName,
|
|
673
|
+
strategy: strategyName,
|
|
674
|
+
symbol,
|
|
675
|
+
interval,
|
|
676
|
+
timestamp: candle.timestamp,
|
|
677
|
+
evaluatedAt: candle.timestamp,
|
|
678
|
+
status: "skip",
|
|
679
|
+
reason: typeof signal === "string" && signal.trim() ? signal : "NO_SIGNAL"
|
|
680
|
+
});
|
|
681
|
+
} else {
|
|
682
|
+
replaySignalEvaluations.push({
|
|
683
|
+
evaluationId: `${signal.signalId || testId}:${strategyName}:${symbol}:${signal.timestamp || candle.timestamp}`,
|
|
684
|
+
userName,
|
|
685
|
+
strategy: signal.strategy || strategyName,
|
|
686
|
+
symbol: signal.symbol || symbol,
|
|
687
|
+
interval: signal.interval || interval,
|
|
688
|
+
timestamp: typeof signal.timestamp === "number" && Number.isFinite(signal.timestamp) ? signal.timestamp : candle.timestamp,
|
|
689
|
+
evaluatedAt: candle.timestamp,
|
|
690
|
+
status: "signal",
|
|
691
|
+
reason: signal.orderSkipReason || signal.orderStatus,
|
|
692
|
+
signalId: signal.signalId,
|
|
693
|
+
direction: signal.direction,
|
|
694
|
+
orderStatus: signal.orderStatus,
|
|
695
|
+
orderSkipReason: signal.orderSkipReason,
|
|
696
|
+
aiAnalysis: signal.aiAnalysis ?? null,
|
|
697
|
+
ml: signal.ml
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
const shouldCapturePayload = signal && typeof signal !== "string" && signal.signalId && (ml || ai);
|
|
701
|
+
if (shouldCapturePayload) {
|
|
702
|
+
await withTimeout(
|
|
703
|
+
"derivatives context",
|
|
704
|
+
enrichSignalWithDerivativesContext({
|
|
705
|
+
signal,
|
|
706
|
+
env: "BACKTEST"
|
|
707
|
+
})
|
|
708
|
+
);
|
|
709
|
+
}
|
|
632
710
|
if (ml && signal && typeof signal !== "string" && signal.signalId) {
|
|
633
711
|
const payload = buildMlPayload({
|
|
634
712
|
signal,
|
|
@@ -661,7 +739,11 @@ var testing = async ({
|
|
|
661
739
|
}
|
|
662
740
|
}
|
|
663
741
|
await withTimeout("flush closed results", flushClosedResultsBatch());
|
|
664
|
-
|
|
742
|
+
const result = await withTimeout("collect result", testConnector.getResult());
|
|
743
|
+
return {
|
|
744
|
+
...result,
|
|
745
|
+
inlineReplaySignalEvaluations: replaySignalEvaluations
|
|
746
|
+
};
|
|
665
747
|
};
|
|
666
748
|
export {
|
|
667
749
|
createTestConnector,
|