@tradejs/core 1.0.5 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { StrategyConfigGrid, TestSuite, StrategyConfig, PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
2
- export { c as compactOrderLog, g as getTimeline } from './time-DEyFa2vI.mjs';
2
+ export { c as compactOrderLog, g as getTimeline } from './time-BMkFD4Kd.mjs';
3
3
 
4
4
  type GenericConfig = StrategyConfig;
5
5
  declare const generateParamGrid: <T extends StrategyConfig>(paramOptions: StrategyConfigGrid) => T[];
@@ -1,5 +1,5 @@
1
1
  import { StrategyConfigGrid, TestSuite, StrategyConfig, PositionLogData, TestStat, TestThresholdsKey, ThresholdLevel, TestWorkerResult } from '@tradejs/types';
2
- export { c as compactOrderLog, g as getTimeline } from './time-DEyFa2vI.js';
2
+ export { c as compactOrderLog, g as getTimeline } from './time-BMkFD4Kd.js';
3
3
 
4
4
  type GenericConfig = StrategyConfig;
5
5
  declare const generateParamGrid: <T extends StrategyConfig>(paramOptions: StrategyConfigGrid) => T[];
package/dist/backtest.js CHANGED
@@ -50,7 +50,7 @@ module.exports = __toCommonJS(backtest_exports);
50
50
  var import_lodash = __toESM(require("lodash"));
51
51
 
52
52
  // src/constants/index.ts
53
- var BACKTEST_PRELOAD_DAYS = 160;
53
+ var BACKTEST_DEFAULT_DAYS = 160;
54
54
  var TestThresholdsConfig = {
55
55
  // Период и частота — используем как требования к качеству теста, в скоринг не влияют
56
56
  periodDays: {
@@ -189,7 +189,7 @@ var getTimestamp = (days = 0) => {
189
189
  }
190
190
  return (0, import_date_fns2.getUnixTime)(/* @__PURE__ */ new Date()) * 1e3;
191
191
  };
192
- var getTimeline = (start = getTimestamp(BACKTEST_PRELOAD_DAYS), end = getTimestamp(), step = TIMELINE_STEP) => {
192
+ var getTimeline = (start = getTimestamp(BACKTEST_DEFAULT_DAYS), end = getTimestamp(), step = TIMELINE_STEP) => {
193
193
  const res = new Array();
194
194
  for (let ind = start; ind <= end; ind += step) {
195
195
  res.push(ind);
@@ -223,9 +223,9 @@ var compactOrderLog = (timeline, orderLog) => {
223
223
  };
224
224
 
225
225
  // src/utils/uuid.ts
226
- var import_uuid = require("uuid");
226
+ var import_node_crypto = require("crypto");
227
227
  var uuid = (len = 12) => {
228
- const uuid2 = (0, import_uuid.v4)();
228
+ const uuid2 = (0, import_node_crypto.randomUUID)();
229
229
  return uuid2.slice(-len);
230
230
  };
231
231
 
@@ -275,7 +275,7 @@ var mergeConfigs = (configs) => {
275
275
  return result;
276
276
  };
277
277
  var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName) => {
278
- const start = getTimestamp(BACKTEST_PRELOAD_DAYS);
278
+ const start = getTimestamp(BACKTEST_DEFAULT_DAYS);
279
279
  const end = getTimestamp();
280
280
  const testSuiteId = uuid(6);
281
281
  const paramGrid = generateParamGrid(backtestConfig);
package/dist/backtest.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  uuid
3
- } from "./chunk-NQ7D3T4E.mjs";
3
+ } from "./chunk-AJK4NS7Y.mjs";
4
4
  import {
5
5
  absReturns,
6
6
  equityPoints,
@@ -13,11 +13,11 @@ import {
13
13
  compactOrderLog,
14
14
  getTimeline,
15
15
  getTimestamp
16
- } from "./chunk-PXLXXXLA.mjs";
16
+ } from "./chunk-PQETJ42A.mjs";
17
17
  import {
18
- BACKTEST_PRELOAD_DAYS,
18
+ BACKTEST_DEFAULT_DAYS,
19
19
  TestThresholdsConfig
20
- } from "./chunk-JG2QPVAV.mjs";
20
+ } from "./chunk-JLORHLL6.mjs";
21
21
 
22
22
  // src/utils/grid.ts
23
23
  import _ from "lodash";
@@ -66,7 +66,7 @@ var mergeConfigs = (configs) => {
66
66
  return result;
67
67
  };
68
68
  var createTestSuite = (userName, tickers, strategyName, backtestConfig, connectorName) => {
69
- const start = getTimestamp(BACKTEST_PRELOAD_DAYS);
69
+ const start = getTimestamp(BACKTEST_DEFAULT_DAYS);
70
70
  const end = getTimestamp();
71
71
  const testSuiteId = uuid(6);
72
72
  const paramGrid = generateParamGrid(backtestConfig);
@@ -3,12 +3,12 @@ import {
3
3
  } from "./chunk-AYC2QVKI.mjs";
4
4
  import {
5
5
  toMs
6
- } from "./chunk-PXLXXXLA.mjs";
6
+ } from "./chunk-PQETJ42A.mjs";
7
7
  import {
8
8
  CORRELATION_WINDOW,
9
9
  ML_BASE_CANDLES_WINDOW,
10
10
  TRENDLINE_DEFAULTS
11
- } from "./chunk-JG2QPVAV.mjs";
11
+ } from "./chunk-JLORHLL6.mjs";
12
12
  import {
13
13
  cloneArrayValues
14
14
  } from "./chunk-M7QGVZ3J.mjs";
@@ -211,6 +211,235 @@ var coinalyzePointsToRows = (points, interval, source) => points.map((point) =>
211
211
  source
212
212
  }));
