@tradejs/core 3.1.27-beta.250 → 3.1.28-beta.251
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 +9 -2
- package/dist/backtest.d.ts +9 -2
- package/dist/backtest.js +92 -0
- package/dist/backtest.mjs +88 -0
- package/dist/{chunk-5JMDX4IW.mjs → chunk-IS72ATRN.mjs} +102 -64
- package/dist/{chunk-NYJU3J7Y.mjs → chunk-V4KXTU6Y.mjs} +1 -1
- package/dist/{chunk-M7QGVZ3J.mjs → chunk-WJQRRGUY.mjs} +8 -6
- package/dist/data.js +8 -6
- package/dist/data.mjs +1 -1
- package/dist/indicators.js +109 -69
- package/dist/indicators.mjs +2 -2
- package/dist/runtimeTrades.mjs +2 -2
- package/dist/strategies.js +111 -71
- package/dist/strategies.mjs +4 -4
- package/dist/trade.mjs +2 -2
- package/package.json +2 -2
package/dist/backtest.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
|
|
1
|
+
import { ExecutionCostModel, BacktestExecutionCosts, PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
|
|
2
2
|
export { c as compactOrderLog, g as getTimeline } from './time-BQ3AXmxo.mjs';
|
|
3
3
|
|
|
4
4
|
declare const parseTestName: (testName: string) => {
|
|
@@ -7,6 +7,13 @@ declare const parseTestName: (testName: string) => {
|
|
|
7
7
|
testId: string;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
declare const LEGACY_EXECUTION_CONFIG_FIELDS: readonly ["MAKER_FEE_RATE", "TAKER_FEE_RATE", "FUNDING_ENABLED", "SLIPPAGE_BASE_BPS", "SLIPPAGE_SPREAD_MULTIPLIER", "SLIPPAGE_MARKET_IMPACT_BPS", "SLIPPAGE_DELAY_RISK_MULTIPLIER", "EXECUTION_COSTS_CACHE_ONLY"];
|
|
11
|
+
declare const assertStrategyExecutionIsolation: (config: Record<string, unknown>) => void;
|
|
12
|
+
/** Validate JSON at ingestion, including explicit zero rates. Never coerce null. */
|
|
13
|
+
declare const parseBacktestExecutionCosts: (input: unknown) => BacktestExecutionCosts;
|
|
14
|
+
/** Stable economic fields only: timestamps and provenance are separate evidence. */
|
|
15
|
+
declare const executionCostsFromModel: (model: ExecutionCostModel) => BacktestExecutionCosts;
|
|
16
|
+
|
|
10
17
|
/**
|
|
11
18
|
* Максимальная просадка (Max Drawdown) в процентах от бегающего пика.
|
|
12
19
|
* Формула по точкам amount_t:
|
|
@@ -142,4 +149,4 @@ declare const getFormatted: (stat: Partial<TestStat> | undefined, key: TestThres
|
|
|
142
149
|
level: ThresholdLevel;
|
|
143
150
|
};
|
|
144
151
|
|
|
145
|
-
export { type AdvancedExitBreakdownBucket, type AdvancedQuarterlyPnl, type AdvancedTradeDirection, type AdvancedTradeInput, type AdvancedTradeMetrics, type AdvancedTradeMetricsInput, calculateAdvancedTradeMetrics, calculateMaxDrawdown, calculateStatsFull, classifyMetric, getBacktestScore, getFormatted, parseTestName, sortBestTests };
|
|
152
|
+
export { type AdvancedExitBreakdownBucket, type AdvancedQuarterlyPnl, type AdvancedTradeDirection, type AdvancedTradeInput, type AdvancedTradeMetrics, type AdvancedTradeMetricsInput, LEGACY_EXECUTION_CONFIG_FIELDS, assertStrategyExecutionIsolation, calculateAdvancedTradeMetrics, calculateMaxDrawdown, calculateStatsFull, classifyMetric, executionCostsFromModel, getBacktestScore, getFormatted, parseBacktestExecutionCosts, parseTestName, sortBestTests };
|
package/dist/backtest.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
|
|
1
|
+
import { ExecutionCostModel, BacktestExecutionCosts, PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
|
|
2
2
|
export { c as compactOrderLog, g as getTimeline } from './time-BQ3AXmxo.js';
|
|
3
3
|
|
|
4
4
|
declare const parseTestName: (testName: string) => {
|
|
@@ -7,6 +7,13 @@ declare const parseTestName: (testName: string) => {
|
|
|
7
7
|
testId: string;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
declare const LEGACY_EXECUTION_CONFIG_FIELDS: readonly ["MAKER_FEE_RATE", "TAKER_FEE_RATE", "FUNDING_ENABLED", "SLIPPAGE_BASE_BPS", "SLIPPAGE_SPREAD_MULTIPLIER", "SLIPPAGE_MARKET_IMPACT_BPS", "SLIPPAGE_DELAY_RISK_MULTIPLIER", "EXECUTION_COSTS_CACHE_ONLY"];
|
|
11
|
+
declare const assertStrategyExecutionIsolation: (config: Record<string, unknown>) => void;
|
|
12
|
+
/** Validate JSON at ingestion, including explicit zero rates. Never coerce null. */
|
|
13
|
+
declare const parseBacktestExecutionCosts: (input: unknown) => BacktestExecutionCosts;
|
|
14
|
+
/** Stable economic fields only: timestamps and provenance are separate evidence. */
|
|
15
|
+
declare const executionCostsFromModel: (model: ExecutionCostModel) => BacktestExecutionCosts;
|
|
16
|
+
|
|
10
17
|
/**
|
|
11
18
|
* Максимальная просадка (Max Drawdown) в процентах от бегающего пика.
|
|
12
19
|
* Формула по точкам amount_t:
|
|
@@ -142,4 +149,4 @@ declare const getFormatted: (stat: Partial<TestStat> | undefined, key: TestThres
|
|
|
142
149
|
level: ThresholdLevel;
|
|
143
150
|
};
|
|
144
151
|
|
|
145
|
-
export { type AdvancedExitBreakdownBucket, type AdvancedQuarterlyPnl, type AdvancedTradeDirection, type AdvancedTradeInput, type AdvancedTradeMetrics, type AdvancedTradeMetricsInput, calculateAdvancedTradeMetrics, calculateMaxDrawdown, calculateStatsFull, classifyMetric, getBacktestScore, getFormatted, parseTestName, sortBestTests };
|
|
152
|
+
export { type AdvancedExitBreakdownBucket, type AdvancedQuarterlyPnl, type AdvancedTradeDirection, type AdvancedTradeInput, type AdvancedTradeMetrics, type AdvancedTradeMetricsInput, LEGACY_EXECUTION_CONFIG_FIELDS, assertStrategyExecutionIsolation, calculateAdvancedTradeMetrics, calculateMaxDrawdown, calculateStatsFull, classifyMetric, executionCostsFromModel, getBacktestScore, getFormatted, parseBacktestExecutionCosts, parseTestName, sortBestTests };
|
package/dist/backtest.js
CHANGED
|
@@ -30,14 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/backtest.ts
|
|
31
31
|
var backtest_exports = {};
|
|
32
32
|
__export(backtest_exports, {
|
|
33
|
+
LEGACY_EXECUTION_CONFIG_FIELDS: () => LEGACY_EXECUTION_CONFIG_FIELDS,
|
|
34
|
+
assertStrategyExecutionIsolation: () => assertStrategyExecutionIsolation,
|
|
33
35
|
calculateAdvancedTradeMetrics: () => calculateAdvancedTradeMetrics,
|
|
34
36
|
calculateMaxDrawdown: () => calculateMaxDrawdown,
|
|
35
37
|
calculateStatsFull: () => calculateStatsFull,
|
|
36
38
|
classifyMetric: () => classifyMetric,
|
|
37
39
|
compactOrderLog: () => compactOrderLog,
|
|
40
|
+
executionCostsFromModel: () => executionCostsFromModel,
|
|
38
41
|
getBacktestScore: () => getBacktestScore,
|
|
39
42
|
getFormatted: () => getFormatted,
|
|
40
43
|
getTimeline: () => getTimeline,
|
|
44
|
+
parseBacktestExecutionCosts: () => parseBacktestExecutionCosts,
|
|
41
45
|
parseTestName: () => parseTestName,
|
|
42
46
|
sortBestTests: () => sortBestTests
|
|
43
47
|
});
|
|
@@ -49,6 +53,90 @@ var parseTestName = (testName) => {
|
|
|
49
53
|
return { symbol, testSuiteId, testId };
|
|
50
54
|
};
|
|
51
55
|
|
|
56
|
+
// src/utils/backtestExecutionCosts.ts
|
|
57
|
+
var LEGACY_EXECUTION_CONFIG_FIELDS = [
|
|
58
|
+
"MAKER_FEE_RATE",
|
|
59
|
+
"TAKER_FEE_RATE",
|
|
60
|
+
"FUNDING_ENABLED",
|
|
61
|
+
"SLIPPAGE_BASE_BPS",
|
|
62
|
+
"SLIPPAGE_SPREAD_MULTIPLIER",
|
|
63
|
+
"SLIPPAGE_MARKET_IMPACT_BPS",
|
|
64
|
+
"SLIPPAGE_DELAY_RISK_MULTIPLIER",
|
|
65
|
+
"EXECUTION_COSTS_CACHE_ONLY"
|
|
66
|
+
];
|
|
67
|
+
var assertStrategyExecutionIsolation = (config) => {
|
|
68
|
+
for (const key of LEGACY_EXECUTION_CONFIG_FIELDS) {
|
|
69
|
+
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`${key} is an execution setting: use executionCosts separately; strategy estimates use RISK_FEE_RATE and RISK_SLIPPAGE_BPS`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var parseBacktestExecutionCosts = (input) => {
|
|
77
|
+
const record = (value, label) => {
|
|
78
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
79
|
+
throw new Error(`${label} must be an object`);
|
|
80
|
+
return value;
|
|
81
|
+
};
|
|
82
|
+
const root = record(input, "executionCosts");
|
|
83
|
+
const fees = record(root.fees, "executionCosts.fees");
|
|
84
|
+
const slippage = record(root.slippage, "executionCosts.slippage");
|
|
85
|
+
const funding = record(root.funding, "executionCosts.funding");
|
|
86
|
+
const number = (value, label, min = 0, max = Infinity) => {
|
|
87
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < min || value >= max)
|
|
88
|
+
throw new Error(`${label} must be a finite number in [${min}, ${max})`);
|
|
89
|
+
return value;
|
|
90
|
+
};
|
|
91
|
+
if (typeof funding.enabled !== "boolean")
|
|
92
|
+
throw new Error("executionCosts.funding.enabled must be boolean");
|
|
93
|
+
for (const [value, keys, label] of [
|
|
94
|
+
[root, ["fees", "slippage", "funding"], "executionCosts"],
|
|
95
|
+
[fees, ["makerRate", "takerRate"], "fees"],
|
|
96
|
+
[
|
|
97
|
+
slippage,
|
|
98
|
+
["baseBps", "spreadMultiplier", "marketImpactBps", "delayRiskMultiplier"],
|
|
99
|
+
"slippage"
|
|
100
|
+
],
|
|
101
|
+
[funding, ["enabled"], "funding"]
|
|
102
|
+
]) {
|
|
103
|
+
for (const key of Object.keys(value))
|
|
104
|
+
if (!keys.includes(key))
|
|
105
|
+
throw new Error(`Unknown ${label}.${key}`);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
fees: {
|
|
109
|
+
makerRate: number(fees.makerRate, "makerRate", -1, 1),
|
|
110
|
+
takerRate: number(fees.takerRate, "takerRate", -1, 1)
|
|
111
|
+
},
|
|
112
|
+
slippage: {
|
|
113
|
+
baseBps: number(slippage.baseBps, "baseBps", 0, 1e4),
|
|
114
|
+
spreadMultiplier: number(slippage.spreadMultiplier, "spreadMultiplier"),
|
|
115
|
+
marketImpactBps: number(
|
|
116
|
+
slippage.marketImpactBps,
|
|
117
|
+
"marketImpactBps",
|
|
118
|
+
0,
|
|
119
|
+
1e4
|
|
120
|
+
),
|
|
121
|
+
delayRiskMultiplier: number(
|
|
122
|
+
slippage.delayRiskMultiplier,
|
|
123
|
+
"delayRiskMultiplier"
|
|
124
|
+
)
|
|
125
|
+
},
|
|
126
|
+
funding: { enabled: funding.enabled }
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
var executionCostsFromModel = (model) => parseBacktestExecutionCosts({
|
|
130
|
+
fees: { makerRate: model.fees.makerRate, takerRate: model.fees.takerRate },
|
|
131
|
+
slippage: {
|
|
132
|
+
baseBps: model.slippage.baseBps,
|
|
133
|
+
spreadMultiplier: model.slippage.spreadMultiplier,
|
|
134
|
+
marketImpactBps: model.slippage.marketImpactBps,
|
|
135
|
+
delayRiskMultiplier: model.slippage.delayRiskMultiplier
|
|
136
|
+
},
|
|
137
|
+
funding: { enabled: model.funding.enabled }
|
|
138
|
+
});
|
|
139
|
+
|
|
52
140
|
// src/utils/stat.ts
|
|
53
141
|
var import_date_fns = require("date-fns");
|
|
54
142
|
|
|
@@ -904,14 +992,18 @@ var compactOrderLog = (timeline, orderLog) => {
|
|
|
904
992
|
};
|
|
905
993
|
// Annotate the CommonJS export names for ESM import in node:
|
|
906
994
|
0 && (module.exports = {
|
|
995
|
+
LEGACY_EXECUTION_CONFIG_FIELDS,
|
|
996
|
+
assertStrategyExecutionIsolation,
|
|
907
997
|
calculateAdvancedTradeMetrics,
|
|
908
998
|
calculateMaxDrawdown,
|
|
909
999
|
calculateStatsFull,
|
|
910
1000
|
classifyMetric,
|
|
911
1001
|
compactOrderLog,
|
|
1002
|
+
executionCostsFromModel,
|
|
912
1003
|
getBacktestScore,
|
|
913
1004
|
getFormatted,
|
|
914
1005
|
getTimeline,
|
|
1006
|
+
parseBacktestExecutionCosts,
|
|
915
1007
|
parseTestName,
|
|
916
1008
|
sortBestTests
|
|
917
1009
|
});
|
package/dist/backtest.mjs
CHANGED
|
@@ -20,6 +20,90 @@ var parseTestName = (testName) => {
|
|
|
20
20
|
return { symbol, testSuiteId, testId };
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
// src/utils/backtestExecutionCosts.ts
|
|
24
|
+
var LEGACY_EXECUTION_CONFIG_FIELDS = [
|
|
25
|
+
"MAKER_FEE_RATE",
|
|
26
|
+
"TAKER_FEE_RATE",
|
|
27
|
+
"FUNDING_ENABLED",
|
|
28
|
+
"SLIPPAGE_BASE_BPS",
|
|
29
|
+
"SLIPPAGE_SPREAD_MULTIPLIER",
|
|
30
|
+
"SLIPPAGE_MARKET_IMPACT_BPS",
|
|
31
|
+
"SLIPPAGE_DELAY_RISK_MULTIPLIER",
|
|
32
|
+
"EXECUTION_COSTS_CACHE_ONLY"
|
|
33
|
+
];
|
|
34
|
+
var assertStrategyExecutionIsolation = (config) => {
|
|
35
|
+
for (const key of LEGACY_EXECUTION_CONFIG_FIELDS) {
|
|
36
|
+
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`${key} is an execution setting: use executionCosts separately; strategy estimates use RISK_FEE_RATE and RISK_SLIPPAGE_BPS`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var parseBacktestExecutionCosts = (input) => {
|
|
44
|
+
const record = (value, label) => {
|
|
45
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
46
|
+
throw new Error(`${label} must be an object`);
|
|
47
|
+
return value;
|
|
48
|
+
};
|
|
49
|
+
const root = record(input, "executionCosts");
|
|
50
|
+
const fees = record(root.fees, "executionCosts.fees");
|
|
51
|
+
const slippage = record(root.slippage, "executionCosts.slippage");
|
|
52
|
+
const funding = record(root.funding, "executionCosts.funding");
|
|
53
|
+
const number = (value, label, min = 0, max = Infinity) => {
|
|
54
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < min || value >= max)
|
|
55
|
+
throw new Error(`${label} must be a finite number in [${min}, ${max})`);
|
|
56
|
+
return value;
|
|
57
|
+
};
|
|
58
|
+
if (typeof funding.enabled !== "boolean")
|
|
59
|
+
throw new Error("executionCosts.funding.enabled must be boolean");
|
|
60
|
+
for (const [value, keys, label] of [
|
|
61
|
+
[root, ["fees", "slippage", "funding"], "executionCosts"],
|
|
62
|
+
[fees, ["makerRate", "takerRate"], "fees"],
|
|
63
|
+
[
|
|
64
|
+
slippage,
|
|
65
|
+
["baseBps", "spreadMultiplier", "marketImpactBps", "delayRiskMultiplier"],
|
|
66
|
+
"slippage"
|
|
67
|
+
],
|
|
68
|
+
[funding, ["enabled"], "funding"]
|
|
69
|
+
]) {
|
|
70
|
+
for (const key of Object.keys(value))
|
|
71
|
+
if (!keys.includes(key))
|
|
72
|
+
throw new Error(`Unknown ${label}.${key}`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
fees: {
|
|
76
|
+
makerRate: number(fees.makerRate, "makerRate", -1, 1),
|
|
77
|
+
takerRate: number(fees.takerRate, "takerRate", -1, 1)
|
|
78
|
+
},
|
|
79
|
+
slippage: {
|
|
80
|
+
baseBps: number(slippage.baseBps, "baseBps", 0, 1e4),
|
|
81
|
+
spreadMultiplier: number(slippage.spreadMultiplier, "spreadMultiplier"),
|
|
82
|
+
marketImpactBps: number(
|
|
83
|
+
slippage.marketImpactBps,
|
|
84
|
+
"marketImpactBps",
|
|
85
|
+
0,
|
|
86
|
+
1e4
|
|
87
|
+
),
|
|
88
|
+
delayRiskMultiplier: number(
|
|
89
|
+
slippage.delayRiskMultiplier,
|
|
90
|
+
"delayRiskMultiplier"
|
|
91
|
+
)
|
|
92
|
+
},
|
|
93
|
+
funding: { enabled: funding.enabled }
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
var executionCostsFromModel = (model) => parseBacktestExecutionCosts({
|
|
97
|
+
fees: { makerRate: model.fees.makerRate, takerRate: model.fees.takerRate },
|
|
98
|
+
slippage: {
|
|
99
|
+
baseBps: model.slippage.baseBps,
|
|
100
|
+
spreadMultiplier: model.slippage.spreadMultiplier,
|
|
101
|
+
marketImpactBps: model.slippage.marketImpactBps,
|
|
102
|
+
delayRiskMultiplier: model.slippage.delayRiskMultiplier
|
|
103
|
+
},
|
|
104
|
+
funding: { enabled: model.funding.enabled }
|
|
105
|
+
});
|
|
106
|
+
|
|
23
107
|
// src/utils/stat.ts
|
|
24
108
|
import {
|
|
25
109
|
startOfMonth,
|
|
@@ -674,14 +758,18 @@ var getFormatted = (stat, key) => {
|
|
|
674
758
|
};
|
|
675
759
|
};
|
|
676
760
|
export {
|
|
761
|
+
LEGACY_EXECUTION_CONFIG_FIELDS,
|
|
762
|
+
assertStrategyExecutionIsolation,
|
|
677
763
|
calculateAdvancedTradeMetrics,
|
|
678
764
|
calculateMaxDrawdown,
|
|
679
765
|
calculateStatsFull,
|
|
680
766
|
classifyMetric,
|
|
681
767
|
compactOrderLog,
|
|
768
|
+
executionCostsFromModel,
|
|
682
769
|
getBacktestScore,
|
|
683
770
|
getFormatted,
|
|
684
771
|
getTimeline,
|
|
772
|
+
parseBacktestExecutionCosts,
|
|
685
773
|
parseTestName,
|
|
686
774
|
sortBestTests
|
|
687
775
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cloneArrayValues
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WJQRRGUY.mjs";
|
|
4
4
|
import {
|
|
5
5
|
toMs
|
|
6
6
|
} from "./chunk-S4KHOAXM.mjs";
|
|
@@ -977,14 +977,26 @@ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
|
|
|
977
977
|
h1: 60 * 6e4,
|
|
978
978
|
h4: 4 * 60 * 6e4
|
|
979
979
|
};
|
|
980
|
+
var PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES = Object.entries(
|
|
981
|
+
PSYCHOLOGICAL_LEVEL_WINDOWS
|
|
982
|
+
);
|
|
980
983
|
var buildSessionContext = (timestamp) => {
|
|
981
984
|
const date = new Date(timestamp);
|
|
982
985
|
const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
|
|
983
986
|
const dayOfWeekUtc = date.getUTCDay() || 7;
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
987
|
+
let activeSessionCount = 0;
|
|
988
|
+
let asiaActive = false;
|
|
989
|
+
let europeActive = false;
|
|
990
|
+
let usActive = false;
|
|
991
|
+
for (const { name, startMinuteUtc, endMinuteUtc } of SESSION_WINDOWS) {
|
|
992
|
+
const active = startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
|
|
993
|
+
if (!active) continue;
|
|
994
|
+
activeSessionCount += 1;
|
|
995
|
+
if (name === "asia") asiaActive = true;
|
|
996
|
+
if (name === "europe") europeActive = true;
|
|
997
|
+
if (name === "us") usActive = true;
|
|
998
|
+
}
|
|
999
|
+
const sessionPhase = usActive ? "us" : europeActive ? "europe" : asiaActive ? "asia" : "off_hours";
|
|
988
1000
|
const primaryWindow = SESSION_WINDOWS.find(
|
|
989
1001
|
({ name }) => name === sessionPhase
|
|
990
1002
|
);
|
|
@@ -995,7 +1007,7 @@ var buildSessionContext = (timestamp) => {
|
|
|
995
1007
|
return {
|
|
996
1008
|
sessionPhase,
|
|
997
1009
|
sessionWindowPhase,
|
|
998
|
-
isOverlap:
|
|
1010
|
+
isOverlap: activeSessionCount > 1,
|
|
999
1011
|
minutesFromSessionOpen,
|
|
1000
1012
|
minutesToSessionClose,
|
|
1001
1013
|
minutesToFundingWindow,
|
|
@@ -1049,24 +1061,30 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
|
|
|
1049
1061
|
var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
|
|
1050
1062
|
const endCandle = candles[candles.length - 1];
|
|
1051
1063
|
if (!endCandle) return null;
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
startCandle
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1064
|
+
const windows = {};
|
|
1065
|
+
for (const [window, durationMs] of PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES) {
|
|
1066
|
+
const targetTimestamp = endCandle.timestamp - durationMs;
|
|
1067
|
+
let low = 0;
|
|
1068
|
+
let high = candles.length - 1;
|
|
1069
|
+
let startCandle;
|
|
1070
|
+
while (low <= high) {
|
|
1071
|
+
const middle = low + high >>> 1;
|
|
1072
|
+
const candidate = candles[middle];
|
|
1073
|
+
if (candidate.timestamp <= targetTimestamp) {
|
|
1074
|
+
if (candidate.timestamp === targetTimestamp) {
|
|
1075
|
+
startCandle = candidate;
|
|
1076
|
+
}
|
|
1077
|
+
low = middle + 1;
|
|
1078
|
+
} else {
|
|
1079
|
+
high = middle - 1;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
windows[window] = startCandle ? buildPsychologicalLevelWindow(
|
|
1083
|
+
startCandle.close,
|
|
1084
|
+
endCandle.close,
|
|
1085
|
+
stepUsd
|
|
1086
|
+
) : unavailablePsychologicalLevelWindow();
|
|
1087
|
+
}
|
|
1070
1088
|
return { source: "aligned_15m_ohlcv", stepUsd, windows };
|
|
1071
1089
|
};
|
|
1072
1090
|
var returnPct = (candles) => {
|
|
@@ -7957,35 +7975,34 @@ var buildLiquidityZonesContext = (candles, price, previousPrice, atr2) => {
|
|
|
7957
7975
|
}
|
|
7958
7976
|
const lastIndex = candles.length - 1;
|
|
7959
7977
|
const current = candles[lastIndex];
|
|
7960
|
-
|
|
7978
|
+
let activeCount = 0;
|
|
7979
|
+
let nearestSupport = null;
|
|
7980
|
+
let nearestResistance = null;
|
|
7981
|
+
for (const zone of zones) {
|
|
7961
7982
|
if (lastIndex - zone.startIndex > LIQUIDITY_ZONE_MAX_AGE) {
|
|
7962
|
-
|
|
7983
|
+
continue;
|
|
7963
7984
|
}
|
|
7964
7985
|
const crossed = zone.crossed || (zone.kind === "swing_high_liquidity" ? current.close > zone.top : current.close < zone.bottom);
|
|
7965
7986
|
zone.crossed = crossed;
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
const nearestResistance = resistances.reduce(
|
|
7979
|
-
(nearest, zone) => nearest == null || Math.abs(zone.level - price) < Math.abs(nearest.level - price) ? zone : nearest,
|
|
7980
|
-
null
|
|
7981
|
-
) ?? null;
|
|
7987
|
+
if (crossed) {
|
|
7988
|
+
continue;
|
|
7989
|
+
}
|
|
7990
|
+
activeCount += 1;
|
|
7991
|
+
if (zone.kind === "swing_low_liquidity") {
|
|
7992
|
+
if (nearestSupport == null || Math.abs(price - zone.level) < Math.abs(price - nearestSupport.level)) {
|
|
7993
|
+
nearestSupport = zone;
|
|
7994
|
+
}
|
|
7995
|
+
} else if (nearestResistance == null || Math.abs(zone.level - price) < Math.abs(nearestResistance.level - price)) {
|
|
7996
|
+
nearestResistance = zone;
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7982
7999
|
const supportRetest = nearestSupport != null && current.low <= nearestSupport.top;
|
|
7983
8000
|
const resistanceRetest = nearestResistance != null && current.high >= nearestResistance.bottom;
|
|
7984
8001
|
const retestZone = supportRetest ? nearestSupport : resistanceRetest ? nearestResistance : null;
|
|
7985
8002
|
const retestPenetration = retestZone == null ? null : retestZone.kind === "swing_low_liquidity" ? Math.max(0, retestZone.top - current.low) : Math.max(0, current.high - retestZone.bottom);
|
|
7986
8003
|
const retestHeight = retestZone == null ? null : Math.max(retestZone.top - retestZone.bottom, 0);
|
|
7987
8004
|
return {
|
|
7988
|
-
activeCount
|
|
8005
|
+
activeCount,
|
|
7989
8006
|
nearestSupport: {
|
|
7990
8007
|
top: nearestSupport?.top ?? null,
|
|
7991
8008
|
bottom: nearestSupport?.bottom ?? null,
|
|
@@ -8094,19 +8111,22 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
8094
8111
|
}
|
|
8095
8112
|
const lastIndex = candles.length - 1;
|
|
8096
8113
|
const current = candles[lastIndex];
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8114
|
+
let activeCount = 0;
|
|
8115
|
+
let nearestBuy = null;
|
|
8116
|
+
let nearestSell = null;
|
|
8117
|
+
for (const zone of zones) {
|
|
8118
|
+
if (zone.spent || lastIndex - zone.startIndex > LIQUIDITY_TAIL_MAX_AGE) {
|
|
8119
|
+
continue;
|
|
8120
|
+
}
|
|
8121
|
+
activeCount += 1;
|
|
8122
|
+
if (zone.kind === "buy_pressure") {
|
|
8123
|
+
if (nearestBuy == null || Math.abs(price - zone.mid) < Math.abs(price - nearestBuy.mid)) {
|
|
8124
|
+
nearestBuy = zone;
|
|
8125
|
+
}
|
|
8126
|
+
} else if (nearestSell == null || Math.abs(zone.mid - price) < Math.abs(nearestSell.mid - price)) {
|
|
8127
|
+
nearestSell = zone;
|
|
8128
|
+
}
|
|
8129
|
+
}
|
|
8110
8130
|
const topShadow = current.high - Math.max(current.open, current.close);
|
|
8111
8131
|
const bottomShadow = Math.min(current.open, current.close) - current.low;
|
|
8112
8132
|
const body = Math.max(Math.abs(current.close - current.open), 1e-9);
|
|
@@ -8115,7 +8135,7 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
8115
8135
|
const dominantWick = dominantUpper ? topShadow : bottomShadow;
|
|
8116
8136
|
const oppositeWick = dominantUpper ? bottomShadow : topShadow;
|
|
8117
8137
|
return {
|
|
8118
|
-
activeCount
|
|
8138
|
+
activeCount,
|
|
8119
8139
|
nearestBuyPressure: {
|
|
8120
8140
|
top: nearestBuy?.top ?? null,
|
|
8121
8141
|
bottom: nearestBuy?.bottom ?? null,
|
|
@@ -9750,6 +9770,7 @@ var BASE_CONTEXT_PSAR_EMA_PERIOD = 50;
|
|
|
9750
9770
|
var BASE_CONTEXT_PSAR_ADX_MIN = 15;
|
|
9751
9771
|
var BASE_CONTEXT_PSAR_COOLDOWN_BARS = 1;
|
|
9752
9772
|
var baseContextEmaKey = (period) => String(period);
|
|
9773
|
+
var sliceCapturedBaseContextTail = (values, length) => values.slice(Math.max(0, length - BASE_CONTEXT_CANDLE_WINDOW), length);
|
|
9753
9774
|
var processLike = globalThis.process;
|
|
9754
9775
|
var INDICATOR_NEXT_PROFILE = processLike?.env?.TRADEJS_INDICATOR_NEXT_PROFILE === "1";
|
|
9755
9776
|
var indicatorNextProfileStats = {
|
|
@@ -10925,7 +10946,6 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
10925
10946
|
let cachedBaseContextSnapshot;
|
|
10926
10947
|
const getCapturedCoinCandles = () => candlesHistory.slice(0, capturedCoinLength);
|
|
10927
10948
|
const getCapturedBtcCandles = () => btcCandlesHistory.slice(0, capturedBtcLength);
|
|
10928
|
-
const getCapturedEthCandles = () => ethCandlesHistory.slice(0, capturedEthLength);
|
|
10929
10949
|
const getCapturedCoinResampled = () => ({
|
|
10930
10950
|
h1: coin1hCache.snapshot(capturedCoin1hLength),
|
|
10931
10951
|
h4: coin4hCache.snapshot(capturedCoin4hLength),
|
|
@@ -11015,12 +11035,30 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
11015
11035
|
candle: latestCandle,
|
|
11016
11036
|
prevCandle: latestPrevCandle,
|
|
11017
11037
|
baseResult,
|
|
11018
|
-
candlesHistory:
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11038
|
+
candlesHistory: sliceCapturedBaseContextTail(
|
|
11039
|
+
candlesHistory,
|
|
11040
|
+
capturedCoinLength
|
|
11041
|
+
),
|
|
11042
|
+
btcCandlesHistory: sliceCapturedBaseContextTail(
|
|
11043
|
+
btcCandlesHistory,
|
|
11044
|
+
capturedBtcLength
|
|
11045
|
+
),
|
|
11046
|
+
ethCandlesHistory: sliceCapturedBaseContextTail(
|
|
11047
|
+
ethCandlesHistory,
|
|
11048
|
+
capturedEthLength
|
|
11049
|
+
),
|
|
11050
|
+
closeSeries: sliceCapturedBaseContextTail(
|
|
11051
|
+
closes,
|
|
11052
|
+
capturedCoinLength
|
|
11053
|
+
),
|
|
11054
|
+
volumeSeries: sliceCapturedBaseContextTail(
|
|
11055
|
+
volumes,
|
|
11056
|
+
capturedCoinLength
|
|
11057
|
+
),
|
|
11058
|
+
btcCloseSeries: sliceCapturedBaseContextTail(
|
|
11059
|
+
btcCloses,
|
|
11060
|
+
capturedBtcLength
|
|
11061
|
+
),
|
|
11024
11062
|
coinResampledCandles: getCapturedCoinResampled(),
|
|
11025
11063
|
btcResampledCandles: getCapturedBtcResampled(),
|
|
11026
11064
|
ethResampledCandles: getCapturedEthResampled(),
|
|
@@ -46,12 +46,14 @@ var isWrongData = (interval, data) => {
|
|
|
46
46
|
}
|
|
47
47
|
return false;
|
|
48
48
|
};
|
|
49
|
-
var cloneArrayValues = (record) =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
var cloneArrayValues = (record) => {
|
|
50
|
+
const clone = {};
|
|
51
|
+
for (const key of Object.keys(record)) {
|
|
52
|
+
const value = record[key];
|
|
53
|
+
clone[key] = Array.isArray(value) ? value.slice() : value;
|
|
54
|
+
}
|
|
55
|
+
return clone;
|
|
56
|
+
};
|
|
55
57
|
|
|
56
58
|
export {
|
|
57
59
|
intervalToMs,
|
package/dist/data.js
CHANGED
|
@@ -86,12 +86,14 @@ var isWrongData = (interval, data) => {
|
|
|
86
86
|
}
|
|
87
87
|
return false;
|
|
88
88
|
};
|
|
89
|
-
var cloneArrayValues = (record) =>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
var cloneArrayValues = (record) => {
|
|
90
|
+
const clone = {};
|
|
91
|
+
for (const key of Object.keys(record)) {
|
|
92
|
+
const value = record[key];
|
|
93
|
+
clone[key] = Array.isArray(value) ? value.slice() : value;
|
|
94
|
+
}
|
|
95
|
+
return clone;
|
|
96
|
+
};
|
|
95
97
|
|
|
96
98
|
// src/utils/toJson.ts
|
|
97
99
|
var toJson = (data, stringify = false) => {
|
package/dist/data.mjs
CHANGED
package/dist/indicators.js
CHANGED
|
@@ -754,12 +754,14 @@ var TRENDLINE_DEFAULTS = {
|
|
|
754
754
|
|
|
755
755
|
// src/utils/array.ts
|
|
756
756
|
var import_lodash2 = __toESM(require("lodash"));
|
|
757
|
-
var cloneArrayValues = (record) =>
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
757
|
+
var cloneArrayValues = (record) => {
|
|
758
|
+
const clone = {};
|
|
759
|
+
for (const key of Object.keys(record)) {
|
|
760
|
+
const value = record[key];
|
|
761
|
+
clone[key] = Array.isArray(value) ? value.slice() : value;
|
|
762
|
+
}
|
|
763
|
+
return clone;
|
|
764
|
+
};
|
|
763
765
|
|
|
764
766
|
// src/utils/indicatorHistory.ts
|
|
765
767
|
var createNumericHistoryBuffer = () => ({
|
|
@@ -1092,14 +1094,26 @@ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
|
|
|
1092
1094
|
h1: 60 * 6e4,
|
|
1093
1095
|
h4: 4 * 60 * 6e4
|
|
1094
1096
|
};
|
|
1097
|
+
var PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES = Object.entries(
|
|
1098
|
+
PSYCHOLOGICAL_LEVEL_WINDOWS
|
|
1099
|
+
);
|
|
1095
1100
|
var buildSessionContext = (timestamp) => {
|
|
1096
1101
|
const date = new Date(timestamp);
|
|
1097
1102
|
const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
|
|
1098
1103
|
const dayOfWeekUtc = date.getUTCDay() || 7;
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1104
|
+
let activeSessionCount = 0;
|
|
1105
|
+
let asiaActive = false;
|
|
1106
|
+
let europeActive = false;
|
|
1107
|
+
let usActive = false;
|
|
1108
|
+
for (const { name, startMinuteUtc, endMinuteUtc } of SESSION_WINDOWS) {
|
|
1109
|
+
const active = startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
|
|
1110
|
+
if (!active) continue;
|
|
1111
|
+
activeSessionCount += 1;
|
|
1112
|
+
if (name === "asia") asiaActive = true;
|
|
1113
|
+
if (name === "europe") europeActive = true;
|
|
1114
|
+
if (name === "us") usActive = true;
|
|
1115
|
+
}
|
|
1116
|
+
const sessionPhase = usActive ? "us" : europeActive ? "europe" : asiaActive ? "asia" : "off_hours";
|
|
1103
1117
|
const primaryWindow = SESSION_WINDOWS.find(
|
|
1104
1118
|
({ name }) => name === sessionPhase
|
|
1105
1119
|
);
|
|
@@ -1110,7 +1124,7 @@ var buildSessionContext = (timestamp) => {
|
|
|
1110
1124
|
return {
|
|
1111
1125
|
sessionPhase,
|
|
1112
1126
|
sessionWindowPhase,
|
|
1113
|
-
isOverlap:
|
|
1127
|
+
isOverlap: activeSessionCount > 1,
|
|
1114
1128
|
minutesFromSessionOpen,
|
|
1115
1129
|
minutesToSessionClose,
|
|
1116
1130
|
minutesToFundingWindow,
|
|
@@ -1164,24 +1178,30 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
|
|
|
1164
1178
|
var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
|
|
1165
1179
|
const endCandle = candles[candles.length - 1];
|
|
1166
1180
|
if (!endCandle) return null;
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
startCandle
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1181
|
+
const windows = {};
|
|
1182
|
+
for (const [window, durationMs] of PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES) {
|
|
1183
|
+
const targetTimestamp = endCandle.timestamp - durationMs;
|
|
1184
|
+
let low = 0;
|
|
1185
|
+
let high = candles.length - 1;
|
|
1186
|
+
let startCandle;
|
|
1187
|
+
while (low <= high) {
|
|
1188
|
+
const middle = low + high >>> 1;
|
|
1189
|
+
const candidate = candles[middle];
|
|
1190
|
+
if (candidate.timestamp <= targetTimestamp) {
|
|
1191
|
+
if (candidate.timestamp === targetTimestamp) {
|
|
1192
|
+
startCandle = candidate;
|
|
1193
|
+
}
|
|
1194
|
+
low = middle + 1;
|
|
1195
|
+
} else {
|
|
1196
|
+
high = middle - 1;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
windows[window] = startCandle ? buildPsychologicalLevelWindow(
|
|
1200
|
+
startCandle.close,
|
|
1201
|
+
endCandle.close,
|
|
1202
|
+
stepUsd
|
|
1203
|
+
) : unavailablePsychologicalLevelWindow();
|
|
1204
|
+
}
|
|
1185
1205
|
return { source: "aligned_15m_ohlcv", stepUsd, windows };
|
|
1186
1206
|
};
|
|
1187
1207
|
var returnPct = (candles) => {
|
|
@@ -8072,35 +8092,34 @@ var buildLiquidityZonesContext = (candles, price, previousPrice, atr2) => {
|
|
|
8072
8092
|
}
|
|
8073
8093
|
const lastIndex = candles.length - 1;
|
|
8074
8094
|
const current = candles[lastIndex];
|
|
8075
|
-
|
|
8095
|
+
let activeCount = 0;
|
|
8096
|
+
let nearestSupport = null;
|
|
8097
|
+
let nearestResistance = null;
|
|
8098
|
+
for (const zone of zones) {
|
|
8076
8099
|
if (lastIndex - zone.startIndex > LIQUIDITY_ZONE_MAX_AGE) {
|
|
8077
|
-
|
|
8100
|
+
continue;
|
|
8078
8101
|
}
|
|
8079
8102
|
const crossed = zone.crossed || (zone.kind === "swing_high_liquidity" ? current.close > zone.top : current.close < zone.bottom);
|
|
8080
8103
|
zone.crossed = crossed;
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
const nearestResistance = resistances.reduce(
|
|
8094
|
-
(nearest, zone) => nearest == null || Math.abs(zone.level - price) < Math.abs(nearest.level - price) ? zone : nearest,
|
|
8095
|
-
null
|
|
8096
|
-
) ?? null;
|
|
8104
|
+
if (crossed) {
|
|
8105
|
+
continue;
|
|
8106
|
+
}
|
|
8107
|
+
activeCount += 1;
|
|
8108
|
+
if (zone.kind === "swing_low_liquidity") {
|
|
8109
|
+
if (nearestSupport == null || Math.abs(price - zone.level) < Math.abs(price - nearestSupport.level)) {
|
|
8110
|
+
nearestSupport = zone;
|
|
8111
|
+
}
|
|
8112
|
+
} else if (nearestResistance == null || Math.abs(zone.level - price) < Math.abs(nearestResistance.level - price)) {
|
|
8113
|
+
nearestResistance = zone;
|
|
8114
|
+
}
|
|
8115
|
+
}
|
|
8097
8116
|
const supportRetest = nearestSupport != null && current.low <= nearestSupport.top;
|
|
8098
8117
|
const resistanceRetest = nearestResistance != null && current.high >= nearestResistance.bottom;
|
|
8099
8118
|
const retestZone = supportRetest ? nearestSupport : resistanceRetest ? nearestResistance : null;
|
|
8100
8119
|
const retestPenetration = retestZone == null ? null : retestZone.kind === "swing_low_liquidity" ? Math.max(0, retestZone.top - current.low) : Math.max(0, current.high - retestZone.bottom);
|
|
8101
8120
|
const retestHeight = retestZone == null ? null : Math.max(retestZone.top - retestZone.bottom, 0);
|
|
8102
8121
|
return {
|
|
8103
|
-
activeCount
|
|
8122
|
+
activeCount,
|
|
8104
8123
|
nearestSupport: {
|
|
8105
8124
|
top: nearestSupport?.top ?? null,
|
|
8106
8125
|
bottom: nearestSupport?.bottom ?? null,
|
|
@@ -8209,19 +8228,22 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
8209
8228
|
}
|
|
8210
8229
|
const lastIndex = candles.length - 1;
|
|
8211
8230
|
const current = candles[lastIndex];
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8231
|
+
let activeCount = 0;
|
|
8232
|
+
let nearestBuy = null;
|
|
8233
|
+
let nearestSell = null;
|
|
8234
|
+
for (const zone of zones) {
|
|
8235
|
+
if (zone.spent || lastIndex - zone.startIndex > LIQUIDITY_TAIL_MAX_AGE) {
|
|
8236
|
+
continue;
|
|
8237
|
+
}
|
|
8238
|
+
activeCount += 1;
|
|
8239
|
+
if (zone.kind === "buy_pressure") {
|
|
8240
|
+
if (nearestBuy == null || Math.abs(price - zone.mid) < Math.abs(price - nearestBuy.mid)) {
|
|
8241
|
+
nearestBuy = zone;
|
|
8242
|
+
}
|
|
8243
|
+
} else if (nearestSell == null || Math.abs(zone.mid - price) < Math.abs(nearestSell.mid - price)) {
|
|
8244
|
+
nearestSell = zone;
|
|
8245
|
+
}
|
|
8246
|
+
}
|
|
8225
8247
|
const topShadow = current.high - Math.max(current.open, current.close);
|
|
8226
8248
|
const bottomShadow = Math.min(current.open, current.close) - current.low;
|
|
8227
8249
|
const body = Math.max(Math.abs(current.close - current.open), 1e-9);
|
|
@@ -8230,7 +8252,7 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
8230
8252
|
const dominantWick = dominantUpper ? topShadow : bottomShadow;
|
|
8231
8253
|
const oppositeWick = dominantUpper ? bottomShadow : topShadow;
|
|
8232
8254
|
return {
|
|
8233
|
-
activeCount
|
|
8255
|
+
activeCount,
|
|
8234
8256
|
nearestBuyPressure: {
|
|
8235
8257
|
top: nearestBuy?.top ?? null,
|
|
8236
8258
|
bottom: nearestBuy?.bottom ?? null,
|
|
@@ -9865,6 +9887,7 @@ var BASE_CONTEXT_PSAR_EMA_PERIOD = 50;
|
|
|
9865
9887
|
var BASE_CONTEXT_PSAR_ADX_MIN = 15;
|
|
9866
9888
|
var BASE_CONTEXT_PSAR_COOLDOWN_BARS = 1;
|
|
9867
9889
|
var baseContextEmaKey = (period) => String(period);
|
|
9890
|
+
var sliceCapturedBaseContextTail = (values, length) => values.slice(Math.max(0, length - BASE_CONTEXT_CANDLE_WINDOW), length);
|
|
9868
9891
|
var processLike = globalThis.process;
|
|
9869
9892
|
var INDICATOR_NEXT_PROFILE = processLike?.env?.TRADEJS_INDICATOR_NEXT_PROFILE === "1";
|
|
9870
9893
|
var indicatorNextProfileStats = {
|
|
@@ -11040,7 +11063,6 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
11040
11063
|
let cachedBaseContextSnapshot;
|
|
11041
11064
|
const getCapturedCoinCandles = () => candlesHistory.slice(0, capturedCoinLength);
|
|
11042
11065
|
const getCapturedBtcCandles = () => btcCandlesHistory.slice(0, capturedBtcLength);
|
|
11043
|
-
const getCapturedEthCandles = () => ethCandlesHistory.slice(0, capturedEthLength);
|
|
11044
11066
|
const getCapturedCoinResampled = () => ({
|
|
11045
11067
|
h1: coin1hCache.snapshot(capturedCoin1hLength),
|
|
11046
11068
|
h4: coin4hCache.snapshot(capturedCoin4hLength),
|
|
@@ -11130,12 +11152,30 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
11130
11152
|
candle: latestCandle,
|
|
11131
11153
|
prevCandle: latestPrevCandle,
|
|
11132
11154
|
baseResult,
|
|
11133
|
-
candlesHistory:
|
|
11134
|
-
|
|
11135
|
-
|
|
11136
|
-
|
|
11137
|
-
|
|
11138
|
-
|
|
11155
|
+
candlesHistory: sliceCapturedBaseContextTail(
|
|
11156
|
+
candlesHistory,
|
|
11157
|
+
capturedCoinLength
|
|
11158
|
+
),
|
|
11159
|
+
btcCandlesHistory: sliceCapturedBaseContextTail(
|
|
11160
|
+
btcCandlesHistory,
|
|
11161
|
+
capturedBtcLength
|
|
11162
|
+
),
|
|
11163
|
+
ethCandlesHistory: sliceCapturedBaseContextTail(
|
|
11164
|
+
ethCandlesHistory,
|
|
11165
|
+
capturedEthLength
|
|
11166
|
+
),
|
|
11167
|
+
closeSeries: sliceCapturedBaseContextTail(
|
|
11168
|
+
closes,
|
|
11169
|
+
capturedCoinLength
|
|
11170
|
+
),
|
|
11171
|
+
volumeSeries: sliceCapturedBaseContextTail(
|
|
11172
|
+
volumes,
|
|
11173
|
+
capturedCoinLength
|
|
11174
|
+
),
|
|
11175
|
+
btcCloseSeries: sliceCapturedBaseContextTail(
|
|
11176
|
+
btcCloses,
|
|
11177
|
+
capturedBtcLength
|
|
11178
|
+
),
|
|
11139
11179
|
coinResampledCandles: getCapturedCoinResampled(),
|
|
11140
11180
|
btcResampledCandles: getCapturedBtcResampled(),
|
|
11141
11181
|
ethResampledCandles: getCapturedEthResampled(),
|
package/dist/indicators.mjs
CHANGED
|
@@ -39,8 +39,8 @@ import {
|
|
|
39
39
|
toArrayData,
|
|
40
40
|
toCoinalyzeTimestampMs,
|
|
41
41
|
toFiniteNumber
|
|
42
|
-
} from "./chunk-
|
|
43
|
-
import "./chunk-
|
|
42
|
+
} from "./chunk-IS72ATRN.mjs";
|
|
43
|
+
import "./chunk-WJQRRGUY.mjs";
|
|
44
44
|
import "./chunk-S4KHOAXM.mjs";
|
|
45
45
|
import "./chunk-LI6FPPKB.mjs";
|
|
46
46
|
import "./chunk-MKCQSB4H.mjs";
|
package/dist/runtimeTrades.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
normalizeStrategyOrderLinkKey,
|
|
3
3
|
parseStrategyOrderLinkKey
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-V4KXTU6Y.mjs";
|
|
5
|
+
import "./chunk-WJQRRGUY.mjs";
|
|
6
6
|
import {
|
|
7
7
|
INITIAL_BACKTEST_AMOUNT
|
|
8
8
|
} from "./chunk-MKCQSB4H.mjs";
|
package/dist/strategies.js
CHANGED
|
@@ -186,12 +186,14 @@ var DERIVATIVES_CONTEXT_REFERENCE_SYMBOLS = [
|
|
|
186
186
|
|
|
187
187
|
// src/utils/array.ts
|
|
188
188
|
var import_lodash2 = __toESM(require("lodash"));
|
|
189
|
-
var cloneArrayValues = (record) =>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
var cloneArrayValues = (record) => {
|
|
190
|
+
const clone = {};
|
|
191
|
+
for (const key of Object.keys(record)) {
|
|
192
|
+
const value = record[key];
|
|
193
|
+
clone[key] = Array.isArray(value) ? value.slice() : value;
|
|
194
|
+
}
|
|
195
|
+
return clone;
|
|
196
|
+
};
|
|
195
197
|
|
|
196
198
|
// src/utils/indicatorHistory.ts
|
|
197
199
|
var createNumericHistoryBuffer = () => ({
|
|
@@ -524,14 +526,26 @@ var PSYCHOLOGICAL_LEVEL_WINDOWS = {
|
|
|
524
526
|
h1: 60 * 6e4,
|
|
525
527
|
h4: 4 * 60 * 6e4
|
|
526
528
|
};
|
|
529
|
+
var PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES = Object.entries(
|
|
530
|
+
PSYCHOLOGICAL_LEVEL_WINDOWS
|
|
531
|
+
);
|
|
527
532
|
var buildSessionContext = (timestamp) => {
|
|
528
533
|
const date = new Date(timestamp);
|
|
529
534
|
const minuteUtc = date.getUTCHours() * 60 + date.getUTCMinutes();
|
|
530
535
|
const dayOfWeekUtc = date.getUTCDay() || 7;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
536
|
+
let activeSessionCount = 0;
|
|
537
|
+
let asiaActive = false;
|
|
538
|
+
let europeActive = false;
|
|
539
|
+
let usActive = false;
|
|
540
|
+
for (const { name, startMinuteUtc, endMinuteUtc } of SESSION_WINDOWS) {
|
|
541
|
+
const active = startMinuteUtc <= endMinuteUtc ? minuteUtc >= startMinuteUtc && minuteUtc < endMinuteUtc : minuteUtc >= startMinuteUtc || minuteUtc < endMinuteUtc;
|
|
542
|
+
if (!active) continue;
|
|
543
|
+
activeSessionCount += 1;
|
|
544
|
+
if (name === "asia") asiaActive = true;
|
|
545
|
+
if (name === "europe") europeActive = true;
|
|
546
|
+
if (name === "us") usActive = true;
|
|
547
|
+
}
|
|
548
|
+
const sessionPhase = usActive ? "us" : europeActive ? "europe" : asiaActive ? "asia" : "off_hours";
|
|
535
549
|
const primaryWindow = SESSION_WINDOWS.find(
|
|
536
550
|
({ name }) => name === sessionPhase
|
|
537
551
|
);
|
|
@@ -542,7 +556,7 @@ var buildSessionContext = (timestamp) => {
|
|
|
542
556
|
return {
|
|
543
557
|
sessionPhase,
|
|
544
558
|
sessionWindowPhase,
|
|
545
|
-
isOverlap:
|
|
559
|
+
isOverlap: activeSessionCount > 1,
|
|
546
560
|
minutesFromSessionOpen,
|
|
547
561
|
minutesToSessionClose,
|
|
548
562
|
minutesToFundingWindow,
|
|
@@ -596,24 +610,30 @@ var buildPsychologicalLevelWindow = (startPrice, endPrice, stepUsd) => {
|
|
|
596
610
|
var buildPsychologicalLevelAssetContext = (candles, stepUsd) => {
|
|
597
611
|
const endCandle = candles[candles.length - 1];
|
|
598
612
|
if (!endCandle) return null;
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
startCandle
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
613
|
+
const windows = {};
|
|
614
|
+
for (const [window, durationMs] of PSYCHOLOGICAL_LEVEL_WINDOW_ENTRIES) {
|
|
615
|
+
const targetTimestamp = endCandle.timestamp - durationMs;
|
|
616
|
+
let low = 0;
|
|
617
|
+
let high = candles.length - 1;
|
|
618
|
+
let startCandle;
|
|
619
|
+
while (low <= high) {
|
|
620
|
+
const middle = low + high >>> 1;
|
|
621
|
+
const candidate = candles[middle];
|
|
622
|
+
if (candidate.timestamp <= targetTimestamp) {
|
|
623
|
+
if (candidate.timestamp === targetTimestamp) {
|
|
624
|
+
startCandle = candidate;
|
|
625
|
+
}
|
|
626
|
+
low = middle + 1;
|
|
627
|
+
} else {
|
|
628
|
+
high = middle - 1;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
windows[window] = startCandle ? buildPsychologicalLevelWindow(
|
|
632
|
+
startCandle.close,
|
|
633
|
+
endCandle.close,
|
|
634
|
+
stepUsd
|
|
635
|
+
) : unavailablePsychologicalLevelWindow();
|
|
636
|
+
}
|
|
617
637
|
return { source: "aligned_15m_ohlcv", stepUsd, windows };
|
|
618
638
|
};
|
|
619
639
|
var returnPct = (candles) => {
|
|
@@ -7504,35 +7524,34 @@ var buildLiquidityZonesContext = (candles, price, previousPrice, atr2) => {
|
|
|
7504
7524
|
}
|
|
7505
7525
|
const lastIndex = candles.length - 1;
|
|
7506
7526
|
const current = candles[lastIndex];
|
|
7507
|
-
|
|
7527
|
+
let activeCount = 0;
|
|
7528
|
+
let nearestSupport = null;
|
|
7529
|
+
let nearestResistance = null;
|
|
7530
|
+
for (const zone of zones) {
|
|
7508
7531
|
if (lastIndex - zone.startIndex > LIQUIDITY_ZONE_MAX_AGE) {
|
|
7509
|
-
|
|
7532
|
+
continue;
|
|
7510
7533
|
}
|
|
7511
7534
|
const crossed = zone.crossed || (zone.kind === "swing_high_liquidity" ? current.close > zone.top : current.close < zone.bottom);
|
|
7512
7535
|
zone.crossed = crossed;
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
const nearestResistance = resistances.reduce(
|
|
7526
|
-
(nearest, zone) => nearest == null || Math.abs(zone.level - price) < Math.abs(nearest.level - price) ? zone : nearest,
|
|
7527
|
-
null
|
|
7528
|
-
) ?? null;
|
|
7536
|
+
if (crossed) {
|
|
7537
|
+
continue;
|
|
7538
|
+
}
|
|
7539
|
+
activeCount += 1;
|
|
7540
|
+
if (zone.kind === "swing_low_liquidity") {
|
|
7541
|
+
if (nearestSupport == null || Math.abs(price - zone.level) < Math.abs(price - nearestSupport.level)) {
|
|
7542
|
+
nearestSupport = zone;
|
|
7543
|
+
}
|
|
7544
|
+
} else if (nearestResistance == null || Math.abs(zone.level - price) < Math.abs(nearestResistance.level - price)) {
|
|
7545
|
+
nearestResistance = zone;
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7529
7548
|
const supportRetest = nearestSupport != null && current.low <= nearestSupport.top;
|
|
7530
7549
|
const resistanceRetest = nearestResistance != null && current.high >= nearestResistance.bottom;
|
|
7531
7550
|
const retestZone = supportRetest ? nearestSupport : resistanceRetest ? nearestResistance : null;
|
|
7532
7551
|
const retestPenetration = retestZone == null ? null : retestZone.kind === "swing_low_liquidity" ? Math.max(0, retestZone.top - current.low) : Math.max(0, current.high - retestZone.bottom);
|
|
7533
7552
|
const retestHeight = retestZone == null ? null : Math.max(retestZone.top - retestZone.bottom, 0);
|
|
7534
7553
|
return {
|
|
7535
|
-
activeCount
|
|
7554
|
+
activeCount,
|
|
7536
7555
|
nearestSupport: {
|
|
7537
7556
|
top: nearestSupport?.top ?? null,
|
|
7538
7557
|
bottom: nearestSupport?.bottom ?? null,
|
|
@@ -7641,19 +7660,22 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
7641
7660
|
}
|
|
7642
7661
|
const lastIndex = candles.length - 1;
|
|
7643
7662
|
const current = candles[lastIndex];
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7663
|
+
let activeCount = 0;
|
|
7664
|
+
let nearestBuy = null;
|
|
7665
|
+
let nearestSell = null;
|
|
7666
|
+
for (const zone of zones) {
|
|
7667
|
+
if (zone.spent || lastIndex - zone.startIndex > LIQUIDITY_TAIL_MAX_AGE) {
|
|
7668
|
+
continue;
|
|
7669
|
+
}
|
|
7670
|
+
activeCount += 1;
|
|
7671
|
+
if (zone.kind === "buy_pressure") {
|
|
7672
|
+
if (nearestBuy == null || Math.abs(price - zone.mid) < Math.abs(price - nearestBuy.mid)) {
|
|
7673
|
+
nearestBuy = zone;
|
|
7674
|
+
}
|
|
7675
|
+
} else if (nearestSell == null || Math.abs(zone.mid - price) < Math.abs(nearestSell.mid - price)) {
|
|
7676
|
+
nearestSell = zone;
|
|
7677
|
+
}
|
|
7678
|
+
}
|
|
7657
7679
|
const topShadow = current.high - Math.max(current.open, current.close);
|
|
7658
7680
|
const bottomShadow = Math.min(current.open, current.close) - current.low;
|
|
7659
7681
|
const body = Math.max(Math.abs(current.close - current.open), 1e-9);
|
|
@@ -7662,7 +7684,7 @@ var buildLiquidityTailsContext = (candles, price, atr2) => {
|
|
|
7662
7684
|
const dominantWick = dominantUpper ? topShadow : bottomShadow;
|
|
7663
7685
|
const oppositeWick = dominantUpper ? bottomShadow : topShadow;
|
|
7664
7686
|
return {
|
|
7665
|
-
activeCount
|
|
7687
|
+
activeCount,
|
|
7666
7688
|
nearestBuyPressure: {
|
|
7667
7689
|
top: nearestBuy?.top ?? null,
|
|
7668
7690
|
bottom: nearestBuy?.bottom ?? null,
|
|
@@ -9164,6 +9186,7 @@ var BASE_CONTEXT_PSAR_EMA_PERIOD = 50;
|
|
|
9164
9186
|
var BASE_CONTEXT_PSAR_ADX_MIN = 15;
|
|
9165
9187
|
var BASE_CONTEXT_PSAR_COOLDOWN_BARS = 1;
|
|
9166
9188
|
var baseContextEmaKey = (period) => String(period);
|
|
9189
|
+
var sliceCapturedBaseContextTail = (values, length) => values.slice(Math.max(0, length - BASE_CONTEXT_CANDLE_WINDOW), length);
|
|
9167
9190
|
var processLike = globalThis.process;
|
|
9168
9191
|
var INDICATOR_NEXT_PROFILE = processLike?.env?.TRADEJS_INDICATOR_NEXT_PROFILE === "1";
|
|
9169
9192
|
var indicatorNextProfileStats = {
|
|
@@ -10339,7 +10362,6 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
10339
10362
|
let cachedBaseContextSnapshot;
|
|
10340
10363
|
const getCapturedCoinCandles = () => candlesHistory.slice(0, capturedCoinLength);
|
|
10341
10364
|
const getCapturedBtcCandles = () => btcCandlesHistory.slice(0, capturedBtcLength);
|
|
10342
|
-
const getCapturedEthCandles = () => ethCandlesHistory.slice(0, capturedEthLength);
|
|
10343
10365
|
const getCapturedCoinResampled = () => ({
|
|
10344
10366
|
h1: coin1hCache.snapshot(capturedCoin1hLength),
|
|
10345
10367
|
h4: coin4hCache.snapshot(capturedCoin4hLength),
|
|
@@ -10429,12 +10451,30 @@ var createIndicators = (data, btcData = [], options = {}) => {
|
|
|
10429
10451
|
candle: latestCandle,
|
|
10430
10452
|
prevCandle: latestPrevCandle,
|
|
10431
10453
|
baseResult,
|
|
10432
|
-
candlesHistory:
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
|
|
10436
|
-
|
|
10437
|
-
|
|
10454
|
+
candlesHistory: sliceCapturedBaseContextTail(
|
|
10455
|
+
candlesHistory,
|
|
10456
|
+
capturedCoinLength
|
|
10457
|
+
),
|
|
10458
|
+
btcCandlesHistory: sliceCapturedBaseContextTail(
|
|
10459
|
+
btcCandlesHistory,
|
|
10460
|
+
capturedBtcLength
|
|
10461
|
+
),
|
|
10462
|
+
ethCandlesHistory: sliceCapturedBaseContextTail(
|
|
10463
|
+
ethCandlesHistory,
|
|
10464
|
+
capturedEthLength
|
|
10465
|
+
),
|
|
10466
|
+
closeSeries: sliceCapturedBaseContextTail(
|
|
10467
|
+
closes,
|
|
10468
|
+
capturedCoinLength
|
|
10469
|
+
),
|
|
10470
|
+
volumeSeries: sliceCapturedBaseContextTail(
|
|
10471
|
+
volumes,
|
|
10472
|
+
capturedCoinLength
|
|
10473
|
+
),
|
|
10474
|
+
btcCloseSeries: sliceCapturedBaseContextTail(
|
|
10475
|
+
btcCloses,
|
|
10476
|
+
capturedBtcLength
|
|
10477
|
+
),
|
|
10438
10478
|
coinResampledCandles: getCapturedCoinResampled(),
|
|
10439
10479
|
btcResampledCandles: getCapturedBtcResampled(),
|
|
10440
10480
|
ethResampledCandles: getCapturedEthResampled(),
|
|
@@ -11058,8 +11098,8 @@ var getDirectionalTpSlPrices = ({
|
|
|
11058
11098
|
takeProfitPrice,
|
|
11059
11099
|
stopLossPrice
|
|
11060
11100
|
});
|
|
11061
|
-
const
|
|
11062
|
-
const qty = typeof maxLossValue === "number" && Number.isFinite(maxLossValue) && maxLossValue > 0 ?
|
|
11101
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + (Math.abs(price) + Math.abs(stopLossPrice)) * Math.max(0, feePercent);
|
|
11102
|
+
const qty = typeof maxLossValue === "number" && Number.isFinite(maxLossValue) && maxLossValue > 0 ? lossPerUnit > 0 ? maxLossValue / lossPerUnit : 0 : void 0;
|
|
11063
11103
|
return {
|
|
11064
11104
|
stopLossPrice,
|
|
11065
11105
|
takeProfitPrice,
|
package/dist/strategies.mjs
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
createIndicators,
|
|
6
6
|
getRequiredControllerSeedWindow
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-IS72ATRN.mjs";
|
|
8
|
+
import "./chunk-WJQRRGUY.mjs";
|
|
9
9
|
import {
|
|
10
10
|
getTimestamp
|
|
11
11
|
} from "./chunk-S4KHOAXM.mjs";
|
|
@@ -369,8 +369,8 @@ var getDirectionalTpSlPrices = ({
|
|
|
369
369
|
takeProfitPrice,
|
|
370
370
|
stopLossPrice
|
|
371
371
|
});
|
|
372
|
-
const
|
|
373
|
-
const qty = typeof maxLossValue === "number" && Number.isFinite(maxLossValue) && maxLossValue > 0 ?
|
|
372
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + (Math.abs(price) + Math.abs(stopLossPrice)) * Math.max(0, feePercent);
|
|
373
|
+
const qty = typeof maxLossValue === "number" && Number.isFinite(maxLossValue) && maxLossValue > 0 ? lossPerUnit > 0 ? maxLossValue / lossPerUnit : 0 : void 0;
|
|
374
374
|
return {
|
|
375
375
|
stopLossPrice,
|
|
376
376
|
takeProfitPrice,
|
package/dist/trade.mjs
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
normalizeStrategyOrderLinkKey,
|
|
11
11
|
parseStrategyOrderLinkKey,
|
|
12
12
|
slippageBpsToRate
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-V4KXTU6Y.mjs";
|
|
14
|
+
import "./chunk-WJQRRGUY.mjs";
|
|
15
15
|
import "./chunk-MKCQSB4H.mjs";
|
|
16
16
|
export {
|
|
17
17
|
applyExecutionSlippage,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/core",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.28-beta.251",
|
|
4
4
|
"description": "MIT-licensed browser-safe API for TradeJS config, strategy authoring, figures, and shared helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
134
|
"dependencies": {
|
|
135
|
-
"@tradejs/types": "^3.1.
|
|
135
|
+
"@tradejs/types": "^3.1.28-beta.251",
|
|
136
136
|
"date-fns": "^3.6.0",
|
|
137
137
|
"fast-technical-indicators": "^1.1.4",
|
|
138
138
|
"klinecharts": "10.0.0-alpha9",
|