@tradejs/core 2.0.17 → 2.0.19
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.js +2 -3
- package/dist/backtest.mjs +1 -1
- package/dist/{chunk-NN7Z3GIK.mjs → chunk-Q3OFPRVV.mjs} +115 -125
- package/dist/{chunk-BOETNABM.mjs → chunk-S4KHOAXM.mjs} +1 -2
- package/dist/chunk-U3GDILUZ.mjs +13 -0
- package/dist/grid.d.mts +3 -2
- package/dist/grid.d.ts +3 -2
- package/dist/grid.js +13 -11
- package/dist/grid.mjs +6 -6
- package/dist/{indicators-C4AaiFrs.d.ts → indicatorControllerContracts-DdSuUzb2.d.mts} +26 -92
- package/dist/{indicators-C4AaiFrs.d.mts → indicatorControllerContracts-DdSuUzb2.d.ts} +26 -92
- package/dist/indicators.d.mts +70 -3
- package/dist/indicators.d.ts +70 -3
- package/dist/indicators.js +114 -125
- package/dist/indicators.mjs +2 -2
- package/dist/strategies.d.mts +6 -3
- package/dist/strategies.d.ts +6 -3
- package/dist/strategies.js +133 -138
- package/dist/strategies.mjs +9 -6
- package/dist/time.js +2 -3
- package/dist/time.mjs +1 -1
- package/dist/uuid-DMoErO_1.d.mts +3 -0
- package/dist/uuid-DMoErO_1.d.ts +3 -0
- package/package.json +2 -2
- package/dist/chunk-AJK4NS7Y.mjs +0 -10
package/dist/strategies.js
CHANGED
|
@@ -6407,7 +6407,7 @@ var calculateRecentRangeExpansionSeries = (candles, lookback) => calculateRecent
|
|
|
6407
6407
|
(index) => calculateRangeExpansionAt(candles, index)
|
|
6408
6408
|
);
|
|
6409
6409
|
|
|
6410
|
-
// src/utils/
|
|
6410
|
+
// src/utils/indicatorBaseContextRelative.ts
|
|
6411
6411
|
var SESSION_WINDOWS = [
|
|
6412
6412
|
{ name: "asia", startMinuteUtc: 0, endMinuteUtc: 8 * 60 },
|
|
6413
6413
|
{ name: "europe", startMinuteUtc: 7 * 60, endMinuteUtc: 16 * 60 },
|
|
@@ -6416,28 +6416,24 @@ var SESSION_WINDOWS = [
|
|
|
6416
6416
|
var FUNDING_WINDOW_STEP_MINUTES = 8 * 60;
|
|
6417
6417
|
var FUNDING_WINDOW_NEARBY_MINUTES = 60;
|
|
6418
6418
|
var SESSION_WINDOW_EDGE_MINUTES = 60;
|
|
6419
|
-
var BASE_INTERVAL_MS = 15 * 6e4;
|
|
6420
6419
|
var PSYCHOLOGICAL_LEVEL_WINDOWS = {
|
|
6421
|
-
m15:
|
|
6420
|
+
m15: 15 * 6e4,
|
|
6422
6421
|
h1: 60 * 6e4,
|
|
6423
6422
|
h4: 4 * 60 * 6e4
|
|
6424
6423
|
};
|
|
6425
|
-
var isInsideSession = (minuteUtc, startMinuteUtc, endMinuteUtc) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
|
|
6426
6424
|
var buildSessionContext = (timestamp) => {
|
|
6427
6425
|
const date = new Date(timestamp);
|
|
6428
|
-
const
|
|
6429
|
-
const utcMinute = date.getUTCMinutes();
|
|
6430
|
-
const minuteUtc = utcHour * 60 + utcMinute;
|
|
6426
|
+
const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
|
|
6431
6427
|
const dayOfWeekUtc = date.getUTCDay() || 7;
|
|
6432
6428
|
const activeSessions = SESSION_WINDOWS.filter(
|
|
6433
|
-
(
|
|
6434
|
-
).map((
|
|
6429
|
+
({ startMinuteUtc, endMinuteUtc }) => startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc
|
|
6430
|
+
).map(({ name }) => name);
|
|
6435
6431
|
const sessionPhase = activeSessions.includes("us") ? "us" : activeSessions.includes("europe") ? "europe" : activeSessions.includes("asia") ? "asia" : "off_hours";
|
|
6436
6432
|
const primaryWindow = SESSION_WINDOWS.find(
|
|
6437
|
-
(
|
|
6433
|
+
({ name }) => name === sessionPhase
|
|
6438
6434
|
);
|
|
6439
|
-
const minutesFromSessionOpen = primaryWindow
|
|
6440
|
-
const minutesToSessionClose = primaryWindow
|
|
6435
|
+
const minutesFromSessionOpen = primaryWindow ? minuteUtc - primaryWindow.startMinuteUtc : null;
|
|
6436
|
+
const minutesToSessionClose = primaryWindow ? primaryWindow.endMinuteUtc - minuteUtc : null;
|
|
6441
6437
|
const sessionWindowPhase = primaryWindow == null || minutesFromSessionOpen == null ? "off_hours" : minutesFromSessionOpen < SESSION_WINDOW_EDGE_MINUTES ? "opening" : minutesToSessionClose != null && minutesToSessionClose <= SESSION_WINDOW_EDGE_MINUTES ? "closing" : "active";
|
|
6442
6438
|
const minutesToFundingWindow = (FUNDING_WINDOW_STEP_MINUTES - minuteUtc % FUNDING_WINDOW_STEP_MINUTES) % FUNDING_WINDOW_STEP_MINUTES;
|
|
6443
6439
|
return {
|
|
@@ -6453,7 +6449,7 @@ var buildSessionContext = (timestamp) => {
|
|
|
6453
6449
|
isWeekendUtc: dayOfWeekUtc >= 6
|
|
6454
6450
|
};
|
|
6455
6451
|
};
|
|
6456
|
-
var
|
|
6452
|
+
var unavailablePsychologicalLevelWindow = () => ({
|
|
6457
6453
|
crossed: null,
|
|
6458
6454
|
direction: "unknown",
|
|
6459
6455
|
level: null,
|
|
@@ -6462,7 +6458,7 @@ var buildUnavailablePsychologicalLevelWindow = () => ({
|
|
|
6462
6458
|
});
|
|
6463
6459
|
var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
|
|
6464
6460
|
if (!Number.isFinite(startPrice) || !Number.isFinite(endPrice) || !Number.isFinite(stepUsd) || startPrice <= 0 || endPrice <= 0 || stepUsd <= 0) {
|
|
6465
|
-
return
|
|
6461
|
+
return unavailablePsychologicalLevelWindow();
|
|
6466
6462
|
}
|
|
6467
6463
|
if (endPrice === startPrice) {
|
|
6468
6464
|
return {
|
|
@@ -6486,21 +6482,17 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
|
|
|
6486
6482
|
distanceBeyondLevelBps: null
|
|
6487
6483
|
};
|
|
6488
6484
|
}
|
|
6489
|
-
const levelsCrossed = Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1;
|
|
6490
|
-
const distanceBeyondLevelBps = Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4;
|
|
6491
6485
|
return {
|
|
6492
6486
|
crossed: true,
|
|
6493
6487
|
direction: movingUp ? "up" : "down",
|
|
6494
6488
|
level: lastCrossedLevel,
|
|
6495
|
-
levelsCrossed,
|
|
6496
|
-
distanceBeyondLevelBps
|
|
6489
|
+
levelsCrossed: Math.round(Math.abs(lastCrossedLevel - firstCrossedLevel) / stepUsd) + 1,
|
|
6490
|
+
distanceBeyondLevelBps: Math.abs(endPrice - lastCrossedLevel) / lastCrossedLevel * 1e4
|
|
6497
6491
|
};
|
|
6498
6492
|
};
|
|
6499
6493
|
var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
|
|
6500
6494
|
const endCandle = candles[candles.length - 1];
|
|
6501
|
-
if (!endCandle)
|
|
6502
|
-
return null;
|
|
6503
|
-
}
|
|
6495
|
+
if (!endCandle) return null;
|
|
6504
6496
|
const candlesByTimestamp = new Map(
|
|
6505
6497
|
candles.map((item) => [item.timestamp, item])
|
|
6506
6498
|
);
|
|
@@ -6515,104 +6507,70 @@ var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
|
|
|
6515
6507
|
startCandle.close,
|
|
6516
6508
|
endCandle.close,
|
|
6517
6509
|
stepUsd
|
|
6518
|
-
) :
|
|
6510
|
+
) : unavailablePsychologicalLevelWindow()
|
|
6519
6511
|
];
|
|
6520
6512
|
})
|
|
6521
6513
|
);
|
|
6522
|
-
return {
|
|
6523
|
-
source: "aligned_15m_ohlcv",
|
|
6524
|
-
stepUsd,
|
|
6525
|
-
windows
|
|
6526
|
-
};
|
|
6514
|
+
return { source: "aligned_15m_ohlcv", stepUsd, windows };
|
|
6527
6515
|
};
|
|
6528
|
-
var
|
|
6529
|
-
var BASE_CONTEXT_CANDLE_WINDOW = 256;
|
|
6530
|
-
var PIVOT_LEFT_RIGHT = 2;
|
|
6531
|
-
var ZONE_ATR_FACTOR = 0.5;
|
|
6532
|
-
var PROFILE_BIN_COUNT = 24;
|
|
6533
|
-
var SR_ZONE_PIVOT_PERIOD = 9;
|
|
6534
|
-
var SR_ZONE_MIN_STRENGTH = 2;
|
|
6535
|
-
var SR_ZONE_MAX_PIVOTS = 15;
|
|
6536
|
-
var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
|
|
6537
|
-
var SR_ZONE_MAX_LEVELS = 6;
|
|
6538
|
-
var VOLUME_STRUCTURE_CALC_BARS = 180;
|
|
6539
|
-
var VOLUME_STRUCTURE_ROW_COUNT = 20;
|
|
6540
|
-
var LIQUIDITY_ZONE_LOOKBACK = 15;
|
|
6541
|
-
var LIQUIDITY_ZONE_MAX_AGE = 120;
|
|
6542
|
-
var LIQUIDITY_TAIL_ATR_LENGTH = 14;
|
|
6543
|
-
var LIQUIDITY_TAIL_ATR_MULT = 0.8;
|
|
6544
|
-
var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
|
|
6545
|
-
var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
|
|
6546
|
-
var LIQUIDITY_TAIL_MIN_GAP = 5;
|
|
6547
|
-
var LIQUIDITY_TAIL_MAX_AGE = 120;
|
|
6548
|
-
var TREND_FOLLOW_PIVOT_LENGTH = 10;
|
|
6549
|
-
var TREND_FOLLOW_ATR_LENGTH = 14;
|
|
6550
|
-
var TREND_FOLLOW_ATR_MULT = 4;
|
|
6551
|
-
var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
|
|
6552
|
-
var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
|
|
6553
|
-
var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
|
|
6554
|
-
var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
|
|
6555
|
-
var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
|
|
6556
|
-
var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
|
|
6557
|
-
var STRUCTURE_ZONES_ACCEPT_BARS = 2;
|
|
6558
|
-
var calculateReturnPctFromCandles = (candles) => {
|
|
6516
|
+
var returnPct = (candles) => {
|
|
6559
6517
|
if (candles.length < 2) return null;
|
|
6560
|
-
const previous = candles[candles.length - 2];
|
|
6561
|
-
const current = candles[candles.length - 1];
|
|
6562
|
-
return percentChange(current.close, previous.close);
|
|
6563
|
-
};
|
|
6564
|
-
var calculateRatioReturnPct = (coinCandles, btcCandles) => {
|
|
6565
|
-
if (coinCandles.length < 2 || btcCandles.length < 2) return null;
|
|
6566
|
-
const currentCoin = coinCandles[coinCandles.length - 1];
|
|
6567
|
-
const previousCoin = coinCandles[coinCandles.length - 2];
|
|
6568
|
-
const currentBtc = btcCandles[btcCandles.length - 1];
|
|
6569
|
-
const previousBtc = btcCandles[btcCandles.length - 2];
|
|
6570
|
-
if (currentBtc.close <= 0 || previousBtc.close <= 0) return null;
|
|
6571
6518
|
return percentChange(
|
|
6572
|
-
|
|
6573
|
-
|
|
6519
|
+
candles[candles.length - 1].close,
|
|
6520
|
+
candles[candles.length - 2].close
|
|
6574
6521
|
);
|
|
6575
6522
|
};
|
|
6576
|
-
var
|
|
6577
|
-
|
|
6578
|
-
const
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6523
|
+
var ratioReturnPct = (target, reference) => {
|
|
6524
|
+
if (target.length < 2 || reference.length < 2) return null;
|
|
6525
|
+
const targetCurrent = target[target.length - 1];
|
|
6526
|
+
const targetPrevious = target[target.length - 2];
|
|
6527
|
+
const referenceCurrent = reference[reference.length - 1];
|
|
6528
|
+
const referencePrevious = reference[reference.length - 2];
|
|
6529
|
+
if (referenceCurrent.close <= 0 || referencePrevious.close <= 0) return null;
|
|
6530
|
+
return percentChange(
|
|
6531
|
+
targetCurrent.close / referenceCurrent.close,
|
|
6532
|
+
targetPrevious.close / referencePrevious.close
|
|
6533
|
+
);
|
|
6534
|
+
};
|
|
6535
|
+
var alignRecentCandles = (target, reference) => {
|
|
6536
|
+
const alignedTarget = [];
|
|
6537
|
+
const alignedReference = [];
|
|
6538
|
+
let targetIndex = Math.max(0, target.length - 80);
|
|
6539
|
+
let referenceIndex = Math.max(0, reference.length - 80);
|
|
6540
|
+
while (targetIndex < target.length && referenceIndex < reference.length) {
|
|
6541
|
+
const targetTimestamp = target[targetIndex].timestamp;
|
|
6542
|
+
const referenceTimestamp = reference[referenceIndex].timestamp;
|
|
6543
|
+
if (targetTimestamp === referenceTimestamp) {
|
|
6544
|
+
alignedTarget.push(target[targetIndex]);
|
|
6545
|
+
alignedReference.push(reference[referenceIndex]);
|
|
6546
|
+
targetIndex += 1;
|
|
6547
|
+
referenceIndex += 1;
|
|
6548
|
+
} else if (targetTimestamp < referenceTimestamp) {
|
|
6549
|
+
targetIndex += 1;
|
|
6591
6550
|
} else {
|
|
6592
|
-
|
|
6551
|
+
referenceIndex += 1;
|
|
6593
6552
|
}
|
|
6594
6553
|
}
|
|
6595
|
-
return {
|
|
6554
|
+
return { alignedTarget, alignedReference };
|
|
6596
6555
|
};
|
|
6597
|
-
var
|
|
6556
|
+
var returnSeries = (candles, limit) => {
|
|
6598
6557
|
const returns = [];
|
|
6599
|
-
|
|
6600
|
-
for (let index = startIndex; index < candles.length; index += 1) {
|
|
6558
|
+
for (let index = Math.max(1, candles.length - limit); index < candles.length; index += 1) {
|
|
6601
6559
|
const previous = candles[index - 1];
|
|
6602
6560
|
const current = candles[index];
|
|
6603
6561
|
if (previous.close <= 0) continue;
|
|
6604
|
-
const
|
|
6605
|
-
if (
|
|
6562
|
+
const value = percentChange(current.close, previous.close);
|
|
6563
|
+
if (value != null && Number.isFinite(value)) returns.push(value);
|
|
6606
6564
|
}
|
|
6607
6565
|
return returns;
|
|
6608
6566
|
};
|
|
6609
|
-
var
|
|
6567
|
+
var beta = (targetReturns, referenceReturns) => {
|
|
6610
6568
|
const length = Math.min(targetReturns.length, referenceReturns.length);
|
|
6611
6569
|
if (length < 2) return null;
|
|
6612
6570
|
const target = targetReturns.slice(-length);
|
|
6613
6571
|
const reference = referenceReturns.slice(-length);
|
|
6614
|
-
const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) /
|
|
6615
|
-
const targetMean = target.reduce((sum2, value) => sum2 + value, 0) /
|
|
6572
|
+
const referenceMean = reference.reduce((sum2, value) => sum2 + value, 0) / length;
|
|
6573
|
+
const targetMean = target.reduce((sum2, value) => sum2 + value, 0) / length;
|
|
6616
6574
|
let covariance = 0;
|
|
6617
6575
|
let referenceVariance = 0;
|
|
6618
6576
|
for (let index = 0; index < length; index += 1) {
|
|
@@ -6629,16 +6587,6 @@ var classifyRatioTrend = (ratioReturn24h, ratioReturn4h) => {
|
|
|
6629
6587
|
if (value < -0.15) return "down";
|
|
6630
6588
|
return "flat";
|
|
6631
6589
|
};
|
|
6632
|
-
var hasDistinctReferenceCandles = (coinCandles, referenceCandles) => {
|
|
6633
|
-
const coinLast = coinCandles[coinCandles.length - 1];
|
|
6634
|
-
const referenceLast = referenceCandles[referenceCandles.length - 1];
|
|
6635
|
-
const coinPrev = coinCandles[coinCandles.length - 2];
|
|
6636
|
-
const referencePrev = referenceCandles[referenceCandles.length - 2];
|
|
6637
|
-
if (!coinLast || !referenceLast || !coinPrev || !referencePrev) {
|
|
6638
|
-
return false;
|
|
6639
|
-
}
|
|
6640
|
-
return coinLast.timestamp !== referenceLast.timestamp || coinLast.close !== referenceLast.close || coinPrev.timestamp !== referencePrev.timestamp || coinPrev.close !== referencePrev.close;
|
|
6641
|
-
};
|
|
6642
6590
|
var buildTargetVsBtcContext = ({
|
|
6643
6591
|
coin1h,
|
|
6644
6592
|
btc1h,
|
|
@@ -6649,19 +6597,21 @@ var buildTargetVsBtcContext = ({
|
|
|
6649
6597
|
coinCandles,
|
|
6650
6598
|
btcCandles
|
|
6651
6599
|
}) => {
|
|
6652
|
-
const ratioReturn1h =
|
|
6653
|
-
const ratioReturn4h =
|
|
6654
|
-
const ratioReturn24h =
|
|
6655
|
-
const coinReturn1h =
|
|
6656
|
-
const coinReturn4h =
|
|
6657
|
-
const coinReturn24h =
|
|
6658
|
-
const btcReturn1h =
|
|
6659
|
-
const btcReturn4h =
|
|
6660
|
-
const btcReturn24h =
|
|
6661
|
-
const {
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6600
|
+
const ratioReturn1h = ratioReturnPct(coin1h, btc1h);
|
|
6601
|
+
const ratioReturn4h = ratioReturnPct(coin4h, btc4h);
|
|
6602
|
+
const ratioReturn24h = ratioReturnPct(coin1d, btc1d);
|
|
6603
|
+
const coinReturn1h = returnPct(coin1h);
|
|
6604
|
+
const coinReturn4h = returnPct(coin4h);
|
|
6605
|
+
const coinReturn24h = returnPct(coin1d);
|
|
6606
|
+
const btcReturn1h = returnPct(btc1h);
|
|
6607
|
+
const btcReturn4h = returnPct(btc4h);
|
|
6608
|
+
const btcReturn24h = returnPct(btc1d);
|
|
6609
|
+
const { alignedTarget, alignedReference } = alignRecentCandles(
|
|
6610
|
+
coinCandles,
|
|
6611
|
+
btcCandles
|
|
6612
|
+
);
|
|
6613
|
+
const coinReturns20 = returnSeries(alignedTarget, 21).slice(-20);
|
|
6614
|
+
const btcReturns20 = returnSeries(alignedReference, 21).slice(-20);
|
|
6665
6615
|
return {
|
|
6666
6616
|
source: "aligned_ohlcv",
|
|
6667
6617
|
ratioReturn1h,
|
|
@@ -6670,11 +6620,21 @@ var buildTargetVsBtcContext = ({
|
|
|
6670
6620
|
alphaVsBtc1h: coinReturn1h == null || btcReturn1h == null ? null : coinReturn1h - btcReturn1h,
|
|
6671
6621
|
alphaVsBtc4h: coinReturn4h == null || btcReturn4h == null ? null : coinReturn4h - btcReturn4h,
|
|
6672
6622
|
alphaVsBtc24h: coinReturn24h == null || btcReturn24h == null ? null : coinReturn24h - btcReturn24h,
|
|
6673
|
-
betaToBtc20:
|
|
6674
|
-
correlationToBtc20,
|
|
6623
|
+
betaToBtc20: beta(coinReturns20, btcReturns20),
|
|
6624
|
+
correlationToBtc20: coinReturns20.length === btcReturns20.length && coinReturns20.length >= 2 ? calculatePearsonCorrelation(coinReturns20, btcReturns20) : null,
|
|
6675
6625
|
ratioTrend: classifyRatioTrend(ratioReturn24h, ratioReturn4h)
|
|
6676
6626
|
};
|
|
6677
6627
|
};
|
|
6628
|
+
var hasDistinctReferenceCandles = (target, reference) => {
|
|
6629
|
+
const targetLast = target[target.length - 1];
|
|
6630
|
+
const referenceLast = reference[reference.length - 1];
|
|
6631
|
+
const targetPrevious = target[target.length - 2];
|
|
6632
|
+
const referencePrevious = reference[reference.length - 2];
|
|
6633
|
+
if (!targetLast || !referenceLast || !targetPrevious || !referencePrevious) {
|
|
6634
|
+
return false;
|
|
6635
|
+
}
|
|
6636
|
+
return targetLast.timestamp !== referenceLast.timestamp || targetLast.close !== referenceLast.close || targetPrevious.timestamp !== referencePrevious.timestamp || targetPrevious.close !== referencePrevious.close;
|
|
6637
|
+
};
|
|
6678
6638
|
var buildTargetVsEthContext = ({
|
|
6679
6639
|
coin1h,
|
|
6680
6640
|
eth1h,
|
|
@@ -6685,9 +6645,7 @@ var buildTargetVsEthContext = ({
|
|
|
6685
6645
|
coinCandles,
|
|
6686
6646
|
ethCandles
|
|
6687
6647
|
}) => {
|
|
6688
|
-
if (!hasDistinctReferenceCandles(coinCandles, ethCandles))
|
|
6689
|
-
return null;
|
|
6690
|
-
}
|
|
6648
|
+
if (!hasDistinctReferenceCandles(coinCandles, ethCandles)) return null;
|
|
6691
6649
|
const context = buildTargetVsBtcContext({
|
|
6692
6650
|
coin1h,
|
|
6693
6651
|
btc1h: eth1h,
|
|
@@ -6711,6 +6669,38 @@ var buildTargetVsEthContext = ({
|
|
|
6711
6669
|
ratioTrend: context.ratioTrend
|
|
6712
6670
|
};
|
|
6713
6671
|
};
|
|
6672
|
+
|
|
6673
|
+
// src/utils/indicatorBaseContext.ts
|
|
6674
|
+
var STRUCTURE_LOOKBACK = 80;
|
|
6675
|
+
var BASE_CONTEXT_CANDLE_WINDOW = 256;
|
|
6676
|
+
var PIVOT_LEFT_RIGHT = 2;
|
|
6677
|
+
var ZONE_ATR_FACTOR = 0.5;
|
|
6678
|
+
var PROFILE_BIN_COUNT = 24;
|
|
6679
|
+
var SR_ZONE_PIVOT_PERIOD = 9;
|
|
6680
|
+
var SR_ZONE_MIN_STRENGTH = 2;
|
|
6681
|
+
var SR_ZONE_MAX_PIVOTS = 15;
|
|
6682
|
+
var SR_ZONE_CHANNEL_WIDTH_PCT = 8;
|
|
6683
|
+
var SR_ZONE_MAX_LEVELS = 6;
|
|
6684
|
+
var VOLUME_STRUCTURE_CALC_BARS = 180;
|
|
6685
|
+
var VOLUME_STRUCTURE_ROW_COUNT = 20;
|
|
6686
|
+
var LIQUIDITY_ZONE_LOOKBACK = 15;
|
|
6687
|
+
var LIQUIDITY_ZONE_MAX_AGE = 120;
|
|
6688
|
+
var LIQUIDITY_TAIL_ATR_LENGTH = 14;
|
|
6689
|
+
var LIQUIDITY_TAIL_ATR_MULT = 0.8;
|
|
6690
|
+
var LIQUIDITY_TAIL_MIN_WICK_RATIO = 1.3;
|
|
6691
|
+
var LIQUIDITY_TAIL_WICK_DOMINANCE = 1.2;
|
|
6692
|
+
var LIQUIDITY_TAIL_MIN_GAP = 5;
|
|
6693
|
+
var LIQUIDITY_TAIL_MAX_AGE = 120;
|
|
6694
|
+
var TREND_FOLLOW_PIVOT_LENGTH = 10;
|
|
6695
|
+
var TREND_FOLLOW_ATR_LENGTH = 14;
|
|
6696
|
+
var TREND_FOLLOW_ATR_MULT = 4;
|
|
6697
|
+
var ADAPTIVE_CHANNEL_REGRESSION_BARS = 7;
|
|
6698
|
+
var ADAPTIVE_CHANNEL_ENVELOPE_BARS = 2;
|
|
6699
|
+
var ADAPTIVE_CHANNEL_ATR_STRETCH = 2;
|
|
6700
|
+
var ADAPTIVE_CHANNEL_VOLATILITY_LOOKBACK = 100;
|
|
6701
|
+
var ADAPTIVE_CHANNEL_CALC_LOOKBACK = 220;
|
|
6702
|
+
var STRUCTURE_ZONES_ZONE_WIDTH_ATR = 0.5;
|
|
6703
|
+
var STRUCTURE_ZONES_ACCEPT_BARS = 2;
|
|
6714
6704
|
var BASE_CONTEXT_MA_LAYER_PERIODS = [
|
|
6715
6705
|
[5, 12],
|
|
6716
6706
|
[9, 13],
|
|
@@ -10701,13 +10691,12 @@ var buildIndicatorSeriesByTimeframes = (candles, periods, sourcePrefix = "") =>
|
|
|
10701
10691
|
|
|
10702
10692
|
// src/utils/timestamp.ts
|
|
10703
10693
|
var import_date_fns = require("date-fns");
|
|
10704
|
-
var import_date_fns2 = require("date-fns");
|
|
10705
10694
|
var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
|
|
10706
10695
|
var getTimestamp = (days = 0) => {
|
|
10707
10696
|
if (days > 0) {
|
|
10708
|
-
return (0,
|
|
10697
|
+
return (0, import_date_fns.getUnixTime)((0, import_date_fns.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
|
|
10709
10698
|
}
|
|
10710
|
-
return (0,
|
|
10699
|
+
return (0, import_date_fns.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
|
|
10711
10700
|
};
|
|
10712
10701
|
|
|
10713
10702
|
// src/utils/strategyHelpers/indicators.ts
|
|
@@ -11234,11 +11223,14 @@ var createStrategyStateControllerFactory = ({
|
|
|
11234
11223
|
};
|
|
11235
11224
|
|
|
11236
11225
|
// src/utils/uuid.ts
|
|
11237
|
-
var
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11226
|
+
var randomUuid = () => {
|
|
11227
|
+
if (!globalThis.crypto?.randomUUID) {
|
|
11228
|
+
throw new Error("crypto.randomUUID is not available in this runtime");
|
|
11229
|
+
}
|
|
11230
|
+
return globalThis.crypto.randomUUID();
|
|
11241
11231
|
};
|
|
11232
|
+
var createIdGenerator = (generateUuid = randomUuid) => (length = 12) => generateUuid().slice(-length);
|
|
11233
|
+
var uuid = createIdGenerator();
|
|
11242
11234
|
|
|
11243
11235
|
// src/utils/strategyHelpers/signalBuilders.ts
|
|
11244
11236
|
var COMPACT_MTF_CANDLE_LIMIT = 3;
|
|
@@ -11922,13 +11914,14 @@ var buildEntrySignalDecision = ({
|
|
|
11922
11914
|
additionalIndicators,
|
|
11923
11915
|
signalId,
|
|
11924
11916
|
orderPlan,
|
|
11925
|
-
runtime
|
|
11917
|
+
runtime,
|
|
11918
|
+
generateId = uuid
|
|
11926
11919
|
}) => ({
|
|
11927
11920
|
kind: "entry",
|
|
11928
11921
|
code,
|
|
11929
11922
|
entryContext,
|
|
11930
11923
|
signal: buildStrategySignal({
|
|
11931
|
-
signalId: signalId ??
|
|
11924
|
+
signalId: signalId ?? generateId(),
|
|
11932
11925
|
strategy: entryContext.strategy,
|
|
11933
11926
|
symbol: entryContext.symbol,
|
|
11934
11927
|
interval: entryContext.interval,
|
|
@@ -11943,7 +11936,7 @@ var buildEntrySignalDecision = ({
|
|
|
11943
11936
|
orderPlan,
|
|
11944
11937
|
runtime
|
|
11945
11938
|
});
|
|
11946
|
-
var
|
|
11939
|
+
var isFiniteNumber2 = (value) => typeof value === "number" && Number.isFinite(value);
|
|
11947
11940
|
var toDefaultEntryCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_ENTRY`;
|
|
11948
11941
|
var toDefaultExitCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_EXIT`;
|
|
11949
11942
|
var toDefaultProtectCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_PROTECT`;
|
|
@@ -11954,7 +11947,7 @@ var resolveTakeProfitPrice = ({
|
|
|
11954
11947
|
if (!Array.isArray(takeProfits) || takeProfits.length === 0) {
|
|
11955
11948
|
throw new Error("strategyApi.entry requires at least one takeProfit");
|
|
11956
11949
|
}
|
|
11957
|
-
const prices = takeProfits.map((tp) => tp?.price).filter((price) =>
|
|
11950
|
+
const prices = takeProfits.map((tp) => tp?.price).filter((price) => isFiniteNumber2(price));
|
|
11958
11951
|
if (prices.length === 0) {
|
|
11959
11952
|
throw new Error("strategyApi.entry requires finite takeProfit prices");
|
|
11960
11953
|
}
|
|
@@ -11971,6 +11964,7 @@ var createStrategyAPI = ({
|
|
|
11971
11964
|
isConfigFromBacktest,
|
|
11972
11965
|
sharedReplayKey,
|
|
11973
11966
|
getSharedReplayState,
|
|
11967
|
+
generateId,
|
|
11974
11968
|
loadDecisionBaseContext
|
|
11975
11969
|
}) => {
|
|
11976
11970
|
const isBacktestEnv = env === "BACKTEST";
|
|
@@ -12088,7 +12082,7 @@ var createStrategyAPI = ({
|
|
|
12088
12082
|
};
|
|
12089
12083
|
const resolveDecisionPriceContext = () => {
|
|
12090
12084
|
const candle = cachedData[cachedData.length - 1];
|
|
12091
|
-
if (!candle || !
|
|
12085
|
+
if (!candle || !isFiniteNumber2(candle.timestamp) || !isFiniteNumber2(candle.close)) {
|
|
12092
12086
|
throw new Error(
|
|
12093
12087
|
"strategyApi.getDecisionPriceContext requires a current closed candle"
|
|
12094
12088
|
);
|
|
@@ -12120,7 +12114,7 @@ var createStrategyAPI = ({
|
|
|
12120
12114
|
direction,
|
|
12121
12115
|
takeProfits: orderPlan.takeProfits
|
|
12122
12116
|
});
|
|
12123
|
-
if (!
|
|
12117
|
+
if (!isFiniteNumber2(stopLossPrice)) {
|
|
12124
12118
|
throw new Error(
|
|
12125
12119
|
"strategyApi.entry requires finite orderPlan.stopLossPrice"
|
|
12126
12120
|
);
|
|
@@ -12153,7 +12147,8 @@ var createStrategyAPI = ({
|
|
|
12153
12147
|
additionalIndicators,
|
|
12154
12148
|
signalId,
|
|
12155
12149
|
orderPlan,
|
|
12156
|
-
runtime
|
|
12150
|
+
runtime,
|
|
12151
|
+
generateId
|
|
12157
12152
|
});
|
|
12158
12153
|
},
|
|
12159
12154
|
exit: async ({ code, direction }) => {
|
package/dist/strategies.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createIndicators,
|
|
3
3
|
getRequiredControllerSeedWindow
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Q3OFPRVV.mjs";
|
|
5
5
|
import "./chunk-AYC2QVKI.mjs";
|
|
6
6
|
import "./chunk-M7QGVZ3J.mjs";
|
|
7
7
|
import {
|
|
8
8
|
uuid
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-U3GDILUZ.mjs";
|
|
10
10
|
import {
|
|
11
11
|
getTimestamp
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S4KHOAXM.mjs";
|
|
13
13
|
import {
|
|
14
14
|
FEE_PERCENT
|
|
15
15
|
} from "./chunk-MKCQSB4H.mjs";
|
|
@@ -1219,13 +1219,14 @@ var buildEntrySignalDecision = ({
|
|
|
1219
1219
|
additionalIndicators,
|
|
1220
1220
|
signalId,
|
|
1221
1221
|
orderPlan,
|
|
1222
|
-
runtime
|
|
1222
|
+
runtime,
|
|
1223
|
+
generateId = uuid
|
|
1223
1224
|
}) => ({
|
|
1224
1225
|
kind: "entry",
|
|
1225
1226
|
code,
|
|
1226
1227
|
entryContext,
|
|
1227
1228
|
signal: buildStrategySignal({
|
|
1228
|
-
signalId: signalId ??
|
|
1229
|
+
signalId: signalId ?? generateId(),
|
|
1229
1230
|
strategy: entryContext.strategy,
|
|
1230
1231
|
symbol: entryContext.symbol,
|
|
1231
1232
|
interval: entryContext.interval,
|
|
@@ -1268,6 +1269,7 @@ var createStrategyAPI = ({
|
|
|
1268
1269
|
isConfigFromBacktest,
|
|
1269
1270
|
sharedReplayKey,
|
|
1270
1271
|
getSharedReplayState,
|
|
1272
|
+
generateId,
|
|
1271
1273
|
loadDecisionBaseContext
|
|
1272
1274
|
}) => {
|
|
1273
1275
|
const isBacktestEnv = env === "BACKTEST";
|
|
@@ -1450,7 +1452,8 @@ var createStrategyAPI = ({
|
|
|
1450
1452
|
additionalIndicators,
|
|
1451
1453
|
signalId,
|
|
1452
1454
|
orderPlan,
|
|
1453
|
-
runtime
|
|
1455
|
+
runtime,
|
|
1456
|
+
generateId
|
|
1454
1457
|
});
|
|
1455
1458
|
},
|
|
1456
1459
|
exit: async ({ code, direction }) => {
|
package/dist/time.js
CHANGED
|
@@ -33,7 +33,6 @@ module.exports = __toCommonJS(time_exports);
|
|
|
33
33
|
|
|
34
34
|
// src/utils/timestamp.ts
|
|
35
35
|
var import_date_fns = require("date-fns");
|
|
36
|
-
var import_date_fns2 = require("date-fns");
|
|
37
36
|
|
|
38
37
|
// src/constants/index.ts
|
|
39
38
|
var BACKTEST_EXECUTION_DELAY_MS = 5 * 6e4;
|
|
@@ -59,9 +58,9 @@ var RUNTIME_STORAGE_DAY_OFFSET_MS = 6 * 60 * 60 * 1e3;
|
|
|
59
58
|
var toMs = (ts) => ts < 1e12 ? ts * 1e3 : ts;
|
|
60
59
|
var getTimestamp = (days = 0) => {
|
|
61
60
|
if (days > 0) {
|
|
62
|
-
return (0,
|
|
61
|
+
return (0, import_date_fns.getUnixTime)((0, import_date_fns.subDays)(/* @__PURE__ */ new Date(), days)) * 1e3;
|
|
63
62
|
}
|
|
64
|
-
return (0,
|
|
63
|
+
return (0, import_date_fns.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
|
|
65
64
|
};
|
|
66
65
|
var getItemTimestamp = (item) => item.timestamp;
|
|
67
66
|
var getDataTimestamp = (data) => {
|
package/dist/time.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.19",
|
|
4
4
|
"description": "MIT-licensed browser-safe API for TradeJS config, strategy authoring, figures, and shared helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
102
|
"dependencies": {
|
|
103
|
-
"@tradejs/types": "^2.0.
|
|
103
|
+
"@tradejs/types": "^2.0.19",
|
|
104
104
|
"date-fns": "^3.6.0",
|
|
105
105
|
"fast-technical-indicators": "^1.1.4",
|
|
106
106
|
"klinecharts": "10.0.0-alpha9",
|