213
213
 
214
+ // src/utils/derivativesContext.ts
215
+ var HOUR_MS = 60 * 60 * 1e3;
216
+ var DEFAULT_STALE_AFTER_MS = {
217
+ "15m": 45 * 60 * 1e3,
218
+ "1h": 3 * HOUR_MS
219
+ };
220
+ var DERIVATIVES_INTERVALS = ["15m", "1h"];
221
+ var toFiniteNumberOrNull = (value) => {
222
+ if (typeof value === "number" && Number.isFinite(value)) return value;
223
+ if (typeof value === "string" && value.trim()) {
224
+ const parsed = Number(value);
225
+ return Number.isFinite(parsed) ? parsed : null;
226
+ }
227
+ return null;
228
+ };
229
+ var toTimestampMs = (value) => {
230
+ if (value instanceof Date) {
231
+ const time = value.getTime();
232
+ return Number.isFinite(time) ? time : null;
233
+ }
234
+ const num = toFiniteNumberOrNull(value);
235
+ if (num == null) return null;
236
+ return num > 1e10 ? Math.floor(num) : Math.floor(num * 1e3);
237
+ };
238
+ var roundNullable = (value, digits = 6) => {
239
+ if (value == null || !Number.isFinite(value)) return null;
240
+ const multiplier = 10 ** digits;
241
+ return Math.round(value * multiplier) / multiplier;
242
+ };
243
+ var pctChange = (current, previous) => {
244
+ if (current == null || previous == null || !Number.isFinite(current) || !Number.isFinite(previous) || previous === 0) {
245
+ return null;
246
+ }
247
+ return (current - previous) / Math.abs(previous) * 100;
248
+ };
249
+ var normalizeRows = (rows, timestamp) => (rows ?? []).map((row) => ({
250
+ ...row,
251
+ tsMs: toTimestampMs(row.ts),
252
+ openInterest: toFiniteNumberOrNull(row.openInterest),
253
+ fundingRate: toFiniteNumberOrNull(row.fundingRate),
254
+ liqLong: toFiniteNumberOrNull(row.liqLong),
255
+ liqShort: toFiniteNumberOrNull(row.liqShort),
256
+ liqTotal: toFiniteNumberOrNull(row.liqTotal)
257
+ })).filter((row) => {
258
+ return row.tsMs != null && row.tsMs <= timestamp;
259
+ }).sort((a, b) => a.tsMs - b.tsMs);
260
+ var findRowAtOrBefore = (rows, targetTs) => {
261
+ for (let i = rows.length - 1; i >= 0; i -= 1) {
262
+ if (rows[i].tsMs <= targetTs) {
263
+ return rows[i];
264
+ }
265
+ }
266
+ return null;
267
+ };
268
+ var calculateZScore = (values, current) => {
269
+ const finite = values.filter(
270
+ (value) => typeof value === "number" && Number.isFinite(value)
271
+ );
272
+ if (current == null || finite.length < 3) return null;
273
+ const mean = finite.reduce((sum, value) => sum + value, 0) / finite.length;
274
+ const variance = finite.reduce((sum, value) => sum + (value - mean) ** 2, 0) / finite.length;
275
+ const std = Math.sqrt(variance);
276
+ if (!Number.isFinite(std) || std === 0) return 0;
277
+ return (current - mean) / std;
278
+ };
279
+ var calculateAverage = (values) => {
280
+ const finite = values.filter(
281
+ (value) => typeof value === "number" && Number.isFinite(value)
282
+ );
283
+ if (!finite.length) return null;
284
+ return finite.reduce((sum, value) => sum + value, 0) / finite.length;
285
+ };
286
+ var buildIntervalContext = (params) => {
287
+ const { interval, rows, timestamp, staleAfterMs } = params;
288
+ const normalizedRows = normalizeRows(rows, timestamp);
289
+ const latest = normalizedRows[normalizedRows.length - 1];
290
+ if (!latest) return null;
291
+ const openInterest = latest.openInterest;
292
+ const row1h = findRowAtOrBefore(normalizedRows, latest.tsMs - HOUR_MS);
293
+ const row4h = findRowAtOrBefore(normalizedRows, latest.tsMs - 4 * HOUR_MS);
294
+ const row24h = findRowAtOrBefore(normalizedRows, latest.tsMs - 24 * HOUR_MS);
295
+ const liqLong = latest.liqLong;
296
+ const liqShort = latest.liqShort;
297
+ const liqTotal = latest.liqTotal ?? (liqLong ?? 0) + (liqShort ?? 0);
298
+ const previousLiquidations = normalizedRows.slice(0, -1).map((row) => row.liqTotal ?? (row.liqLong ?? 0) + (row.liqShort ?? 0));
299
+ const avgPreviousLiquidations = calculateAverage(previousLiquidations);
300
+ const liqSpikeRatio = liqTotal != null && avgPreviousLiquidations != null && avgPreviousLiquidations > 0 ? liqTotal / avgPreviousLiquidations : null;
301
+ const liqImbalance = liqTotal != null && liqTotal > 0 ? ((liqShort ?? 0) - (liqLong ?? 0)) / liqTotal : null;
302
+ return {
303
+ interval,
304
+ asOfTs: latest.tsMs,
305
+ stale: timestamp - latest.tsMs > staleAfterMs,
306
+ points: normalizedRows.length,
307
+ openInterest: roundNullable(openInterest),
308
+ oiChangePct1h: roundNullable(
309
+ pctChange(openInterest, row1h?.openInterest ?? null),
310
+ 4
311
+ ),
312
+ oiChangePct4h: roundNullable(
313
+ pctChange(openInterest, row4h?.openInterest ?? null),
314
+ 4
315
+ ),
316
+ oiChangePct24h: roundNullable(
317
+ pctChange(openInterest, row24h?.openInterest ?? null),
318
+ 4
319
+ ),
320
+ fundingRate: roundNullable(latest.fundingRate, 8),
321
+ fundingZScore: roundNullable(
322
+ calculateZScore(
323
+ normalizedRows.map((row) => row.fundingRate),
324
+ latest.fundingRate
325
+ ),
326
+ 4
327
+ ),
328
+ liqLong: roundNullable(liqLong),
329
+ liqShort: roundNullable(liqShort),
330
+ liqTotal: roundNullable(liqTotal),
331
+ liqImbalance: roundNullable(liqImbalance, 4),
332
+ liqSpikeRatio: roundNullable(liqSpikeRatio, 4)
333
+ };
334
+ };
335
+ var getPrimaryContext = (intervals) => intervals["15m"] ?? intervals["1h"] ?? null;
336
+ var isCrowdedLong = (context) => context.fundingRate != null && context.fundingRate >= 5e-4 || context.fundingZScore != null && context.fundingZScore >= 1.5;
337
+ var isCrowdedShort = (context) => context.fundingRate != null && context.fundingRate <= -5e-4 || context.fundingZScore != null && context.fundingZScore <= -1.5;
338
+ var hasLiquidationSpike = (context) => context.liqSpikeRatio != null && context.liqSpikeRatio >= 2;
339
+ var detectPressure = (context) => {
340
+ if (!context) return "neutral";
341
+ if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance <= -0.35) {
342
+ return "long_flush";
343
+ }
344
+ if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance >= 0.35) {
345
+ return "short_flush";
346
+ }
347
+ if (isCrowdedLong(context)) return "crowded_long";
348
+ if (isCrowdedShort(context)) return "crowded_short";
349
+ return "neutral";
350
+ };
351
+ var collectRiskFlags = (contexts) => {
352
+ const flags = /* @__PURE__ */ new Set();
353
+ if (!contexts.length) {
354
+ flags.add("missing_derivatives");
355
+ return [...flags];
356
+ }
357
+ if (contexts.some((context) => context.stale)) {
358
+ flags.add("stale_derivatives");
359
+ }
360
+ for (const context of contexts) {
361
+ if (isCrowdedLong(context)) flags.add("crowded_long");
362
+ if (isCrowdedShort(context)) flags.add("crowded_short");
363
+ if (context.oiChangePct1h != null && context.oiChangePct1h < -1) {
364
+ flags.add("oi_falling");
365
+ }
366
+ if (context.oiChangePct1h != null && Math.abs(context.oiChangePct1h) < 0.15) {
367
+ flags.add("oi_not_confirming");
368
+ }
369
+ if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance <= -0.35) {
370
+ flags.add("long_liquidation_spike");
371
+ }
372
+ if (hasLiquidationSpike(context) && context.liqImbalance != null && context.liqImbalance >= 0.35) {
373
+ flags.add("short_liquidation_spike");
374
+ }
375
+ }
376
+ return [...flags];
377
+ };
378
+ var resolveDirectionAligned = (params) => {
379
+ const { direction, primary, pressure, riskFlags } = params;
380
+ if (!primary || primary.stale || riskFlags.includes("missing_derivatives")) {
381
+ return null;
382
+ }
383
+ if (direction === "LONG") {
384
+ if (pressure === "crowded_long" || riskFlags.includes("oi_falling")) {
385
+ return false;
386
+ }
387
+ if (pressure === "short_flush" || primary.oiChangePct1h != null && primary.oiChangePct1h > 0.25 && !riskFlags.includes("crowded_long")) {
388
+ return true;
389
+ }
390
+ return null;
391
+ }
392
+ if (pressure === "crowded_short" || riskFlags.includes("oi_falling")) {
393
+ return false;
394
+ }
395
+ if (pressure === "long_flush" || primary.oiChangePct1h != null && primary.oiChangePct1h > 0.25 && !riskFlags.includes("crowded_short")) {
396
+ return true;
397
+ }
398
+ return null;
399
+ };
400
+ var buildDerivativesContext = (params) => {
401
+ const {
402
+ symbol,
403
+ direction,
404
+ timestamp,
405
+ rowsByInterval,
406
+ intervals = DERIVATIVES_INTERVALS,
407
+ staleAfterMsByInterval = {}
408
+ } = params;
409
+ const intervalContexts = {};
410
+ for (const interval of intervals) {
411
+ const context = buildIntervalContext({
412
+ interval,
413
+ rows: rowsByInterval[interval],
414
+ timestamp,
415
+ staleAfterMs: staleAfterMsByInterval[interval] ?? DEFAULT_STALE_AFTER_MS[interval]
416
+ });
417
+ if (context) {
418
+ intervalContexts[interval] = context;
419
+ }
420
+ }
421
+ const contexts = Object.values(intervalContexts);
422
+ const primary = getPrimaryContext(intervalContexts);
423
+ const pressure = detectPressure(primary);
424
+ const riskFlags = collectRiskFlags(contexts);
425
+ return {
426
+ source: "coinalyze",
427
+ symbol,
428
+ timestamp,
429
+ intervals: intervalContexts,
430
+ summary: {
431
+ pressure,
432
+ directionAligned: resolveDirectionAligned({
433
+ direction,
434
+ primary,
435
+ pressure,
436
+ riskFlags
437
+ }),
438
+ riskFlags
439
+ }
440
+ };
441
+ };
442
+
214
443
  // src/utils/indicators.ts
