@tradejs/core 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/backtest.mjs +4 -4
- package/dist/chunk-NYJU3J7Y.mjs +265 -0
- package/dist/http.d.mts +8 -0
- package/dist/http.d.ts +8 -0
- package/dist/http.js +79 -0
- package/dist/http.mjs +54 -0
- package/dist/indicators.mjs +2 -2
- package/dist/runtimeTrades.d.mts +82 -0
- package/dist/runtimeTrades.d.ts +82 -0
- package/dist/runtimeTrades.js +577 -0
- package/dist/runtimeTrades.mjs +478 -0
- package/dist/strategies.mjs +2 -2
- package/dist/trade.mjs +14 -250
- package/package.json +12 -2
- package/dist/{chunk-QRRQA4TU.mjs → chunk-OLHUGX7X.mjs} +3 -3
package/README.md
CHANGED
|
@@ -36,6 +36,8 @@ Import only explicit public subpaths:
|
|
|
36
36
|
- `@tradejs/core/constants`
|
|
37
37
|
- `@tradejs/core/data`
|
|
38
38
|
- `@tradejs/core/async`
|
|
39
|
+
- `@tradejs/core/http`
|
|
40
|
+
- `@tradejs/core/runtimeTrades`
|
|
39
41
|
- `@tradejs/core/tickers`
|
|
40
42
|
|
|
41
43
|
There is no root `@tradejs/core` import surface.
|
package/dist/backtest.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compactOrderLog,
|
|
3
|
+
getTimeline
|
|
4
|
+
} from "./chunk-S4KHOAXM.mjs";
|
|
1
5
|
import {
|
|
2
6
|
absReturns,
|
|
3
7
|
equityPoints,
|
|
@@ -6,10 +10,6 @@ import {
|
|
|
6
10
|
round,
|
|
7
11
|
sum
|
|
8
12
|
} from "./chunk-AYC2QVKI.mjs";
|
|
9
|
-
import {
|
|
10
|
-
compactOrderLog,
|
|
11
|
-
getTimeline
|
|
12
|
-
} from "./chunk-S4KHOAXM.mjs";
|
|
13
13
|
import {
|
|
14
14
|
TestThresholdsConfig
|
|
15
15
|
} from "./chunk-MKCQSB4H.mjs";
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import {
|
|
2
|
+
intervalToMs
|
|
3
|
+
} from "./chunk-M7QGVZ3J.mjs";
|
|
4
|
+
import {
|
|
5
|
+
BACKTEST_BASE_SLIPPAGE_BPS,
|
|
6
|
+
BACKTEST_DELAY_RISK_LOOKBACK_CANDLES,
|
|
7
|
+
BACKTEST_DELAY_RISK_MAX_BPS,
|
|
8
|
+
BACKTEST_DELAY_RISK_MULTIPLIER,
|
|
9
|
+
BACKTEST_EXPECTED_DELAY_MS,
|
|
10
|
+
BACKTEST_MARKET_IMPACT_BPS,
|
|
11
|
+
BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER
|
|
12
|
+
} from "./chunk-MKCQSB4H.mjs";
|
|
13
|
+
|
|
14
|
+
// src/utils/executionSlippage.ts
|
|
15
|
+
var toNonNegativeFiniteNumber = (value, fallback = 0) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
16
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
17
|
+
var toRecord = (value) => value && typeof value === "object" ? value : null;
|
|
18
|
+
var getMedian = (values) => {
|
|
19
|
+
if (!values.length) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
23
|
+
const middle = Math.floor(sorted.length / 2);
|
|
24
|
+
if (sorted.length % 2 === 0) {
|
|
25
|
+
const left = sorted[middle - 1];
|
|
26
|
+
const right = sorted[middle];
|
|
27
|
+
return left == null || right == null ? null : (left + right) / 2;
|
|
28
|
+
}
|
|
29
|
+
return sorted[middle] ?? null;
|
|
30
|
+
};
|
|
31
|
+
var extractCandleClose = (value) => {
|
|
32
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
const record = toRecord(value);
|
|
36
|
+
return toFiniteNumberOrNull(record?.close);
|
|
37
|
+
};
|
|
38
|
+
var extractCloseSeries = ({
|
|
39
|
+
closes,
|
|
40
|
+
candles
|
|
41
|
+
}) => {
|
|
42
|
+
const source = Array.isArray(closes) && closes.length ? closes : candles;
|
|
43
|
+
if (!Array.isArray(source)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return source.map(extractCandleClose).filter((value) => value != null && value > 0);
|
|
47
|
+
};
|
|
48
|
+
var getSignalIntervalMs = (interval) => {
|
|
49
|
+
if (typeof interval !== "string") {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return intervalToMs(interval);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var getSignalCandleSeries = (signal) => {
|
|
59
|
+
const indicators = toRecord(signal?.indicators);
|
|
60
|
+
if (!indicators) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const intervalKey = (() => {
|
|
64
|
+
switch (signal?.interval) {
|
|
65
|
+
case "15":
|
|
66
|
+
return "candles15m";
|
|
67
|
+
case "60":
|
|
68
|
+
return "candles1h";
|
|
69
|
+
case "240":
|
|
70
|
+
return "candles4h";
|
|
71
|
+
case "D":
|
|
72
|
+
return "candles1d";
|
|
73
|
+
default:
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
const keys = [
|
|
78
|
+
intervalKey,
|
|
79
|
+
"candles15m",
|
|
80
|
+
"candles1h",
|
|
81
|
+
"candles4h",
|
|
82
|
+
"candles1d"
|
|
83
|
+
].filter((key) => Boolean(key));
|
|
84
|
+
for (const key of keys) {
|
|
85
|
+
const value = indicators[key];
|
|
86
|
+
if (Array.isArray(value) && value.length > 1) {
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const candle = indicators.candle;
|
|
91
|
+
const prevCandle = indicators.prevCandle;
|
|
92
|
+
return prevCandle && candle ? [prevCandle, candle] : null;
|
|
93
|
+
};
|
|
94
|
+
var calculateEffectiveSlippageBps = ({
|
|
95
|
+
baseSlippageBps = BACKTEST_BASE_SLIPPAGE_BPS,
|
|
96
|
+
spreadBps,
|
|
97
|
+
spreadMultiplier = BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER,
|
|
98
|
+
marketImpactBps = BACKTEST_MARKET_IMPACT_BPS,
|
|
99
|
+
delayRiskBps
|
|
100
|
+
} = {}) => {
|
|
101
|
+
const base = toNonNegativeFiniteNumber(baseSlippageBps);
|
|
102
|
+
const spread = toNonNegativeFiniteNumber(spreadBps);
|
|
103
|
+
const multiplier = toNonNegativeFiniteNumber(spreadMultiplier);
|
|
104
|
+
const marketImpact = toNonNegativeFiniteNumber(marketImpactBps);
|
|
105
|
+
const delayRisk = toNonNegativeFiniteNumber(delayRiskBps);
|
|
106
|
+
return base + spread * multiplier + marketImpact + delayRisk;
|
|
107
|
+
};
|
|
108
|
+
var calculateExecutionSlippageBreakdown = ({
|
|
109
|
+
baseSlippageBps = BACKTEST_BASE_SLIPPAGE_BPS,
|
|
110
|
+
spreadBps,
|
|
111
|
+
spreadMultiplier = BACKTEST_SPREAD_SLIPPAGE_MULTIPLIER,
|
|
112
|
+
marketImpactBps = BACKTEST_MARKET_IMPACT_BPS,
|
|
113
|
+
delayRiskBps
|
|
114
|
+
} = {}) => {
|
|
115
|
+
const base = toNonNegativeFiniteNumber(baseSlippageBps);
|
|
116
|
+
const spread = toNonNegativeFiniteNumber(spreadBps);
|
|
117
|
+
const multiplier = toNonNegativeFiniteNumber(spreadMultiplier);
|
|
118
|
+
const spreadSlippage = spread * multiplier;
|
|
119
|
+
const marketImpact = toNonNegativeFiniteNumber(marketImpactBps);
|
|
120
|
+
const delayRisk = toNonNegativeFiniteNumber(delayRiskBps);
|
|
121
|
+
return {
|
|
122
|
+
baseSlippageBps: base,
|
|
123
|
+
spreadBps: spread,
|
|
124
|
+
spreadMultiplier: multiplier,
|
|
125
|
+
spreadSlippageBps: spreadSlippage,
|
|
126
|
+
marketImpactBps: marketImpact,
|
|
127
|
+
delayRiskBps: delayRisk,
|
|
128
|
+
effectiveSlippageBps: base + spreadSlippage + marketImpact + delayRisk
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
var calculateDelayRiskBps = ({
|
|
132
|
+
closes,
|
|
133
|
+
candles,
|
|
134
|
+
intervalMs,
|
|
135
|
+
expectedDelayMs = BACKTEST_EXPECTED_DELAY_MS,
|
|
136
|
+
lookbackCandles = BACKTEST_DELAY_RISK_LOOKBACK_CANDLES,
|
|
137
|
+
multiplier = BACKTEST_DELAY_RISK_MULTIPLIER,
|
|
138
|
+
maxBps = BACKTEST_DELAY_RISK_MAX_BPS
|
|
139
|
+
} = {}) => {
|
|
140
|
+
const normalizedLookback = Math.max(
|
|
141
|
+
1,
|
|
142
|
+
Math.trunc(toNonNegativeFiniteNumber(lookbackCandles, 1))
|
|
143
|
+
);
|
|
144
|
+
const closeSeries = extractCloseSeries({ closes, candles }).slice(
|
|
145
|
+
-(normalizedLookback + 1)
|
|
146
|
+
);
|
|
147
|
+
if (closeSeries.length < 2) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const moveBps = [];
|
|
151
|
+
for (let index = 1; index < closeSeries.length; index += 1) {
|
|
152
|
+
const previous = closeSeries[index - 1];
|
|
153
|
+
const current = closeSeries[index];
|
|
154
|
+
if (previous != null && current != null && previous > 0 && current > 0) {
|
|
155
|
+
moveBps.push(Math.abs(current / previous - 1) * 1e4);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const medianMoveBps = getMedian(moveBps);
|
|
159
|
+
if (medianMoveBps == null) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const delayScale = typeof intervalMs === "number" && Number.isFinite(intervalMs) && intervalMs > 0 && typeof expectedDelayMs === "number" && Number.isFinite(expectedDelayMs) && expectedDelayMs > 0 ? Math.sqrt(expectedDelayMs / intervalMs) : 1;
|
|
163
|
+
const rawDelayRisk = medianMoveBps * delayScale * toNonNegativeFiniteNumber(multiplier);
|
|
164
|
+
const cappedDelayRisk = Math.min(
|
|
165
|
+
rawDelayRisk,
|
|
166
|
+
toNonNegativeFiniteNumber(maxBps, Number.POSITIVE_INFINITY)
|
|
167
|
+
);
|
|
168
|
+
return Number.isFinite(cappedDelayRisk) ? cappedDelayRisk : null;
|
|
169
|
+
};
|
|
170
|
+
var slippageBpsToRate = (slippageBps) => toNonNegativeFiniteNumber(slippageBps) / 1e4;
|
|
171
|
+
var applyExecutionSlippage = ({
|
|
172
|
+
price,
|
|
173
|
+
direction,
|
|
174
|
+
stage,
|
|
175
|
+
...modelParams
|
|
176
|
+
}) => {
|
|
177
|
+
const slippageRate = slippageBpsToRate(
|
|
178
|
+
calculateExecutionSlippageBreakdown(modelParams).effectiveSlippageBps
|
|
179
|
+
);
|
|
180
|
+
if (!slippageRate) {
|
|
181
|
+
return price;
|
|
182
|
+
}
|
|
183
|
+
const sign = direction === "LONG" ? stage === "entry" ? 1 : -1 : stage === "entry" ? -1 : 1;
|
|
184
|
+
return price * (1 + sign * slippageRate);
|
|
185
|
+
};
|
|
186
|
+
var extractExecutionSpreadBps = (signal) => {
|
|
187
|
+
const additionalIndicators = toRecord(signal?.additionalIndicators);
|
|
188
|
+
const explicitSlippage = toRecord(additionalIndicators?.executionSlippage);
|
|
189
|
+
return toFiniteNumberOrNull(explicitSlippage?.spreadBps);
|
|
190
|
+
};
|
|
191
|
+
var extractExecutionMarketImpactBps = (signal) => {
|
|
192
|
+
const additionalIndicators = toRecord(signal?.additionalIndicators);
|
|
193
|
+
const explicitSlippage = toRecord(additionalIndicators?.executionSlippage);
|
|
194
|
+
return toFiniteNumberOrNull(explicitSlippage?.marketImpactBps);
|
|
195
|
+
};
|
|
196
|
+
var extractExecutionDelayRiskBps = (signal) => {
|
|
197
|
+
const additionalIndicators = toRecord(signal?.additionalIndicators);
|
|
198
|
+
const explicitSlippage = toRecord(additionalIndicators?.executionSlippage);
|
|
199
|
+
const explicitDelayRisk = toFiniteNumberOrNull(
|
|
200
|
+
explicitSlippage?.delayRiskBps
|
|
201
|
+
);
|
|
202
|
+
if (explicitDelayRisk != null) {
|
|
203
|
+
return explicitDelayRisk;
|
|
204
|
+
}
|
|
205
|
+
return calculateDelayRiskBps({
|
|
206
|
+
candles: getSignalCandleSeries(signal),
|
|
207
|
+
intervalMs: getSignalIntervalMs(signal?.interval)
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// src/trade.ts
|
|
212
|
+
var ORDER_LINK_PREFIX = "tjs-";
|
|
213
|
+
var ORDER_LINK_SEPARATOR = "--";
|
|
214
|
+
var STRATEGY_SLUG_LENGTH = 10;
|
|
215
|
+
var STRATEGY_HASH_LENGTH = 5;
|
|
216
|
+
var toBase36Hash = (value) => {
|
|
217
|
+
let hash = 0;
|
|
218
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
219
|
+
hash = hash * 31 + value.charCodeAt(index) >>> 0;
|
|
220
|
+
}
|
|
221
|
+
return hash.toString(36).padStart(STRATEGY_HASH_LENGTH, "0");
|
|
222
|
+
};
|
|
223
|
+
var normalizeStrategyOrderLinkKey = (strategyName) => {
|
|
224
|
+
const normalized = String(strategyName ?? "").trim().toLowerCase();
|
|
225
|
+
if (!normalized) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
const slug = normalized.replace(/[^a-z0-9]+/g, "").slice(0, STRATEGY_SLUG_LENGTH) || "strategy";
|
|
229
|
+
const hash = toBase36Hash(normalized).slice(0, STRATEGY_HASH_LENGTH);
|
|
230
|
+
return `${slug}-${hash}`;
|
|
231
|
+
};
|
|
232
|
+
var createRuntimeOrderLinkPrefix = (strategyName) => {
|
|
233
|
+
const strategyKey = normalizeStrategyOrderLinkKey(strategyName);
|
|
234
|
+
return strategyKey ? `${ORDER_LINK_PREFIX}${strategyKey}${ORDER_LINK_SEPARATOR}` : ORDER_LINK_PREFIX;
|
|
235
|
+
};
|
|
236
|
+
var parseStrategyOrderLinkKey = (orderLinkId) => {
|
|
237
|
+
const normalized = String(orderLinkId ?? "").trim().toLowerCase();
|
|
238
|
+
if (!normalized.startsWith(ORDER_LINK_PREFIX)) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const remainder = normalized.slice(ORDER_LINK_PREFIX.length);
|
|
242
|
+
const separatorIndex = remainder.indexOf(ORDER_LINK_SEPARATOR);
|
|
243
|
+
if (separatorIndex <= 0) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const strategyPart = remainder.slice(0, separatorIndex).trim();
|
|
247
|
+
if (!strategyPart) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
return strategyPart;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
export {
|
|
254
|
+
calculateEffectiveSlippageBps,
|
|
255
|
+
calculateExecutionSlippageBreakdown,
|
|
256
|
+
calculateDelayRiskBps,
|
|
257
|
+
slippageBpsToRate,
|
|
258
|
+
applyExecutionSlippage,
|
|
259
|
+
extractExecutionSpreadBps,
|
|
260
|
+
extractExecutionMarketImpactBps,
|
|
261
|
+
extractExecutionDelayRiskBps,
|
|
262
|
+
normalizeStrategyOrderLinkKey,
|
|
263
|
+
createRuntimeOrderLinkPrefix,
|
|
264
|
+
parseStrategyOrderLinkKey
|
|
265
|
+
};
|
package/dist/http.d.mts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type FetchWithRetryOptions = RequestInit & {
|
|
2
|
+
attempts?: number;
|
|
3
|
+
baseDelayMs?: number;
|
|
4
|
+
maxDelayMs?: number;
|
|
5
|
+
};
|
|
6
|
+
declare const fetchWithRetry: (url: string, options?: FetchWithRetryOptions) => Promise<Response>;
|
|
7
|
+
|
|
8
|
+
export { type FetchWithRetryOptions, fetchWithRetry };
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type FetchWithRetryOptions = RequestInit & {
|
|
2
|
+
attempts?: number;
|
|
3
|
+
baseDelayMs?: number;
|
|
4
|
+
maxDelayMs?: number;
|
|
5
|
+
};
|
|
6
|
+
declare const fetchWithRetry: (url: string, options?: FetchWithRetryOptions) => Promise<Response>;
|
|
7
|
+
|
|
8
|
+
export { type FetchWithRetryOptions, fetchWithRetry };
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/http.ts
|
|
21
|
+
var http_exports = {};
|
|
22
|
+
__export(http_exports, {
|
|
23
|
+
fetchWithRetry: () => fetchWithRetry
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(http_exports);
|
|
26
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
var parseRetryAfterMs = (value) => {
|
|
28
|
+
if (!value) return 0;
|
|
29
|
+
const seconds = Number(value);
|
|
30
|
+
if (Number.isFinite(seconds)) {
|
|
31
|
+
return Math.max(0, seconds * 1e3);
|
|
32
|
+
}
|
|
33
|
+
const dateMs = Date.parse(value);
|
|
34
|
+
if (Number.isFinite(dateMs)) {
|
|
35
|
+
return Math.max(0, dateMs - Date.now());
|
|
36
|
+
}
|
|
37
|
+
return 0;
|
|
38
|
+
};
|
|
39
|
+
var fetchWithRetry = async (url, options = {}) => {
|
|
40
|
+
const {
|
|
41
|
+
attempts = 5,
|
|
42
|
+
baseDelayMs = 300,
|
|
43
|
+
maxDelayMs = 5e3,
|
|
44
|
+
...fetchOptions
|
|
45
|
+
} = options;
|
|
46
|
+
let lastError;
|
|
47
|
+
for (let i = 0; i < attempts; i++) {
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(url, fetchOptions);
|
|
50
|
+
if (response.ok) {
|
|
51
|
+
return response;
|
|
52
|
+
}
|
|
53
|
+
const shouldRetry = response.status === 429 || response.status >= 500;
|
|
54
|
+
if (!shouldRetry || i === attempts - 1) {
|
|
55
|
+
return response;
|
|
56
|
+
}
|
|
57
|
+
const retryAfterMs = parseRetryAfterMs(
|
|
58
|
+
response.headers.get("retry-after")
|
|
59
|
+
);
|
|
60
|
+
const backoffMs = Math.min(maxDelayMs, baseDelayMs * 2 ** i);
|
|
61
|
+
await sleep(Math.max(retryAfterMs, backoffMs));
|
|
62
|
+
} catch (error) {
|
|
63
|
+
lastError = error;
|
|
64
|
+
if (i === attempts - 1) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
const backoffMs = Math.min(maxDelayMs, baseDelayMs * 2 ** i);
|
|
68
|
+
await sleep(backoffMs);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (lastError) {
|
|
72
|
+
throw lastError;
|
|
73
|
+
}
|
|
74
|
+
return fetch(url, fetchOptions);
|
|
75
|
+
};
|
|
76
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
77
|
+
0 && (module.exports = {
|
|
78
|
+
fetchWithRetry
|
|
79
|
+
});
|
package/dist/http.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/http.ts
|
|
2
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
var parseRetryAfterMs = (value) => {
|
|
4
|
+
if (!value) return 0;
|
|
5
|
+
const seconds = Number(value);
|
|
6
|
+
if (Number.isFinite(seconds)) {
|
|
7
|
+
return Math.max(0, seconds * 1e3);
|
|
8
|
+
}
|
|
9
|
+
const dateMs = Date.parse(value);
|
|
10
|
+
if (Number.isFinite(dateMs)) {
|
|
11
|
+
return Math.max(0, dateMs - Date.now());
|
|
12
|
+
}
|
|
13
|
+
return 0;
|
|
14
|
+
};
|
|
15
|
+
var fetchWithRetry = async (url, options = {}) => {
|
|
16
|
+
const {
|
|
17
|
+
attempts = 5,
|
|
18
|
+
baseDelayMs = 300,
|
|
19
|
+
maxDelayMs = 5e3,
|
|
20
|
+
...fetchOptions
|
|
21
|
+
} = options;
|
|
22
|
+
let lastError;
|
|
23
|
+
for (let i = 0; i < attempts; i++) {
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch(url, fetchOptions);
|
|
26
|
+
if (response.ok) {
|
|
27
|
+
return response;
|
|
28
|
+
}
|
|
29
|
+
const shouldRetry = response.status === 429 || response.status >= 500;
|
|
30
|
+
if (!shouldRetry || i === attempts - 1) {
|
|
31
|
+
return response;
|
|
32
|
+
}
|
|
33
|
+
const retryAfterMs = parseRetryAfterMs(
|
|
34
|
+
response.headers.get("retry-after")
|
|
35
|
+
);
|
|
36
|
+
const backoffMs = Math.min(maxDelayMs, baseDelayMs * 2 ** i);
|
|
37
|
+
await sleep(Math.max(retryAfterMs, backoffMs));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
lastError = error;
|
|
40
|
+
if (i === attempts - 1) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
const backoffMs = Math.min(maxDelayMs, baseDelayMs * 2 ** i);
|
|
44
|
+
await sleep(backoffMs);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (lastError) {
|
|
48
|
+
throw lastError;
|
|
49
|
+
}
|
|
50
|
+
return fetch(url, fetchOptions);
|
|
51
|
+
};
|
|
52
|
+
export {
|
|
53
|
+
fetchWithRetry
|
|
54
|
+
};
|
package/dist/indicators.mjs
CHANGED
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
toArrayData,
|
|
40
40
|
toCoinalyzeTimestampMs,
|
|
41
41
|
toFiniteNumber
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-OLHUGX7X.mjs";
|
|
43
43
|
import "./chunk-M7QGVZ3J.mjs";
|
|
44
|
-
import "./chunk-AYC2QVKI.mjs";
|
|
45
44
|
import "./chunk-S4KHOAXM.mjs";
|
|
45
|
+
import "./chunk-AYC2QVKI.mjs";
|
|
46
46
|
import "./chunk-MKCQSB4H.mjs";
|
|
47
47
|
export {
|
|
48
48
|
COINALYZE_MIN_INTRADAY_RETENTION_POINTS,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { RuntimeTradeRecord, SimpleOrderLogData, TestStat, RuntimeStrategyTradeSummary, RuntimeStrategyTradeView, MarketUniverse, RuntimeLineage } from '@tradejs/types';
|
|
2
|
+
|
|
3
|
+
declare const resolveStrategyNameByOrderLinkId: ({ orderLinkId, strategyNames, }: {
|
|
4
|
+
orderLinkId: string | null | undefined;
|
|
5
|
+
strategyNames: string[];
|
|
6
|
+
}) => string | null;
|
|
7
|
+
declare const isRuntimeTradeRecord: (value: unknown) => value is RuntimeTradeRecord;
|
|
8
|
+
declare const selectTradesForWindow: (trades: RuntimeTradeRecord[], startTime: number, activeOrderIds?: Set<string>) => RuntimeTradeRecord[];
|
|
9
|
+
declare const buildRuntimeStrategyAnalytics: ({ trades, startTime, endTime, }: {
|
|
10
|
+
trades: RuntimeTradeRecord[];
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime: number;
|
|
13
|
+
}) => {
|
|
14
|
+
orderLog: SimpleOrderLogData;
|
|
15
|
+
stat: TestStat;
|
|
16
|
+
summary: RuntimeStrategyTradeSummary;
|
|
17
|
+
};
|
|
18
|
+
declare const toRuntimeTradeView: (trade: RuntimeTradeRecord, endTime?: number) => RuntimeStrategyTradeView;
|
|
19
|
+
|
|
20
|
+
interface RuntimeStrategyLineageScope {
|
|
21
|
+
strategy: string;
|
|
22
|
+
symbol: string;
|
|
23
|
+
runtimeConfigId?: string;
|
|
24
|
+
lineage: RuntimeLineage & {
|
|
25
|
+
maxLossValue?: number | null;
|
|
26
|
+
};
|
|
27
|
+
firstTimestamp: number;
|
|
28
|
+
lastTimestamp: number;
|
|
29
|
+
}
|
|
30
|
+
interface RuntimeStrategyAiGateChange {
|
|
31
|
+
timestamp: number;
|
|
32
|
+
previousFingerprint: string;
|
|
33
|
+
fingerprint: string;
|
|
34
|
+
}
|
|
35
|
+
interface RuntimeStrategyMaxLossValueChange {
|
|
36
|
+
timestamp: number;
|
|
37
|
+
previousValue: number;
|
|
38
|
+
value: number;
|
|
39
|
+
}
|
|
40
|
+
interface RuntimeStrategyMaxLossValueTimeline {
|
|
41
|
+
observedFrom: number | null;
|
|
42
|
+
initialValue: number | null;
|
|
43
|
+
changes: RuntimeStrategyMaxLossValueChange[];
|
|
44
|
+
}
|
|
45
|
+
interface RuntimeStrategyAccountScope {
|
|
46
|
+
strategyName: string;
|
|
47
|
+
configId: string;
|
|
48
|
+
universe: MarketUniverse;
|
|
49
|
+
accountId?: string;
|
|
50
|
+
}
|
|
51
|
+
declare const buildRuntimeStrategyIdentityKey: ({ strategyName, configId, universe, accountId, deploymentId, policyProfileId, }: {
|
|
52
|
+
strategyName: string;
|
|
53
|
+
configId?: string;
|
|
54
|
+
universe?: MarketUniverse;
|
|
55
|
+
accountId?: string;
|
|
56
|
+
deploymentId?: string;
|
|
57
|
+
policyProfileId?: string;
|
|
58
|
+
}) => string;
|
|
59
|
+
declare const assignLegacyRuntimeTradeAccountScopes: (trades: RuntimeTradeRecord[], scopes: RuntimeStrategyAccountScope[]) => RuntimeTradeRecord[];
|
|
60
|
+
declare const getRuntimeStrategyAiGateObservedFrom: ({ scopes, strategyName, configId, endTime, }: {
|
|
61
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
62
|
+
strategyName: string;
|
|
63
|
+
configId?: string;
|
|
64
|
+
endTime: number;
|
|
65
|
+
}) => number | null;
|
|
66
|
+
declare const buildRuntimeStrategyMaxLossValueTimeline: ({ scopes, strategyName, configId, startTime, endTime, }: {
|
|
67
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
68
|
+
strategyName: string;
|
|
69
|
+
configId?: string;
|
|
70
|
+
startTime: number;
|
|
71
|
+
endTime: number;
|
|
72
|
+
}) => RuntimeStrategyMaxLossValueTimeline;
|
|
73
|
+
declare const isRuntimeStrategyLineageScope: (value: unknown) => value is RuntimeStrategyLineageScope;
|
|
74
|
+
declare const buildRuntimeStrategyAiGateChanges: ({ scopes, strategyName, configId, startTime, endTime, }: {
|
|
75
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
76
|
+
strategyName: string;
|
|
77
|
+
configId?: string;
|
|
78
|
+
startTime: number;
|
|
79
|
+
endTime: number;
|
|
80
|
+
}) => RuntimeStrategyAiGateChange[];
|
|
81
|
+
|
|
82
|
+
export { type RuntimeStrategyAccountScope, type RuntimeStrategyAiGateChange, type RuntimeStrategyLineageScope, type RuntimeStrategyMaxLossValueChange, type RuntimeStrategyMaxLossValueTimeline, assignLegacyRuntimeTradeAccountScopes, buildRuntimeStrategyAiGateChanges, buildRuntimeStrategyAnalytics, buildRuntimeStrategyIdentityKey, buildRuntimeStrategyMaxLossValueTimeline, getRuntimeStrategyAiGateObservedFrom, isRuntimeStrategyLineageScope, isRuntimeTradeRecord, resolveStrategyNameByOrderLinkId, selectTradesForWindow, toRuntimeTradeView };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { RuntimeTradeRecord, SimpleOrderLogData, TestStat, RuntimeStrategyTradeSummary, RuntimeStrategyTradeView, MarketUniverse, RuntimeLineage } from '@tradejs/types';
|
|
2
|
+
|
|
3
|
+
declare const resolveStrategyNameByOrderLinkId: ({ orderLinkId, strategyNames, }: {
|
|
4
|
+
orderLinkId: string | null | undefined;
|
|
5
|
+
strategyNames: string[];
|
|
6
|
+
}) => string | null;
|
|
7
|
+
declare const isRuntimeTradeRecord: (value: unknown) => value is RuntimeTradeRecord;
|
|
8
|
+
declare const selectTradesForWindow: (trades: RuntimeTradeRecord[], startTime: number, activeOrderIds?: Set<string>) => RuntimeTradeRecord[];
|
|
9
|
+
declare const buildRuntimeStrategyAnalytics: ({ trades, startTime, endTime, }: {
|
|
10
|
+
trades: RuntimeTradeRecord[];
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime: number;
|
|
13
|
+
}) => {
|
|
14
|
+
orderLog: SimpleOrderLogData;
|
|
15
|
+
stat: TestStat;
|
|
16
|
+
summary: RuntimeStrategyTradeSummary;
|
|
17
|
+
};
|
|
18
|
+
declare const toRuntimeTradeView: (trade: RuntimeTradeRecord, endTime?: number) => RuntimeStrategyTradeView;
|
|
19
|
+
|
|
20
|
+
interface RuntimeStrategyLineageScope {
|
|
21
|
+
strategy: string;
|
|
22
|
+
symbol: string;
|
|
23
|
+
runtimeConfigId?: string;
|
|
24
|
+
lineage: RuntimeLineage & {
|
|
25
|
+
maxLossValue?: number | null;
|
|
26
|
+
};
|
|
27
|
+
firstTimestamp: number;
|
|
28
|
+
lastTimestamp: number;
|
|
29
|
+
}
|
|
30
|
+
interface RuntimeStrategyAiGateChange {
|
|
31
|
+
timestamp: number;
|
|
32
|
+
previousFingerprint: string;
|
|
33
|
+
fingerprint: string;
|
|
34
|
+
}
|
|
35
|
+
interface RuntimeStrategyMaxLossValueChange {
|
|
36
|
+
timestamp: number;
|
|
37
|
+
previousValue: number;
|
|
38
|
+
value: number;
|
|
39
|
+
}
|
|
40
|
+
interface RuntimeStrategyMaxLossValueTimeline {
|
|
41
|
+
observedFrom: number | null;
|
|
42
|
+
initialValue: number | null;
|
|
43
|
+
changes: RuntimeStrategyMaxLossValueChange[];
|
|
44
|
+
}
|
|
45
|
+
interface RuntimeStrategyAccountScope {
|
|
46
|
+
strategyName: string;
|
|
47
|
+
configId: string;
|
|
48
|
+
universe: MarketUniverse;
|
|
49
|
+
accountId?: string;
|
|
50
|
+
}
|
|
51
|
+
declare const buildRuntimeStrategyIdentityKey: ({ strategyName, configId, universe, accountId, deploymentId, policyProfileId, }: {
|
|
52
|
+
strategyName: string;
|
|
53
|
+
configId?: string;
|
|
54
|
+
universe?: MarketUniverse;
|
|
55
|
+
accountId?: string;
|
|
56
|
+
deploymentId?: string;
|
|
57
|
+
policyProfileId?: string;
|
|
58
|
+
}) => string;
|
|
59
|
+
declare const assignLegacyRuntimeTradeAccountScopes: (trades: RuntimeTradeRecord[], scopes: RuntimeStrategyAccountScope[]) => RuntimeTradeRecord[];
|
|
60
|
+
declare const getRuntimeStrategyAiGateObservedFrom: ({ scopes, strategyName, configId, endTime, }: {
|
|
61
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
62
|
+
strategyName: string;
|
|
63
|
+
configId?: string;
|
|
64
|
+
endTime: number;
|
|
65
|
+
}) => number | null;
|
|
66
|
+
declare const buildRuntimeStrategyMaxLossValueTimeline: ({ scopes, strategyName, configId, startTime, endTime, }: {
|
|
67
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
68
|
+
strategyName: string;
|
|
69
|
+
configId?: string;
|
|
70
|
+
startTime: number;
|
|
71
|
+
endTime: number;
|
|
72
|
+
}) => RuntimeStrategyMaxLossValueTimeline;
|
|
73
|
+
declare const isRuntimeStrategyLineageScope: (value: unknown) => value is RuntimeStrategyLineageScope;
|
|
74
|
+
declare const buildRuntimeStrategyAiGateChanges: ({ scopes, strategyName, configId, startTime, endTime, }: {
|
|
75
|
+
scopes: RuntimeStrategyLineageScope[];
|
|
76
|
+
strategyName: string;
|
|
77
|
+
configId?: string;
|
|
78
|
+
startTime: number;
|
|
79
|
+
endTime: number;
|
|
80
|
+
}) => RuntimeStrategyAiGateChange[];
|
|
81
|
+
|
|
82
|
+
export { type RuntimeStrategyAccountScope, type RuntimeStrategyAiGateChange, type RuntimeStrategyLineageScope, type RuntimeStrategyMaxLossValueChange, type RuntimeStrategyMaxLossValueTimeline, assignLegacyRuntimeTradeAccountScopes, buildRuntimeStrategyAiGateChanges, buildRuntimeStrategyAnalytics, buildRuntimeStrategyIdentityKey, buildRuntimeStrategyMaxLossValueTimeline, getRuntimeStrategyAiGateObservedFrom, isRuntimeStrategyLineageScope, isRuntimeTradeRecord, resolveStrategyNameByOrderLinkId, selectTradesForWindow, toRuntimeTradeView };
|