@tradejs/core 1.0.5 → 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/backtest.d.mts +1 -1
- package/dist/backtest.d.ts +1 -1
- package/dist/backtest.js +5 -5
- package/dist/backtest.mjs +5 -5
- package/dist/{chunk-4F73AYK6.mjs → chunk-622V7IAT.mjs} +253 -12
- package/dist/{chunk-NQ7D3T4E.mjs → chunk-AJK4NS7Y.mjs} +2 -2
- package/dist/{chunk-JG2QPVAV.mjs → chunk-JLORHLL6.mjs} +12 -1
- package/dist/{chunk-PXLXXXLA.mjs → chunk-PQETJ42A.mjs} +6 -2
- package/dist/config.d.mts +49 -2
- package/dist/config.d.ts +49 -2
- package/dist/config.js +40 -3
- package/dist/config.mjs +37 -2
- package/dist/constants.d.mts +6 -2
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +16 -1
- package/dist/constants.mjs +9 -1
- package/dist/indicators.d.mts +11 -2
- package/dist/indicators.d.ts +11 -2
- package/dist/indicators.js +252 -10
- package/dist/indicators.mjs +5 -3
- package/dist/strategies.d.mts +2 -0
- package/dist/strategies.d.ts +2 -0
- package/dist/strategies.js +72 -27
- package/dist/strategies.mjs +54 -21
- package/dist/{time-DEyFa2vI.d.mts → time-BMkFD4Kd.d.mts} +2 -1
- package/dist/{time-DEyFa2vI.d.ts → time-BMkFD4Kd.d.ts} +2 -1
- package/dist/time.d.mts +1 -1
- package/dist/time.d.ts +1 -1
- package/dist/time.js +9 -0
- package/dist/time.mjs +4 -2
- package/package.json +4 -5
package/dist/indicators.js
CHANGED
|
@@ -33,6 +33,7 @@ __export(indicators_exports, {
|
|
|
33
33
|
alignSortedCandlesByTimestamp: () => alignSortedCandlesByTimestamp,
|
|
34
34
|
alignSpreadRows: () => alignSpreadRows,
|
|
35
35
|
applyIndicatorsToHistory: () => applyIndicatorsToHistory,
|
|
36
|
+
buildDerivativesContext: () => buildDerivativesContext,
|
|
36
37
|
buildMlCandleIndicators: () => buildMlCandleIndicators,
|
|
37
38
|
buildMlTimeframeIndicators: () => buildMlTimeframeIndicators,
|
|
38
39
|
buildReturnsFromCandles: () => buildReturnsFromCandles,
|
|
@@ -264,6 +265,235 @@ var coinalyzePointsToRows = (points, interval, source) => points.map((point) =>
|
|
|
264
265
|
source
|
|
265
266
|
}));
|
|
266
267
|
|
|
268
|
+
// src/utils/derivativesContext.ts
|
|
269
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
270
|
+
var DEFAULT_STALE_AFTER_MS = {
|
|
271
|
+
"15m": 45 * 60 * 1e3,
|
|
272
|
+
"1h": 3 * HOUR_MS
|
|
273
|
+
};
|
|
274
|
+
var DERIVATIVES_INTERVALS = ["15m", "1h"];
|
|
275
|
+
var toFiniteNumberOrNull = (value) => {
|
|
276
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
277
|
+
if (typeof value === "string" && value.trim()) {
|
|
278
|
+
const parsed = Number(value);
|
|
279
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
};
|
|
283
|
+
var toTimestampMs = (value) => {
|
|
284
|
+
if (value instanceof Date) {
|
|
285
|
+
const time = value.getTime();
|
|
286
|
+
return Number.isFinite(time) ? time : null;
|
|
287
|
+
}
|
|
288
|
+
const num = toFiniteNumberOrNull(value);
|
|
289
|
+
if (num == null) return null;
|
|
290
|
+
return num > 1e10 ? Math.floor(num) : Math.floor(num * 1e3);
|
|
291
|
+
};
|
|
292
|
+
var roundNullable = (value, digits = 6) => {
|
|
293
|
+
if (value == null || !Number.isFinite(value)) return null;
|
|
294
|
+
const multiplier = 10 ** digits;
|
|
295
|
+
return Math.round(value * multiplier) / multiplier;
|
|
296
|
+
};
|
|
297
|
+
var pctChange = (current, previous) => {
|
|
298
|
+
if (current == null || previous == null || !Number.isFinite(current) || !Number.isFinite(previous) || previous === 0) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
return (current - previous) / Math.abs(previous) * 100;
|
|
302
|
+
};
|
|
303
|
+
var normalizeRows = (rows, timestamp) => (rows ?? []).map((row) => ({
|
|
304
|
+
...row,
|
|
305
|
+
tsMs: toTimestampMs(row.ts),
|
|
306
|
+
openInterest: toFiniteNumberOrNull(row.openInterest),
|
|
307
|
+
fundingRate: toFiniteNumberOrNull(row.fundingRate),
|
|
308
|
+
liqLong: toFiniteNumberOrNull(row.liqLong),
|
|
309
|
+
liqShort: toFiniteNumberOrNull(row.liqShort),
|
|
310
|
+
liqTotal: toFiniteNumberOrNull(row.liqTotal)
|
|
311
|
+
})).filter((row) => {
|
|
312
|
+
return row.tsMs != null && row.tsMs <= timestamp;
|
|
313
|
+
}).sort((a, b) => a.tsMs - b.tsMs);
|
|
314
|
+
var findRowAtOrBefore = (rows, targetTs) => {
|
|
315
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
316
|
+
if (rows[i].tsMs <= targetTs) {
|
|
317
|
+
return rows[i];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return null;
|
|
321
|
+
};
|
|
322
|
+
var calculateZScore = (values, current) => {
|
|
323
|
+
const finite = values.filter(
|
|
324
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
325
|
+
);
|
|
326
|
+
if (current == null || finite.length < 3) return null;
|
|
327
|
+
const mean = finite.reduce((sum, value) => sum + value, 0) / finite.length;
|
|
328
|
+
const variance = finite.reduce((sum, value) => sum + (value - mean) ** 2, 0) / finite.length;
|
|
329
|
+
const std = Math.sqrt(variance);
|
|
330
|
+
if (!Number.isFinite(std) || std === 0) return 0;
|
|
331
|
+
return (current - mean) / std;
|
|
332
|
+
};
|
|
333
|
+
var calculateAverage = (values) => {
|
|
334
|
+
const finite = values.filter(
|
|
335
|
+
(value) => typeof value === "number" && Number.isFinite(value)
|
|
336
|
+
);
|
|
337
|
+
if (!finite.length) return null;
|
|
338
|
+
return finite.reduce((sum, value) => sum + value, 0) / finite.length;
|
|
339
|
+
};
|
|
340
|
+
var buildIntervalContext = (params) => {
|
|
341
|
+
const { interval, rows, timestamp, staleAfterMs } = params;
|
|
342
|
+
const normalizedRows = normalizeRows(rows, timestamp);
|
|
343
|
+
const latest = normalizedRows[normalizedRows.length - 1];
|
|
344
|
+
if (!latest) return null;
|
|
345
|
+
const openInterest = latest.openInterest;
|
|
346
|
+
const row1h = findRowAtOrBefore(normalizedRows, latest.tsMs - HOUR_MS);
|
|
347
|
+
const row4h = findRowAtOrBefore(normalizedRows, latest.tsMs - 4 * HOUR_MS);
|
|
348
|
+
const row24h = findRowAtOrBefore(normalizedRows, latest.tsMs - 24 * HOUR_MS);
|
|
349
|
+
const liqLong = latest.liqLong;
|
|
350
|
+
const liqShort = latest.liqShort;
|
|
351
|
+
const liqTotal = latest.liqTotal ?? (liqLong ?? 0) + (liqShort ?? 0);
|
|
352
|
+
const previousLiquidations = normalizedRows.slice(0, -1).map((row) => row.liqTotal ?? (row.liqLong ?? 0) + (row.liqShort ?? 0));
|
|
353
|
+
const avgPreviousLiquidations = calculateAverage(previousLiquidations);
|
|
354
|
+
const liqSpikeRatio = liqTotal != null && avgPreviousLiquidations != null && avgPreviousLiquidations > 0 ? liqTotal / avgPreviousLiquidations : null;
|
|
355
|
+
const liqImbalance = liqTotal != null && liqTotal > 0 ? ((liqShort ?? 0) - (liqLong ?? 0)) / liqTotal : null;
|
|
356
|
+
return {
|
|
357
|
+
interval,
|
|
358
|
+
asOfTs: latest.tsMs,
|
|
359
|
+
stale: timestamp - latest.tsMs > staleAfterMs,
|
|
360
|
+
points: normalizedRows.length,
|
|
361
|
+
openInterest: roundNullable(openInterest),
|
|
362
|
+
oiChangePct1h: roundNullable(
|
|
363
|
+
pctChange(openInterest, row1h?.openInterest ?? null),
|
|
364
|
+
4
|
|
365
|
+
),
|
|
366
|
+
oiChangePct4h: roundNullable(
|
|
367
|
+
pctChange(openInterest, row4h?.openInterest ?? null),
|
|
368
|
+
4
|
|
369
|
+
),
|
|
370
|
+
oiChangePct24h: roundNullable(
|
|
371
|
+
pctChange(openInterest, row24h?.openInterest ?? null),
|
|
372
|
+
4
|
|
373
|
+
),
|
|
374
|
+
fundingRate: roundNullable(latest.fundingRate, 8),
|
|
375
|
+
fundingZScore: roundNullable(
|
|
376
|
+
calculateZScore(
|
|
377
|
+
normalizedRows.map((row) => row.fundingRate),
|
|
378
|
+
latest.fundingRate
|
|
379
|
+
),
|
|
380
|
+
4
|
|
381
|
+
),
|
|
382
|
+
liqLong: roundNullable(liqLong),
|
|
383
|
+
liqShort: roundNullable(liqShort),
|
|
384
|
+
liqTotal: roundNullable(liqTotal),
|
|
385
|
+
liqImbalance: roundNullable(liqImbalance, 4),
|
|
386
|
+
liqSpikeRatio: roundNullable(liqSpikeRatio, 4)
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
var getPrimaryContext = (intervals) => intervals["15m"] ?? intervals["1h"] ?? null;
|
|
390
|
+
var isCrowdedLong = (context) => context.fundingRate != null && context.fundingRate >= 5e-4 || context.fundingZScore != null && context.fundingZScore >= 1.5;
|
|
391
|
+
var isCrowdedShort = (context) => context.fundingRate != null && context.fundingRate <= -5e-4 || context.fundingZScore != null && context.fundingZScore <= -1.5;
|
|
392
|
+
var hasLiquidationSpike = (context) => context.liqSpikeRatio != null && context.liqSpikeRatio >= 2;
|
|
393
|
+
var detectPressure = (context) => {
|
|
394
|
+
if (!context) return "neutral";
|
|
395
|
+
if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance <= -0.35) {
|
|
396
|
+
return "long_flush";
|
|
397
|
+
}
|
|
398
|
+
if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance >= 0.35) {
|
|
399
|
+
return "short_flush";
|
|
400
|
+
}
|
|
401
|
+
if (isCrowdedLong(context)) return "crowded_long";
|
|
402
|
+
if (isCrowdedShort(context)) return "crowded_short";
|
|
403
|
+
return "neutral";
|
|
404
|
+
};
|
|
405
|
+
var collectRiskFlags = (contexts) => {
|
|
406
|
+
const flags = /* @__PURE__ */ new Set();
|
|
407
|
+
if (!contexts.length) {
|
|
408
|
+
flags.add("missing_derivatives");
|
|
409
|
+
return [...flags];
|
|
410
|
+
}
|
|
411
|
+
if (contexts.some((context) => context.stale)) {
|
|
412
|
+
flags.add("stale_derivatives");
|
|
413
|
+
}
|
|
414
|
+
for (const context of contexts) {
|
|
415
|
+
if (isCrowdedLong(context)) flags.add("crowded_long");
|
|
416
|
+
if (isCrowdedShort(context)) flags.add("crowded_short");
|
|
417
|
+
if (context.oiChangePct1h != null && context.oiChangePct1h < -1) {
|
|
418
|
+
flags.add("oi_falling");
|
|
419
|
+
}
|
|
420
|
+
if (context.oiChangePct1h != null && Math.abs(context.oiChangePct1h) < 0.15) {
|
|
421
|
+
flags.add("oi_not_confirming");
|
|
422
|
+
}
|
|
423
|
+
if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance <= -0.35) {
|
|
424
|
+
flags.add("long_liquidation_spike");
|
|
425
|
+
}
|
|
426
|
+
if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance >= 0.35) {
|
|
427
|
+
flags.add("short_liquidation_spike");
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return [...flags];
|
|
431
|
+
};
|
|
432
|
+
var resolveDirectionAligned = (params) => {
|
|
433
|
+
const { direction, primary, pressure, riskFlags } = params;
|
|
434
|
+
if (!primary || primary.stale || riskFlags.includes("missing_derivatives")) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
if (direction === "LONG") {
|
|
438
|
+
if (pressure === "crowded_long" || riskFlags.includes("oi_falling")) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
if (pressure === "short_flush" || primary.oiChangePct1h != null && primary.oiChangePct1h > 0.25 && !riskFlags.includes("crowded_long")) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
if (pressure === "crowded_short" || riskFlags.includes("oi_falling")) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (pressure === "long_flush" || primary.oiChangePct1h != null && primary.oiChangePct1h > 0.25 && !riskFlags.includes("crowded_short")) {
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
};
|
|
454
|
+
var buildDerivativesContext = (params) => {
|
|
455
|
+
const {
|
|
456
|
+
symbol,
|
|
457
|
+
direction,
|
|
458
|
+
timestamp,
|
|
459
|
+
rowsByInterval,
|
|
460
|
+
intervals = DERIVATIVES_INTERVALS,
|
|
461
|
+
staleAfterMsByInterval = {}
|
|
462
|
+
} = params;
|
|
463
|
+
const intervalContexts = {};
|
|
464
|
+
for (const interval of intervals) {
|
|
465
|
+
const context = buildIntervalContext({
|
|
466
|
+
interval,
|
|
467
|
+
rows: rowsByInterval[interval],
|
|
468
|
+
timestamp,
|
|
469
|
+
staleAfterMs: staleAfterMsByInterval[interval] ?? DEFAULT_STALE_AFTER_MS[interval]
|
|
470
|
+
});
|
|
471
|
+
if (context) {
|
|
472
|
+
intervalContexts[interval] = context;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const contexts = Object.values(intervalContexts);
|
|
476
|
+
const primary = getPrimaryContext(intervalContexts);
|
|
477
|
+
const pressure = detectPressure(primary);
|
|
478
|
+
const riskFlags = collectRiskFlags(contexts);
|
|
479
|
+
return {
|
|
480
|
+
source: "coinalyze",
|
|
481
|
+
symbol,
|
|
482
|
+
timestamp,
|
|
483
|
+
intervals: intervalContexts,
|
|
484
|
+
summary: {
|
|
485
|
+
pressure,
|
|
486
|
+
directionAligned: resolveDirectionAligned({
|
|
487
|
+
direction,
|
|
488
|
+
primary,
|
|
489
|
+
pressure,
|
|
490
|
+
riskFlags
|
|
491
|
+
}),
|
|
492
|
+
riskFlags
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
|
|
267
497
|
// src/utils/indicators.ts
|
|
268
498
|
var import_technicalindicators = require("technicalindicators");
|
|
269
499
|
|
|
@@ -487,6 +717,17 @@ var DEFAULT_INDICATOR_PERIODS = {
|
|
|
487
717
|
levelLookback: 20,
|
|
488
718
|
levelDelay: 2
|
|
489
719
|
};
|
|
720
|
+
var resolveIndicatorPeriods = (periods = {}) => {
|
|
721
|
+
const resolved = {
|
|
722
|
+
...DEFAULT_INDICATOR_PERIODS
|
|
723
|
+
};
|
|
724
|
+
for (const [key, value] of Object.entries(periods)) {
|
|
725
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
726
|
+
resolved[key] = value;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return resolved;
|
|
730
|
+
};
|
|
490
731
|
var ONE_HOUR_MS = 36e5;
|
|
491
732
|
var ONE_DAY_MS = 864e5;
|
|
492
733
|
var toMlCandle = (candle) => ({
|
|
@@ -569,10 +810,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
569
810
|
options.pluginRegistryScope
|
|
570
811
|
);
|
|
571
812
|
const includeMlPayload = options.includeMlPayload !== false;
|
|
572
|
-
const indicatorPeriods =
|
|
573
|
-
...DEFAULT_INDICATOR_PERIODS,
|
|
574
|
-
...options.periods || {}
|
|
575
|
-
};
|
|
813
|
+
const indicatorPeriods = resolveIndicatorPeriods(options.periods);
|
|
576
814
|
const closes = [];
|
|
577
815
|
const highs = [];
|
|
578
816
|
const lows = [];
|
|
@@ -901,10 +1139,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
901
1139
|
};
|
|
902
1140
|
var buildMlTimeframeIndicators = (candles, periods = {}) => {
|
|
903
1141
|
const result = {};
|
|
904
|
-
const indicatorPeriods =
|
|
905
|
-
...DEFAULT_INDICATOR_PERIODS,
|
|
906
|
-
...periods
|
|
907
|
-
};
|
|
1142
|
+
const indicatorPeriods = resolveIndicatorPeriods(periods);
|
|
908
1143
|
for (const timeframe of INDICATOR_TIMEFRAMES) {
|
|
909
1144
|
const tfCandles = resampleCandles(candles, timeframe.minutes);
|
|
910
1145
|
if (tfCandles.length === 0) continue;
|
|
@@ -1608,8 +1843,14 @@ var createTrendlineEngine = (initialCandles, options) => {
|
|
|
1608
1843
|
return result;
|
|
1609
1844
|
};
|
|
1610
1845
|
const nextMany = (candles) => {
|
|
1611
|
-
|
|
1612
|
-
|
|
1846
|
+
for (const candle of candles) {
|
|
1847
|
+
appendCandle(candle);
|
|
1848
|
+
}
|
|
1849
|
+
let result = buildResult();
|
|
1850
|
+
if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
|
|
1851
|
+
rebuildCandidatesLikeBatch();
|
|
1852
|
+
result = buildResult();
|
|
1853
|
+
}
|
|
1613
1854
|
return result;
|
|
1614
1855
|
};
|
|
1615
1856
|
const getLines = () => buildResult();
|
|
@@ -1626,6 +1867,7 @@ var createTrendlineEngine = (initialCandles, options) => {
|
|
|
1626
1867
|
alignSortedCandlesByTimestamp,
|
|
1627
1868
|
alignSpreadRows,
|
|
1628
1869
|
applyIndicatorsToHistory,
|
|
1870
|
+
buildDerivativesContext,
|
|
1629
1871
|
buildMlCandleIndicators,
|
|
1630
1872
|
buildMlTimeframeIndicators,
|
|
1631
1873
|
buildReturnsFromCandles,
|
package/dist/indicators.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
alignSortedCandlesByTimestamp,
|
|
3
3
|
alignSpreadRows,
|
|
4
4
|
applyIndicatorsToHistory,
|
|
5
|
+
buildDerivativesContext,
|
|
5
6
|
buildMlCandleIndicators,
|
|
6
7
|
buildMlTimeframeIndicators,
|
|
7
8
|
buildReturnsFromCandles,
|
|
@@ -28,15 +29,16 @@ import {
|
|
|
28
29
|
toArrayData,
|
|
29
30
|
toCoinalyzeTimestampMs,
|
|
30
31
|
toFiniteNumber
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-622V7IAT.mjs";
|
|
32
33
|
import "./chunk-AYC2QVKI.mjs";
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
34
|
+
import "./chunk-PQETJ42A.mjs";
|
|
35
|
+
import "./chunk-JLORHLL6.mjs";
|
|
35
36
|
import "./chunk-M7QGVZ3J.mjs";
|
|
36
37
|
export {
|
|
37
38
|
alignSortedCandlesByTimestamp,
|
|
38
39
|
alignSpreadRows,
|
|
39
40
|
applyIndicatorsToHistory,
|
|
41
|
+
buildDerivativesContext,
|
|
40
42
|
buildMlCandleIndicators,
|
|
41
43
|
buildMlTimeframeIndicators,
|
|
42
44
|
buildReturnsFromCandles,
|
package/dist/strategies.d.mts
CHANGED
|
@@ -49,7 +49,9 @@ declare const getDirectionalTpSlPrices: ({ price, direction, takeProfitDelta, st
|
|
|
49
49
|
|
|
50
50
|
type AiRuntimeConfigLike = {
|
|
51
51
|
AI_ENABLED?: boolean;
|
|
52
|
+
AI_MODE?: StrategyRuntimeAiOptions['mode'];
|
|
52
53
|
MIN_AI_QUALITY?: number;
|
|
54
|
+
AI_REPLAY_ANALYSES?: StrategyRuntimeAiOptions['replayAnalyses'];
|
|
53
55
|
};
|
|
54
56
|
type MlRuntimeConfigLike = {
|
|
55
57
|
ML_ENABLED?: boolean;
|
package/dist/strategies.d.ts
CHANGED
|
@@ -49,7 +49,9 @@ declare const getDirectionalTpSlPrices: ({ price, direction, takeProfitDelta, st
|
|
|
49
49
|
|
|
50
50
|
type AiRuntimeConfigLike = {
|
|
51
51
|
AI_ENABLED?: boolean;
|
|
52
|
+
AI_MODE?: StrategyRuntimeAiOptions['mode'];
|
|
52
53
|
MIN_AI_QUALITY?: number;
|
|
54
|
+
AI_REPLAY_ANALYSES?: StrategyRuntimeAiOptions['replayAnalyses'];
|
|
53
55
|
};
|
|
54
56
|
type MlRuntimeConfigLike = {
|
|
55
57
|
ML_ENABLED?: boolean;
|
package/dist/strategies.js
CHANGED
|
@@ -145,6 +145,13 @@ var calculateCoinBtcCorrelation = (coinCandles, btcCandles) => {
|
|
|
145
145
|
};
|
|
146
146
|
};
|
|
147
147
|
|
|
148
|
+
// src/utils/derivativesContext.ts
|
|
149
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
150
|
+
var DEFAULT_STALE_AFTER_MS = {
|
|
151
|
+
"15m": 45 * 60 * 1e3,
|
|
152
|
+
"1h": 3 * HOUR_MS
|
|
153
|
+
};
|
|
154
|
+
|
|
148
155
|
// src/utils/indicators.ts
|
|
149
156
|
var import_technicalindicators = require("technicalindicators");
|
|
150
157
|
|
|
@@ -251,6 +258,17 @@ var DEFAULT_INDICATOR_PERIODS = {
|
|
|
251
258
|
levelLookback: 20,
|
|
252
259
|
levelDelay: 2
|
|
253
260
|
};
|
|
261
|
+
var resolveIndicatorPeriods = (periods = {}) => {
|
|
262
|
+
const resolved = {
|
|
263
|
+
...DEFAULT_INDICATOR_PERIODS
|
|
264
|
+
};
|
|
265
|
+
for (const [key, value] of Object.entries(periods)) {
|
|
266
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
267
|
+
resolved[key] = value;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return resolved;
|
|
271
|
+
};
|
|
254
272
|
var ONE_HOUR_MS = 36e5;
|
|
255
273
|
var ONE_DAY_MS = 864e5;
|
|
256
274
|
var toMlCandle = (candle) => ({
|
|
@@ -333,10 +351,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
333
351
|
options.pluginRegistryScope
|
|
334
352
|
);
|
|
335
353
|
const includeMlPayload = options.includeMlPayload !== false;
|
|
336
|
-
const indicatorPeriods =
|
|
337
|
-
...DEFAULT_INDICATOR_PERIODS,
|
|
338
|
-
...options.periods || {}
|
|
339
|
-
};
|
|
354
|
+
const indicatorPeriods = resolveIndicatorPeriods(options.periods);
|
|
340
355
|
const closes = [];
|
|
341
356
|
const highs = [];
|
|
342
357
|
const lows = [];
|
|
@@ -665,10 +680,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
665
680
|
};
|
|
666
681
|
var buildMlTimeframeIndicators = (candles, periods = {}) => {
|
|
667
682
|
const result = {};
|
|
668
|
-
const indicatorPeriods =
|
|
669
|
-
...DEFAULT_INDICATOR_PERIODS,
|
|
670
|
-
...periods
|
|
671
|
-
};
|
|
683
|
+
const indicatorPeriods = resolveIndicatorPeriods(periods);
|
|
672
684
|
for (const timeframe of INDICATOR_TIMEFRAMES) {
|
|
673
685
|
const tfCandles = resampleCandles(candles, timeframe.minutes);
|
|
674
686
|
if (tfCandles.length === 0) continue;
|
|
@@ -714,22 +726,29 @@ var getTimestamp = (days = 0) => {
|
|
|
714
726
|
};
|
|
715
727
|
|
|
716
728
|
// src/utils/strategyHelpers/indicators.ts
|
|
717
|
-
var buildDefaultIndicatorPeriods = (config) =>
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
729
|
+
var buildDefaultIndicatorPeriods = (config) => {
|
|
730
|
+
const periods = {};
|
|
731
|
+
const assignIfFinite = (key, value) => {
|
|
732
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
733
|
+
periods[key] = value;
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
assignIfFinite("maFast", config.MA_FAST);
|
|
737
|
+
assignIfFinite("maMedium", config.MA_MEDIUM);
|
|
738
|
+
assignIfFinite("maSlow", config.MA_SLOW);
|
|
739
|
+
assignIfFinite("obvSma", config.OBV_SMA);
|
|
740
|
+
assignIfFinite("atr", config.ATR);
|
|
741
|
+
assignIfFinite("atrPctShort", config.ATR_PCT_SHORT);
|
|
742
|
+
assignIfFinite("atrPctLong", config.ATR_PCT_LONG);
|
|
743
|
+
assignIfFinite("bb", config.BB);
|
|
744
|
+
assignIfFinite("bbStd", config.BB_STD);
|
|
745
|
+
assignIfFinite("macdFast", config.MACD_FAST);
|
|
746
|
+
assignIfFinite("macdSlow", config.MACD_SLOW);
|
|
747
|
+
assignIfFinite("macdSignal", config.MACD_SIGNAL);
|
|
748
|
+
assignIfFinite("levelLookback", config.LEVEL_LOOKBACK);
|
|
749
|
+
assignIfFinite("levelDelay", config.LEVEL_DELAY);
|
|
750
|
+
return periods;
|
|
751
|
+
};
|
|
733
752
|
var createStrategyIndicatorsState = ({
|
|
734
753
|
env,
|
|
735
754
|
data,
|
|
@@ -808,7 +827,7 @@ var getStrategyMarketSnapshot = async ({
|
|
|
808
827
|
preloadStart,
|
|
809
828
|
backtestPriceMode = "mid"
|
|
810
829
|
}) => {
|
|
811
|
-
const fullData = env === "BACKTEST" ? cachedData : await connector.kline({
|
|
830
|
+
const fullData = env === "BACKTEST" || env === "CRON" ? cachedData : await connector.kline({
|
|
812
831
|
symbol,
|
|
813
832
|
start: preloadStart,
|
|
814
833
|
end: getTimestamp(),
|
|
@@ -897,16 +916,18 @@ var createLastTradeController = ({
|
|
|
897
916
|
};
|
|
898
917
|
|
|
899
918
|
// src/utils/uuid.ts
|
|
900
|
-
var
|
|
919
|
+
var import_node_crypto = require("crypto");
|
|
901
920
|
var uuid = (len = 12) => {
|
|
902
|
-
const uuid2 = (0,
|
|
921
|
+
const uuid2 = (0, import_node_crypto.randomUUID)();
|
|
903
922
|
return uuid2.slice(-len);
|
|
904
923
|
};
|
|
905
924
|
|
|
906
925
|
// src/utils/strategyHelpers/signalBuilders.ts
|
|
907
926
|
var mapAiRuntimeFromConfig = (config, overrides = {}) => ({
|
|
908
927
|
enabled: Boolean(config.AI_ENABLED ?? true),
|
|
928
|
+
mode: config.AI_MODE ?? "llm",
|
|
909
929
|
minQuality: Number(config.MIN_AI_QUALITY ?? 4),
|
|
930
|
+
replayAnalyses: config.AI_REPLAY_ANALYSES,
|
|
910
931
|
...overrides
|
|
911
932
|
});
|
|
912
933
|
var mapMlRuntimeFromConfig = (config, overrides = {}) => ({
|
|
@@ -970,6 +991,8 @@ var buildEntrySignalDecision = ({
|
|
|
970
991
|
});
|
|
971
992
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
972
993
|
var toDefaultEntryCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_ENTRY`;
|
|
994
|
+
var toDefaultExitCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_EXIT`;
|
|
995
|
+
var toDefaultProtectCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_PROTECT`;
|
|
973
996
|
var resolveTakeProfitPrice = ({
|
|
974
997
|
direction,
|
|
975
998
|
takeProfits
|
|
@@ -1074,6 +1097,28 @@ var createStrategyAPI = ({
|
|
|
1074
1097
|
runtime
|
|
1075
1098
|
});
|
|
1076
1099
|
},
|
|
1100
|
+
exit: async ({
|
|
1101
|
+
code,
|
|
1102
|
+
direction,
|
|
1103
|
+
price,
|
|
1104
|
+
timestamp
|
|
1105
|
+
}) => {
|
|
1106
|
+
const marketData = await getMarketData();
|
|
1107
|
+
return {
|
|
1108
|
+
kind: "exit",
|
|
1109
|
+
code: code ?? toDefaultExitCode(String(strategy), direction),
|
|
1110
|
+
closePlan: {
|
|
1111
|
+
price: price ?? marketData.currentPrice,
|
|
1112
|
+
timestamp: timestamp ?? marketData.timestamp,
|
|
1113
|
+
direction
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
},
|
|
1117
|
+
protect: ({ code, protectPlan }) => ({
|
|
1118
|
+
kind: "protect",
|
|
1119
|
+
code: code ?? toDefaultProtectCode(String(strategy), protectPlan.direction),
|
|
1120
|
+
protectPlan
|
|
1121
|
+
}),
|
|
1077
1122
|
getMarketData,
|
|
1078
1123
|
nextIndicators: (candle, btcCandle) => indicatorsState?.next(candle, btcCandle),
|
|
1079
1124
|
getCurrentPosition,
|
package/dist/strategies.mjs
CHANGED
|
@@ -1,35 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
2
|
uuid
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AJK4NS7Y.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createIndicators
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-622V7IAT.mjs";
|
|
7
7
|
import "./chunk-AYC2QVKI.mjs";
|
|
8
8
|
import {
|
|
9
9
|
getTimestamp
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PQETJ42A.mjs";
|
|
11
11
|
import {
|
|
12
12
|
FEE_PERCENT
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JLORHLL6.mjs";
|
|
14
14
|
import "./chunk-M7QGVZ3J.mjs";
|
|
15
15
|
|
|
16
16
|
// src/utils/strategyHelpers/indicators.ts
|
|
17
|
-
var buildDefaultIndicatorPeriods = (config) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
var buildDefaultIndicatorPeriods = (config) => {
|
|
18
|
+
const periods = {};
|
|
19
|
+
const assignIfFinite = (key, value) => {
|
|
20
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
21
|
+
periods[key] = value;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
assignIfFinite("maFast", config.MA_FAST);
|
|
25
|
+
assignIfFinite("maMedium", config.MA_MEDIUM);
|
|
26
|
+
assignIfFinite("maSlow", config.MA_SLOW);
|
|
27
|
+
assignIfFinite("obvSma", config.OBV_SMA);
|
|
28
|
+
assignIfFinite("atr", config.ATR);
|
|
29
|
+
assignIfFinite("atrPctShort", config.ATR_PCT_SHORT);
|
|
30
|
+
assignIfFinite("atrPctLong", config.ATR_PCT_LONG);
|
|
31
|
+
assignIfFinite("bb", config.BB);
|
|
32
|
+
assignIfFinite("bbStd", config.BB_STD);
|
|
33
|
+
assignIfFinite("macdFast", config.MACD_FAST);
|
|
34
|
+
assignIfFinite("macdSlow", config.MACD_SLOW);
|
|
35
|
+
assignIfFinite("macdSignal", config.MACD_SIGNAL);
|
|
36
|
+
assignIfFinite("levelLookback", config.LEVEL_LOOKBACK);
|
|
37
|
+
assignIfFinite("levelDelay", config.LEVEL_DELAY);
|
|
38
|
+
return periods;
|
|
39
|
+
};
|
|
33
40
|
var createStrategyIndicatorsState = ({
|
|
34
41
|
env,
|
|
35
42
|
data,
|
|
@@ -108,7 +115,7 @@ var getStrategyMarketSnapshot = async ({
|
|
|
108
115
|
preloadStart,
|
|
109
116
|
backtestPriceMode = "mid"
|
|
110
117
|
}) => {
|
|
111
|
-
const fullData = env === "BACKTEST" ? cachedData : await connector.kline({
|
|
118
|
+
const fullData = env === "BACKTEST" || env === "CRON" ? cachedData : await connector.kline({
|
|
112
119
|
symbol,
|
|
113
120
|
start: preloadStart,
|
|
114
121
|
end: getTimestamp(),
|
|
@@ -199,7 +206,9 @@ var createLastTradeController = ({
|
|
|
199
206
|
// src/utils/strategyHelpers/signalBuilders.ts
|
|
200
207
|
var mapAiRuntimeFromConfig = (config, overrides = {}) => ({
|
|
201
208
|
enabled: Boolean(config.AI_ENABLED ?? true),
|
|
209
|
+
mode: config.AI_MODE ?? "llm",
|
|
202
210
|
minQuality: Number(config.MIN_AI_QUALITY ?? 4),
|
|
211
|
+
replayAnalyses: config.AI_REPLAY_ANALYSES,
|
|
203
212
|
...overrides
|
|
204
213
|
});
|
|
205
214
|
var mapMlRuntimeFromConfig = (config, overrides = {}) => ({
|
|
@@ -263,6 +272,8 @@ var buildEntrySignalDecision = ({
|
|
|
263
272
|
});
|
|
264
273
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
265
274
|
var toDefaultEntryCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_ENTRY`;
|
|
275
|
+
var toDefaultExitCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_EXIT`;
|
|
276
|
+
var toDefaultProtectCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_PROTECT`;
|
|
266
277
|
var resolveTakeProfitPrice = ({
|
|
267
278
|
direction,
|
|
268
279
|
takeProfits
|
|
@@ -367,6 +378,28 @@ var createStrategyAPI = ({
|
|
|
367
378
|
runtime
|
|
368
379
|
});
|
|
369
380
|
},
|
|
381
|
+
exit: async ({
|
|
382
|
+
code,
|
|
383
|
+
direction,
|
|
384
|
+
price,
|
|
385
|
+
timestamp
|
|
386
|
+
}) => {
|
|
387
|
+
const marketData = await getMarketData();
|
|
388
|
+
return {
|
|
389
|
+
kind: "exit",
|
|
390
|
+
code: code ?? toDefaultExitCode(String(strategy), direction),
|
|
391
|
+
closePlan: {
|
|
392
|
+
price: price ?? marketData.currentPrice,
|
|
393
|
+
timestamp: timestamp ?? marketData.timestamp,
|
|
394
|
+
direction
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
},
|
|
398
|
+
protect: ({ code, protectPlan }) => ({
|
|
399
|
+
kind: "protect",
|
|
400
|
+
code: code ?? toDefaultProtectCode(String(strategy), protectPlan.direction),
|
|
401
|
+
protectPlan
|
|
402
|
+
}),
|
|
370
403
|
getMarketData,
|
|
371
404
|
nextIndicators: (candle, btcCandle) => indicatorsState?.next(candle, btcCandle),
|
|
372
405
|
getCurrentPosition,
|
|
@@ -5,7 +5,8 @@ declare const getTimestamp: (days?: number) => number;
|
|
|
5
5
|
declare const getItemTimestamp: (item: KlineChartItem) => number;
|
|
6
6
|
declare const getDataTimestamp: (data: KlineChartData) => number | null;
|
|
7
7
|
declare const formatUnix: (dt: number) => string;
|
|
8
|
+
declare const getBacktestPreloadStart: (start: number, preloadDays?: number) => number;
|
|
8
9
|
declare const getTimeline: (start?: number, end?: number, step?: number) => number[];
|
|
9
10
|
declare const compactOrderLog: (timeline: number[], orderLog: OrderLogData) => SimpleOrderLogData;
|
|
10
11
|
|
|
11
|
-
export {
|
|
12
|
+
export { getBacktestPreloadStart as a, getDataTimestamp as b, compactOrderLog as c, getItemTimestamp as d, getTimestamp as e, formatUnix as f, getTimeline as g, toMs as t };
|
|
@@ -5,7 +5,8 @@ declare const getTimestamp: (days?: number) => number;
|
|
|
5
5
|
declare const getItemTimestamp: (item: KlineChartItem) => number;
|
|
6
6
|
declare const getDataTimestamp: (data: KlineChartData) => number | null;
|
|
7
7
|
declare const formatUnix: (dt: number) => string;
|
|
8
|
+
declare const getBacktestPreloadStart: (start: number, preloadDays?: number) => number;
|
|
8
9
|
declare const getTimeline: (start?: number, end?: number, step?: number) => number[];
|
|
9
10
|
declare const compactOrderLog: (timeline: number[], orderLog: OrderLogData) => SimpleOrderLogData;
|
|
10
11
|
|
|
11
|
-
export {
|
|
12
|
+
export { getBacktestPreloadStart as a, getDataTimestamp as b, compactOrderLog as c, getItemTimestamp as d, getTimestamp as e, formatUnix as f, getTimeline as g, toMs as t };
|
package/dist/time.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { f as formatUnix, a as
|
|
1
|
+
export { f as formatUnix, a as getBacktestPreloadStart, b as getDataTimestamp, d as getItemTimestamp, e as getTimestamp, t as toMs } from './time-BMkFD4Kd.mjs';
|
|
2
2
|
import '@tradejs/types';
|
package/dist/time.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { f as formatUnix, a as
|
|
1
|
+
export { f as formatUnix, a as getBacktestPreloadStart, b as getDataTimestamp, d as getItemTimestamp, e as getTimestamp, t as toMs } from './time-BMkFD4Kd.js';
|
|
2
2
|
import '@tradejs/types';
|