215
444
  import { SMA, ATR, BollingerBands, OBV, MACD } from "technicalindicators";
216
445
 
@@ -406,6 +635,17 @@ var DEFAULT_INDICATOR_PERIODS = {
406
635
  levelLookback: 20,
407
636
  levelDelay: 2
408
637
  };
638
+ var resolveIndicatorPeriods = (periods = {}) => {
639
+ const resolved = {
640
+ ...DEFAULT_INDICATOR_PERIODS
641
+ };
642
+ for (const [key, value] of Object.entries(periods)) {
643
+ if (typeof value === "number" && Number.isFinite(value)) {
644
+ resolved[key] = value;
645
+ }
646
+ }
647
+ return resolved;
648
+ };
409
649
  var ONE_HOUR_MS = 36e5;
410
650
  var ONE_DAY_MS = 864e5;
411
651
  var toMlCandle = (candle) => ({
@@ -488,10 +728,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
488
728
  options.pluginRegistryScope
489
729
  );
490
730
  const includeMlPayload = options.includeMlPayload !== false;
491
- const indicatorPeriods = {
492
- ...DEFAULT_INDICATOR_PERIODS,
493
- ...options.periods || {}
494
- };
731
+ const indicatorPeriods = resolveIndicatorPeriods(options.periods);
495
732
  const closes = [];
496
733
  const highs = [];
497
734
  const lows = [];
@@ -820,10 +1057,7 @@ var createIndicators = (data, btcData = [], options = {}) => {
820
1057
  };
821
1058
  var buildMlTimeframeIndicators = (candles, periods = {}) => {
822
1059
  const result = {};
823
- const indicatorPeriods = {
824
- ...DEFAULT_INDICATOR_PERIODS,
825
- ...periods
826
- };
1060
+ const indicatorPeriods = resolveIndicatorPeriods(periods);
827
1061
  for (const timeframe of INDICATOR_TIMEFRAMES) {
828
1062
  const tfCandles = resampleCandles(candles, timeframe.minutes);
829
1063
  if (tfCandles.length === 0) continue;
@@ -1522,8 +1756,14 @@ var createTrendlineEngine = (initialCandles, options) => {
1522
1756
  return result;
1523
1757
  };
1524
1758
  const nextMany = (candles) => {
1525
- let result = [];
1526
- for (const candle of candles) result = next(candle);
1759
+ for (const candle of candles) {
1760
+ appendCandle(candle);
1761
+ }
1762
+ let result = buildResult();
1763
+ if (opts.capture && result.length === 0 && rawExtremaPoints.length) {
1764
+ rebuildCandidatesLikeBatch();
1765
+ result = buildResult();
1766
+ }
1527
1767
  return result;
1528
1768
  };
1529
1769
  const getLines = () => buildResult();
@@ -1548,6 +1788,7 @@ export {
1548
1788
  toArrayData,
1549
1789
  mergeCoinalyzeMetrics,
1550
1790
  coinalyzePointsToRows,
1791
+ buildDerivativesContext,
1551
1792
  registerIndicatorEntries,
1552
1793
  getRegisteredIndicatorEntries,
1553
1794
  getPluginIndicatorCatalog,
@@ -1,7 +1,7 @@
1
1
  // src/utils/uuid.ts
2
- import { v4 as uuidv4 } from "uuid";
2
+ import { randomUUID } from "crypto";
3
3
  var uuid = (len = 12) => {
4
- const uuid2 = uuidv4();
4
+ const uuid2 = randomUUID();
5
5
  return uuid2.slice(-len);
6
6
  };
7
7
 
@@ -4,7 +4,9 @@ var CORRELATION_WINDOW = 50;
4
4
  var SPREAD_WINDOW = 50;
5
5
  var PRELOAD_DAYS = 200;
6
6
  var SIGNALS_PRELOAD_DAYS = 60;
7
- var BACKTEST_PRELOAD_DAYS = 160;
7
+ var SIGNALS_CLI_PRELOAD_DAYS = 10;
8
+ var BACKTEST_DEFAULT_DAYS = 160;
9
+ var BACKTEST_PRELOAD_DAYS = 60;
8
10
  var DASHBOARD_PRELOAD_DAYS = 160;
9
11
  var BOT_PRELOAD_DAYS = 160;
10
12
  var PRELOAD_FALLBACK_DAYS = 160;
@@ -12,6 +14,7 @@ var TTL_1H = 3600;
12
14
  var TTL_3H = 10800;
13
15
  var TTL_12H = 43300;
14
16
  var TTL_1D = 86400;
17
+ var TTL_3D = 259200;
15
18
  var TTL_1M = 26e5;
16
19
  var TTL_3M = 78e5;
17
20
  var TESTS_TOP_LIMIT = 50;
@@ -20,6 +23,10 @@ var TESTS_ORDERS_MIN_LIMIT = 3;
20
23
  var MARKET_CATEGORY = "linear";
21
24
  var ML_CANDLE_FEATURE_WINDOW = 50;
22
25
  var ML_BASE_CANDLES_WINDOW = 50;
26
+ var DERIVATIVES_CONTEXT_REFERENCE_SYMBOLS = [
27
+ "BTCUSDT",
28
+ "ETHUSDT"
29
+ ];
23
30
  var TRENDLINE_DEFAULTS = {
24
31
  maxLines: 20,
25
32
  range: 15,
@@ -169,6 +176,8 @@ export {
169
176
  SPREAD_WINDOW,
170
177
  PRELOAD_DAYS,
171
178
  SIGNALS_PRELOAD_DAYS,
179
+ SIGNALS_CLI_PRELOAD_DAYS,
180
+ BACKTEST_DEFAULT_DAYS,
172
181
  BACKTEST_PRELOAD_DAYS,
173
182
  DASHBOARD_PRELOAD_DAYS,
174
183
  BOT_PRELOAD_DAYS,
@@ -177,6 +186,7 @@ export {
177
186
  TTL_3H,
178
187
  TTL_12H,
179
188
  TTL_1D,
189
+ TTL_3D,
180
190
  TTL_1M,
181
191
  TTL_3M,
182
192
  TESTS_TOP_LIMIT,
@@ -185,6 +195,7 @@ export {
185
195
  MARKET_CATEGORY,
186
196
  ML_CANDLE_FEATURE_WINDOW,
187
197
  ML_BASE_CANDLES_WINDOW,
198
+ DERIVATIVES_CONTEXT_REFERENCE_SYMBOLS,
188
199
  TRENDLINE_DEFAULTS,
189
200
  TestThresholdsConfig
190
201
  };
@@ -1,11 +1,13 @@
1
1
  import {
2
+ BACKTEST_DEFAULT_DAYS,
2
3
  BACKTEST_PRELOAD_DAYS
3
- } from "./chunk-JG2QPVAV.mjs";
4
+ } from "./chunk-JLORHLL6.mjs";
4
5
 
5
6
  // src/utils/timestamp.ts
6
7
  import { format } from "date-fns";
7
8
  import { getUnixTime, subDays } from "date-fns";
8
9
  var TIMELINE_STEP = 864e5;
10
+ var DAY_MS = 864e5;
9
11
  var toMs = (ts) => ts < 1e12 ? ts * 1e3 : ts;
10
12
  var getTimestamp = (days = 0) => {
11
13
  if (days > 0) {
@@ -23,7 +25,8 @@ var getDataTimestamp = (data) => {
23
25
  var formatUnix = (dt) => {
24
26
  return format(new Date(dt), "d MMM u HH:mm:ss");
25
27
  };
26
- var getTimeline = (start = getTimestamp(BACKTEST_PRELOAD_DAYS), end = getTimestamp(), step = TIMELINE_STEP) => {
28
+ var getBacktestPreloadStart = (start, preloadDays = BACKTEST_PRELOAD_DAYS) => Math.max(0, Math.trunc(start - preloadDays * DAY_MS));
29
+ var getTimeline = (start = getTimestamp(BACKTEST_DEFAULT_DAYS), end = getTimestamp(), step = TIMELINE_STEP) => {
27
30
  const res = new Array();
28
31
  for (let ind = start; ind <= end; ind += step) {
29
32
  res.push(ind);
@@ -62,6 +65,7 @@ export {
62
65
  getItemTimestamp,
63
66
  getDataTimestamp,
64
67
  formatUnix,
68
+ getBacktestPreloadStart,
65
69
  getTimeline,
66
70
  compactOrderLog
67
71
  };
package/dist/config.d.mts CHANGED
@@ -1,14 +1,61 @@
1
- import { ConnectorPluginDefinition, IndicatorPluginDefinition, StrategyPluginDefinition } from '@tradejs/types';
1
+ import { Connector, Interval, StrategyConfig, Signal, StrategyManifest, StrategyHookBarContext, StrategyDecision, StrategyHookAfterDecisionContext, ConnectorPluginDefinition, IndicatorPluginDefinition, StrategyPluginDefinition } from '@tradejs/types';
2
2
 
3
3
  type PluginModuleSpecifier = string;
4
+ type StrategyManifestHooks = NonNullable<StrategyManifest['hooks']>;
5
+ type HookOrHooks<THook> = THook | THook[];
6
+ type TradejsConfigAfterCoreDecisionHook = (params: StrategyHookAfterDecisionContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
7
+ type TradejsConfigAfterBarDecisionHook = (params: StrategyHookAfterDecisionContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
8
+ type TradejsConfigOnBarHook = (params: StrategyHookBarContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
9
+ interface TradejsConfigSignalsRuntimeStrategy {
10
+ strategyName: string;
11
+ strategyConfig: StrategyConfig;
12
+ }
13
+ interface TradejsConfigSignalsHookContext {
14
+ connector: Connector;
15
+ connectorName: string;
16
+ userName: string;
17
+ interval: Interval;
18
+ tickers: string[];
19
+ runtimeStrategies: TradejsConfigSignalsRuntimeStrategy[];
20
+ }
21
+ interface TradejsConfigBeforeSignalsHookResult {
22
+ abort?: boolean;
23
+ reason?: string;
24
+ }
25
+ interface TradejsConfigAfterSignalsHookContext extends TradejsConfigSignalsHookContext {
26
+ signals: Signal[];
27
+ status: 'completed' | 'failed';
28
+ durationMs: number;
29
+ }
30
+ type TradejsConfigBeforeSignalsHook = (params: TradejsConfigSignalsHookContext) => Promise<TradejsConfigBeforeSignalsHookResult | void> | TradejsConfigBeforeSignalsHookResult | void;
31
+ type TradejsConfigAfterSignalsHook = (params: TradejsConfigAfterSignalsHookContext) => Promise<void> | void;
32
+ interface TradejsConfigHooks {
33
+ beforeSignals?: HookOrHooks<TradejsConfigBeforeSignalsHook>;
34
+ afterSignals?: HookOrHooks<TradejsConfigAfterSignalsHook>;
35
+ onInit?: HookOrHooks<NonNullable<StrategyManifestHooks['onInit']>>;
36
+ onBar?: HookOrHooks<TradejsConfigOnBarHook>;
37
+ afterCoreDecision?: HookOrHooks<TradejsConfigAfterCoreDecisionHook>;
38
+ afterBarDecision?: HookOrHooks<TradejsConfigAfterBarDecisionHook>;
39
+ onSkip?: HookOrHooks<NonNullable<StrategyManifestHooks['onSkip']>>;
40
+ beforeClosePosition?: HookOrHooks<NonNullable<StrategyManifestHooks['beforeClosePosition']>>;
41
+ afterEnrichMl?: HookOrHooks<NonNullable<StrategyManifestHooks['afterEnrichMl']>>;
42
+ afterEnrichAi?: HookOrHooks<NonNullable<StrategyManifestHooks['afterEnrichAi']>>;
43
+ beforeEntryGate?: HookOrHooks<NonNullable<StrategyManifestHooks['beforeEntryGate']>>;
44
+ beforePlaceOrder?: HookOrHooks<NonNullable<StrategyManifestHooks['beforePlaceOrder']>>;
45
+ afterPlaceOrder?: HookOrHooks<NonNullable<StrategyManifestHooks['afterPlaceOrder']>>;
46
+ onRuntimeError?: HookOrHooks<NonNullable<StrategyManifestHooks['onRuntimeError']>>;
47
+ }
4
48
  interface TradejsConfig {
5
49
  strategies?: PluginModuleSpecifier[];
6
50
  indicators?: PluginModuleSpecifier[];
7
51
  connectors?: PluginModuleSpecifier[];
52
+ hooks?: TradejsConfigHooks;
8
53
  }
54
+ declare const mergeTradejsConfigHooks: (...groups: Array<TradejsConfigHooks | undefined>) => TradejsConfigHooks | undefined;
55
+ declare const normalizeTradejsConfigHooks: (hooks?: TradejsConfigHooks) => TradejsConfigHooks | undefined;
9
56
  declare function defineConfig(...configs: TradejsConfig[]): TradejsConfig;
10
57
  declare const defineStrategyPlugin: <T extends StrategyPluginDefinition>(plugin: T) => T;
11
58
  declare const defineIndicatorPlugin: <T extends IndicatorPluginDefinition>(plugin: T) => T;
12
59
  declare const defineConnectorPlugin: <T extends ConnectorPluginDefinition>(plugin: T) => T;
13
60
 
14
- export { type PluginModuleSpecifier, type TradejsConfig, defineConfig, defineConnectorPlugin, defineIndicatorPlugin, defineStrategyPlugin };
61
+ export { type PluginModuleSpecifier, type TradejsConfig, type TradejsConfigAfterBarDecisionHook, type TradejsConfigAfterCoreDecisionHook, type TradejsConfigAfterSignalsHook, type TradejsConfigAfterSignalsHookContext, type TradejsConfigBeforeSignalsHook, type TradejsConfigBeforeSignalsHookResult, type TradejsConfigHooks, type TradejsConfigOnBarHook, type TradejsConfigSignalsHookContext, type TradejsConfigSignalsRuntimeStrategy, defineConfig, defineConnectorPlugin, defineIndicatorPlugin, defineStrategyPlugin, mergeTradejsConfigHooks, normalizeTradejsConfigHooks };
package/dist/config.d.ts CHANGED
@@ -1,14 +1,61 @@
1
- import { ConnectorPluginDefinition, IndicatorPluginDefinition, StrategyPluginDefinition } from '@tradejs/types';
1
+ import { Connector, Interval, StrategyConfig, Signal, StrategyManifest, StrategyHookBarContext, StrategyDecision, StrategyHookAfterDecisionContext, ConnectorPluginDefinition, IndicatorPluginDefinition, StrategyPluginDefinition } from '@tradejs/types';
2
2
 
3
3
  type PluginModuleSpecifier = string;
4
+ type StrategyManifestHooks = NonNullable<StrategyManifest['hooks']>;
5
+ type HookOrHooks<THook> = THook | THook[];
6
+ type TradejsConfigAfterCoreDecisionHook = (params: StrategyHookAfterDecisionContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
7
+ type TradejsConfigAfterBarDecisionHook = (params: StrategyHookAfterDecisionContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
8
+ type TradejsConfigOnBarHook = (params: StrategyHookBarContext) => Promise<StrategyDecision | void> | StrategyDecision | void;
9
+ interface TradejsConfigSignalsRuntimeStrategy {
10
+ strategyName: string;
11
+ strategyConfig: StrategyConfig;
12
+ }
13
+ interface TradejsConfigSignalsHookContext {
14
+ connector: Connector;
15
+ connectorName: string;
16
+ userName: string;
17
+ interval: Interval;
18
+ tickers: string[];
19
+ runtimeStrategies: TradejsConfigSignalsRuntimeStrategy[];
20
+ }
21
+ interface TradejsConfigBeforeSignalsHookResult {
22
+ abort?: boolean;
23
+ reason?: string;
24
+ }
25
+ interface TradejsConfigAfterSignalsHookContext extends TradejsConfigSignalsHookContext {
26
+ signals: Signal[];
27
+ status: 'completed' | 'failed';
28
+ durationMs: number;
29
+ }
30
+ type TradejsConfigBeforeSignalsHook = (params: TradejsConfigSignalsHookContext) => Promise<TradejsConfigBeforeSignalsHookResult | void> | TradejsConfigBeforeSignalsHookResult | void;
31
+ type TradejsConfigAfterSignalsHook = (params: TradejsConfigAfterSignalsHookContext) => Promise<void> | void;
32
+ interface TradejsConfigHooks {
33
+ beforeSignals?: HookOrHooks<TradejsConfigBeforeSignalsHook>;
34
+ afterSignals?: HookOrHooks<TradejsConfigAfterSignalsHook>;
35
+ onInit?: HookOrHooks<NonNullable<StrategyManifestHooks['onInit']>>;
36
+ onBar?: HookOrHooks<TradejsConfigOnBarHook>;
37
+ afterCoreDecision?: HookOrHooks<TradejsConfigAfterCoreDecisionHook>;
38
+ afterBarDecision?: HookOrHooks<TradejsConfigAfterBarDecisionHook>;
39
+ onSkip?: HookOrHooks<NonNullable<StrategyManifestHooks['onSkip']>>;
40
+ beforeClosePosition?: HookOrHooks<NonNullable<StrategyManifestHooks['beforeClosePosition']>>;
41
+ afterEnrichMl?: HookOrHooks<NonNullable<StrategyManifestHooks['afterEnrichMl']>>;
42
+ afterEnrichAi?: HookOrHooks<NonNullable<StrategyManifestHooks['afterEnrichAi']>>;
43
+ beforeEntryGate?: HookOrHooks<NonNullable<StrategyManifestHooks['beforeEntryGate']>>;
44
+ beforePlaceOrder?: HookOrHooks<NonNullable<StrategyManifestHooks['beforePlaceOrder']>>;
45
+ afterPlaceOrder?: HookOrHooks<NonNullable<StrategyManifestHooks['afterPlaceOrder']>>;
46
+ onRuntimeError?: HookOrHooks<NonNullable<StrategyManifestHooks['onRuntimeError']>>;
47
+ }
4
48
  interface TradejsConfig {
5
49
  strategies?: PluginModuleSpecifier[];
6
50
  indicators?: PluginModuleSpecifier[];
7
51
  connectors?: PluginModuleSpecifier[];
52
+ hooks?: TradejsConfigHooks;
8
53
  }
54
+ declare const mergeTradejsConfigHooks: (...groups: Array<TradejsConfigHooks | undefined>) => TradejsConfigHooks | undefined;
55
+ declare const normalizeTradejsConfigHooks: (hooks?: TradejsConfigHooks) => TradejsConfigHooks | undefined;
9
56
  declare function defineConfig(...configs: TradejsConfig[]): TradejsConfig;
10
57
  declare const defineStrategyPlugin: <T extends StrategyPluginDefinition>(plugin: T) => T;
11
58
  declare const defineIndicatorPlugin: <T extends IndicatorPluginDefinition>(plugin: T) => T;
12
59
  declare const defineConnectorPlugin: <T extends ConnectorPluginDefinition>(plugin: T) => T;
13
60
 
14
- export { type PluginModuleSpecifier, type TradejsConfig, defineConfig, defineConnectorPlugin, defineIndicatorPlugin, defineStrategyPlugin };
61
+ export { type PluginModuleSpecifier, type TradejsConfig, type TradejsConfigAfterBarDecisionHook, type TradejsConfigAfterCoreDecisionHook, type TradejsConfigAfterSignalsHook, type TradejsConfigAfterSignalsHookContext, type TradejsConfigBeforeSignalsHook, type TradejsConfigBeforeSignalsHookResult, type TradejsConfigHooks, type TradejsConfigOnBarHook, type TradejsConfigSignalsHookContext, type TradejsConfigSignalsRuntimeStrategy, defineConfig, defineConnectorPlugin, defineIndicatorPlugin, defineStrategyPlugin, mergeTradejsConfigHooks, normalizeTradejsConfigHooks };