@tradejs/cli 3.1.29-beta.285 → 3.1.29-beta.287
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/cli.js +647 -486
- package/dist/lib/mcpReplayProcess.js +4 -2
- package/dist/lib/strategyResearch.js +24 -11
- package/dist/scripts/mcpWorker.js +4 -2
- package/dist/scripts/replay.js +644 -498
- package/dist/scripts/replayRunner.js +646 -498
- package/dist/scripts/strategyResearch.js +24 -11
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -15259,6 +15259,513 @@ var init_backtest = __esm({
|
|
|
15259
15259
|
}
|
|
15260
15260
|
});
|
|
15261
15261
|
|
|
15262
|
+
// src/lib/runtimeModeConfig.ts
|
|
15263
|
+
var hasRuntimeEntryGateEnabled, resolveReplayStrategyEnv, buildRuntimeModeStrategyConfig;
|
|
15264
|
+
var init_runtimeModeConfig = __esm({
|
|
15265
|
+
"src/lib/runtimeModeConfig.ts"() {
|
|
15266
|
+
"use strict";
|
|
15267
|
+
hasRuntimeEntryGateEnabled = (strategyConfig) => strategyConfig.AI_ENABLED === true || strategyConfig.ML_ENABLED === true;
|
|
15268
|
+
resolveReplayStrategyEnv = ({
|
|
15269
|
+
strategyConfig,
|
|
15270
|
+
forceRuntimeGates = false
|
|
15271
|
+
}) => forceRuntimeGates || hasRuntimeEntryGateEnabled(strategyConfig) ? "PARITY" : "BACKTEST";
|
|
15272
|
+
buildRuntimeModeStrategyConfig = ({
|
|
15273
|
+
strategyConfig,
|
|
15274
|
+
env,
|
|
15275
|
+
interval: interval4,
|
|
15276
|
+
makeOrders,
|
|
15277
|
+
recordRuntimeTrades,
|
|
15278
|
+
aiReplayAnalyses
|
|
15279
|
+
}) => ({
|
|
15280
|
+
...strategyConfig,
|
|
15281
|
+
ENV: env,
|
|
15282
|
+
MAKE_ORDERS: makeOrders,
|
|
15283
|
+
INTERVAL: strategyConfig.INTERVAL ?? interval4,
|
|
15284
|
+
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
15285
|
+
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
15286
|
+
});
|
|
15287
|
+
}
|
|
15288
|
+
});
|
|
15289
|
+
|
|
15290
|
+
// src/lib/replay/support.ts
|
|
15291
|
+
var import_chalk16, REPLAY_RESULTS_BY_STRATEGY_HEADERS, REPLAY_RUNTIME_COMPARISON_HEADERS, REPLAY_RESULTS_CONFIG, REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS, REPLAY_RUNTIME_COMPARE_TOLERANCE_MS, formatReplayRuntimeCompareTolerance, getReplayRuntimeUnmatchedCount, buildReplayStrategyConfig, toRecord, compactReplayAdditionalIndicators, compactReplaySignal;
|
|
15292
|
+
var init_support = __esm({
|
|
15293
|
+
"src/lib/replay/support.ts"() {
|
|
15294
|
+
"use strict";
|
|
15295
|
+
import_chalk16 = __toESM(require("chalk"));
|
|
15296
|
+
init_runtimeModeConfig();
|
|
15297
|
+
REPLAY_RESULTS_BY_STRATEGY_HEADERS = [
|
|
15298
|
+
import_chalk16.default.blue("STRATEGY"),
|
|
15299
|
+
import_chalk16.default.yellow("TICKERS"),
|
|
15300
|
+
import_chalk16.default.yellow("TRADE TICKERS"),
|
|
15301
|
+
import_chalk16.default.cyan("ORDERS"),
|
|
15302
|
+
import_chalk16.default.cyan("WIN/LOSS (%)"),
|
|
15303
|
+
import_chalk16.default.cyan("PROFIT"),
|
|
15304
|
+
import_chalk16.default.cyan("AVG TRADE")
|
|
15305
|
+
];
|
|
15306
|
+
REPLAY_RUNTIME_COMPARISON_HEADERS = [
|
|
15307
|
+
import_chalk16.default.blue("STRATEGY"),
|
|
15308
|
+
import_chalk16.default.cyan("BT ENTRIES"),
|
|
15309
|
+
import_chalk16.default.cyan("BT PNL"),
|
|
15310
|
+
import_chalk16.default.yellow("RT TRADES"),
|
|
15311
|
+
import_chalk16.default.yellow("RT PNL"),
|
|
15312
|
+
import_chalk16.default.green("MATCHED"),
|
|
15313
|
+
import_chalk16.default.red("ORDER FAILED"),
|
|
15314
|
+
import_chalk16.default.yellow("RT ONLY"),
|
|
15315
|
+
import_chalk16.default.magenta("BT ONLY"),
|
|
15316
|
+
import_chalk16.default.red("UNMATCHED")
|
|
15317
|
+
];
|
|
15318
|
+
REPLAY_RESULTS_CONFIG = "replay";
|
|
15319
|
+
REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS = 1;
|
|
15320
|
+
REPLAY_RUNTIME_COMPARE_TOLERANCE_MS = REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS * 15 * 60 * 1e3;
|
|
15321
|
+
formatReplayRuntimeCompareTolerance = () => `${REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS} ${REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS === 1 ? "bar" : "bars"}`;
|
|
15322
|
+
getReplayRuntimeUnmatchedCount = (row) => row.orderFailed + row.runtimeOnly + row.backtestOnly;
|
|
15323
|
+
buildReplayStrategyConfig = ({
|
|
15324
|
+
strategyConfig,
|
|
15325
|
+
interval: interval4
|
|
15326
|
+
}) => ({
|
|
15327
|
+
...buildRuntimeModeStrategyConfig({
|
|
15328
|
+
strategyConfig,
|
|
15329
|
+
env: "PARITY",
|
|
15330
|
+
interval: interval4,
|
|
15331
|
+
makeOrders: false,
|
|
15332
|
+
recordRuntimeTrades: false
|
|
15333
|
+
}),
|
|
15334
|
+
SIMULATE_ORDERS: true
|
|
15335
|
+
});
|
|
15336
|
+
toRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
15337
|
+
compactReplayAdditionalIndicators = (additionalIndicators) => {
|
|
15338
|
+
const additional = toRecord(additionalIndicators);
|
|
15339
|
+
if (!additional) {
|
|
15340
|
+
return void 0;
|
|
15341
|
+
}
|
|
15342
|
+
const compact = {};
|
|
15343
|
+
if (additional.executionSlippage != null) {
|
|
15344
|
+
compact.executionSlippage = additional.executionSlippage;
|
|
15345
|
+
}
|
|
15346
|
+
if (additional.marketContext != null) {
|
|
15347
|
+
compact.marketContext = additional.marketContext;
|
|
15348
|
+
}
|
|
15349
|
+
const baseContext = toRecord(additional.baseContext);
|
|
15350
|
+
const relative = toRecord(baseContext?.relative);
|
|
15351
|
+
const execution = toRecord(relative?.execution);
|
|
15352
|
+
if (execution) {
|
|
15353
|
+
compact.baseContext = {
|
|
15354
|
+
relative: {
|
|
15355
|
+
execution
|
|
15356
|
+
}
|
|
15357
|
+
};
|
|
15358
|
+
}
|
|
15359
|
+
return Object.keys(compact).length ? compact : void 0;
|
|
15360
|
+
};
|
|
15361
|
+
compactReplaySignal = (signal) => {
|
|
15362
|
+
if (!signal) {
|
|
15363
|
+
return void 0;
|
|
15364
|
+
}
|
|
15365
|
+
return {
|
|
15366
|
+
signalId: signal.signalId,
|
|
15367
|
+
strategy: signal.strategy,
|
|
15368
|
+
symbol: signal.symbol,
|
|
15369
|
+
interval: signal.interval,
|
|
15370
|
+
direction: signal.direction,
|
|
15371
|
+
timestamp: signal.timestamp,
|
|
15372
|
+
prices: signal.prices,
|
|
15373
|
+
indicators: {},
|
|
15374
|
+
figures: {},
|
|
15375
|
+
additionalIndicators: compactReplayAdditionalIndicators(
|
|
15376
|
+
signal.additionalIndicators
|
|
15377
|
+
),
|
|
15378
|
+
isConfigFromBacktest: signal.isConfigFromBacktest,
|
|
15379
|
+
...signal.orderStatus ? { orderStatus: signal.orderStatus } : {},
|
|
15380
|
+
...signal.orderSkipReason ? { orderSkipReason: signal.orderSkipReason } : {},
|
|
15381
|
+
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
|
|
15382
|
+
...signal.ml ? { ml: signal.ml } : {}
|
|
15383
|
+
};
|
|
15384
|
+
};
|
|
15385
|
+
}
|
|
15386
|
+
});
|
|
15387
|
+
|
|
15388
|
+
// src/lib/marketData/windows.ts
|
|
15389
|
+
var import_indicators2, resolveOpenTimestamp, getClosedCandlesForInterval, splitCandlesForReplayWindow, alignSymbolWithBtcReference;
|
|
15390
|
+
var init_windows = __esm({
|
|
15391
|
+
"src/lib/marketData/windows.ts"() {
|
|
15392
|
+
"use strict";
|
|
15393
|
+
import_indicators2 = require("@tradejs/core/indicators");
|
|
15394
|
+
resolveOpenTimestamp = (timestamp, intervalMs) => Number.isFinite(intervalMs) && intervalMs > 0 ? Math.floor(timestamp / intervalMs) * intervalMs : timestamp;
|
|
15395
|
+
getClosedCandlesForInterval = (candles, currentTimestamp, intervalMs) => {
|
|
15396
|
+
const currentOpenTimestamp = resolveOpenTimestamp(
|
|
15397
|
+
currentTimestamp,
|
|
15398
|
+
intervalMs
|
|
15399
|
+
);
|
|
15400
|
+
return candles.filter((candle) => candle.timestamp < currentOpenTimestamp);
|
|
15401
|
+
};
|
|
15402
|
+
splitCandlesForReplayWindow = (candles, start, preloadStart) => {
|
|
15403
|
+
const prevData = [];
|
|
15404
|
+
const replayData = [];
|
|
15405
|
+
for (const candle of candles) {
|
|
15406
|
+
if (candle.timestamp < preloadStart) {
|
|
15407
|
+
continue;
|
|
15408
|
+
}
|
|
15409
|
+
if (candle.timestamp < start) {
|
|
15410
|
+
prevData.push(candle);
|
|
15411
|
+
continue;
|
|
15412
|
+
}
|
|
15413
|
+
replayData.push(candle);
|
|
15414
|
+
}
|
|
15415
|
+
return { prevData, replayData };
|
|
15416
|
+
};
|
|
15417
|
+
alignSymbolWithBtcReference = (symbolCandles, btcCandles) => (0, import_indicators2.alignSortedCandlesByTimestamp)(symbolCandles, btcCandles);
|
|
15418
|
+
}
|
|
15419
|
+
});
|
|
15420
|
+
|
|
15421
|
+
// src/lib/replay/historicalSignalsReplayPreparation.ts
|
|
15422
|
+
var import_data2, buildPreparedData, strategyIncludesSymbol, buildSymbolSharedReplayKey, resolveHistoricalReplayIntervals, prepareMultiIntervalHistoricalReplay, assertBaseReplayCoverage, prepareHistoricalReplay, releaseHistoricalReplayPlan, releaseHistoricalReplayCaches;
|
|
15423
|
+
var init_historicalSignalsReplayPreparation = __esm({
|
|
15424
|
+
"src/lib/replay/historicalSignalsReplayPreparation.ts"() {
|
|
15425
|
+
"use strict";
|
|
15426
|
+
import_data2 = require("@tradejs/core/data");
|
|
15427
|
+
init_support();
|
|
15428
|
+
init_windows();
|
|
15429
|
+
buildPreparedData = ({
|
|
15430
|
+
data,
|
|
15431
|
+
btcData,
|
|
15432
|
+
ethData,
|
|
15433
|
+
btcBinanceData,
|
|
15434
|
+
btcCoinbaseData,
|
|
15435
|
+
start,
|
|
15436
|
+
preloadStart
|
|
15437
|
+
}) => {
|
|
15438
|
+
const { prevData: prevDataRaw, replayData: replayDataRaw } = splitCandlesForReplayWindow(data, start, preloadStart);
|
|
15439
|
+
const { prevData: btcPrevDataRaw, replayData: btcReplayDataRaw } = splitCandlesForReplayWindow(btcData, start, preloadStart);
|
|
15440
|
+
const { prevData: ethPrevDataRaw, replayData: ethReplayDataRaw } = splitCandlesForReplayWindow(ethData, start, preloadStart);
|
|
15441
|
+
const { prevData: btcBinancePrevDataRaw } = splitCandlesForReplayWindow(
|
|
15442
|
+
btcBinanceData,
|
|
15443
|
+
start,
|
|
15444
|
+
preloadStart
|
|
15445
|
+
);
|
|
15446
|
+
const { prevData: btcCoinbasePrevDataRaw } = splitCandlesForReplayWindow(
|
|
15447
|
+
btcCoinbaseData,
|
|
15448
|
+
start,
|
|
15449
|
+
preloadStart
|
|
15450
|
+
);
|
|
15451
|
+
const { alignedCoinCandles: prevData, alignedBtcCandles: btcPrevData } = alignSymbolWithBtcReference(prevDataRaw, btcPrevDataRaw);
|
|
15452
|
+
const { alignedCoinCandles: replayData, alignedBtcCandles: btcReplayData } = alignSymbolWithBtcReference(replayDataRaw, btcReplayDataRaw);
|
|
15453
|
+
const { alignedBtcCandles: ethPrevData } = alignSymbolWithBtcReference(
|
|
15454
|
+
prevData,
|
|
15455
|
+
ethPrevDataRaw
|
|
15456
|
+
);
|
|
15457
|
+
const { alignedBtcCandles: ethReplayData } = alignSymbolWithBtcReference(
|
|
15458
|
+
replayData,
|
|
15459
|
+
ethReplayDataRaw
|
|
15460
|
+
);
|
|
15461
|
+
const { alignedBtcCandles: btcBinancePrevData } = alignSymbolWithBtcReference(
|
|
15462
|
+
prevDataRaw,
|
|
15463
|
+
btcBinancePrevDataRaw
|
|
15464
|
+
);
|
|
15465
|
+
const { alignedBtcCandles: btcCoinbasePrevData } = alignSymbolWithBtcReference(prevDataRaw, btcCoinbasePrevDataRaw);
|
|
15466
|
+
return {
|
|
15467
|
+
prevData,
|
|
15468
|
+
btcPrevData,
|
|
15469
|
+
ethPrevData,
|
|
15470
|
+
replayData,
|
|
15471
|
+
btcReplayData,
|
|
15472
|
+
ethReplayData,
|
|
15473
|
+
btcBinancePrevData,
|
|
15474
|
+
btcCoinbasePrevData
|
|
15475
|
+
};
|
|
15476
|
+
};
|
|
15477
|
+
strategyIncludesSymbol = (strategy, symbol) => {
|
|
15478
|
+
const tickers = strategy.selection?.tickers;
|
|
15479
|
+
if (!tickers) return true;
|
|
15480
|
+
const normalizedSymbol = symbol.trim().toUpperCase();
|
|
15481
|
+
return tickers.some(
|
|
15482
|
+
(ticker) => ticker.trim().toUpperCase() === normalizedSymbol
|
|
15483
|
+
);
|
|
15484
|
+
};
|
|
15485
|
+
buildSymbolSharedReplayKey = ({
|
|
15486
|
+
userName: userName3,
|
|
15487
|
+
connectorName,
|
|
15488
|
+
interval: interval4,
|
|
15489
|
+
symbol,
|
|
15490
|
+
start,
|
|
15491
|
+
end
|
|
15492
|
+
}) => ["replay", userName3, connectorName, symbol, interval4, start, end].join(":");
|
|
15493
|
+
resolveHistoricalReplayIntervals = (baseInterval, strategyIntervals) => {
|
|
15494
|
+
const intervals = [
|
|
15495
|
+
...new Set(
|
|
15496
|
+
strategyIntervals.map((value) => {
|
|
15497
|
+
if (!value || !Number.isFinite((0, import_data2.intervalToMs)(value)) || (0, import_data2.intervalToMs)(value) <= 0)
|
|
15498
|
+
throw new Error(`Invalid replay strategy interval: ${value}`);
|
|
15499
|
+
return value;
|
|
15500
|
+
})
|
|
15501
|
+
)
|
|
15502
|
+
].sort((a, b) => (0, import_data2.intervalToMs)(a) - (0, import_data2.intervalToMs)(b));
|
|
15503
|
+
if (intervals.length > 1 && intervals.includes("M")) {
|
|
15504
|
+
throw new Error("Mixed replay does not support calendar intervals");
|
|
15505
|
+
}
|
|
15506
|
+
const baseMs = (0, import_data2.intervalToMs)(baseInterval);
|
|
15507
|
+
if (intervals.some(
|
|
15508
|
+
(value) => (0, import_data2.intervalToMs)(value) < baseMs || (0, import_data2.intervalToMs)(value) % baseMs !== 0
|
|
15509
|
+
)) {
|
|
15510
|
+
throw new Error(
|
|
15511
|
+
"Replay strategy intervals must be multiples of the base timeframe"
|
|
15512
|
+
);
|
|
15513
|
+
}
|
|
15514
|
+
if (!intervals.length || !intervals.includes(baseInterval)) {
|
|
15515
|
+
throw new Error(
|
|
15516
|
+
"Replay base timeframe must match an active strategy interval"
|
|
15517
|
+
);
|
|
15518
|
+
}
|
|
15519
|
+
return intervals;
|
|
15520
|
+
};
|
|
15521
|
+
prepareMultiIntervalHistoricalReplay = async (context, adapters, loadReferences) => {
|
|
15522
|
+
const intervals = resolveHistoricalReplayIntervals(
|
|
15523
|
+
context.interval,
|
|
15524
|
+
context.strategies.map((s) => s.strategyConfig.INTERVAL)
|
|
15525
|
+
);
|
|
15526
|
+
const baseMs = (0, import_data2.intervalToMs)(context.interval);
|
|
15527
|
+
const plan = {
|
|
15528
|
+
symbolRuntimes: [],
|
|
15529
|
+
orderedTimestamps: [],
|
|
15530
|
+
sharedReplayKeyPrefixes: [],
|
|
15531
|
+
runtimeLineages: []
|
|
15532
|
+
};
|
|
15533
|
+
const timestamps = /* @__PURE__ */ new Set();
|
|
15534
|
+
const baseRuntimes = /* @__PURE__ */ new Map();
|
|
15535
|
+
const validatedSymbols = /* @__PURE__ */ new Set();
|
|
15536
|
+
try {
|
|
15537
|
+
for (const interval4 of intervals) {
|
|
15538
|
+
const offset = (0, import_data2.intervalToMs)(interval4) - baseMs;
|
|
15539
|
+
const nativeRun = {
|
|
15540
|
+
...context.preparedRun,
|
|
15541
|
+
preloadStart: context.preparedRun.preloadStart - offset,
|
|
15542
|
+
window: {
|
|
15543
|
+
...context.preparedRun.window,
|
|
15544
|
+
start: context.preparedRun.window.start - offset,
|
|
15545
|
+
end: context.preparedRun.window.end - offset
|
|
15546
|
+
}
|
|
15547
|
+
};
|
|
15548
|
+
const part = await prepareHistoricalReplay(
|
|
15549
|
+
{
|
|
15550
|
+
...context,
|
|
15551
|
+
interval: interval4,
|
|
15552
|
+
preparedRun: nativeRun,
|
|
15553
|
+
strategies: context.strategies.filter(
|
|
15554
|
+
(strategy) => strategy.strategyConfig.INTERVAL === interval4
|
|
15555
|
+
),
|
|
15556
|
+
references: interval4 === context.interval ? context.references : await loadReferences(interval4, nativeRun)
|
|
15557
|
+
},
|
|
15558
|
+
adapters
|
|
15559
|
+
);
|
|
15560
|
+
plan.sharedReplayKeyPrefixes.push(...part.sharedReplayKeyPrefixes);
|
|
15561
|
+
plan.runtimeLineages.push(...part.runtimeLineages);
|
|
15562
|
+
for (const runtime of part.symbolRuntimes) {
|
|
15563
|
+
if (interval4 === context.interval) {
|
|
15564
|
+
baseRuntimes.set(runtime.symbol, runtime);
|
|
15565
|
+
} else if (runtime.strategies.length && !validatedSymbols.has(runtime.symbol)) {
|
|
15566
|
+
assertBaseReplayCoverage(
|
|
15567
|
+
baseRuntimes.get(runtime.symbol),
|
|
15568
|
+
runtime.symbol,
|
|
15569
|
+
context.preparedRun.window,
|
|
15570
|
+
baseMs
|
|
15571
|
+
);
|
|
15572
|
+
validatedSymbols.add(runtime.symbol);
|
|
15573
|
+
}
|
|
15574
|
+
runtime.timestampOffsetMs = offset;
|
|
15575
|
+
runtime.advanceMarket = interval4 === context.interval;
|
|
15576
|
+
plan.symbolRuntimes.push(runtime);
|
|
15577
|
+
}
|
|
15578
|
+
for (const timestamp of part.orderedTimestamps) {
|
|
15579
|
+
const scheduled = timestamp + offset;
|
|
15580
|
+
if (scheduled >= context.preparedRun.window.start && scheduled <= context.preparedRun.window.end)
|
|
15581
|
+
timestamps.add(scheduled);
|
|
15582
|
+
}
|
|
15583
|
+
}
|
|
15584
|
+
plan.orderedTimestamps = [...timestamps].sort((a, b) => a - b);
|
|
15585
|
+
return plan;
|
|
15586
|
+
} catch (error) {
|
|
15587
|
+
releaseHistoricalReplayCaches(plan, adapters);
|
|
15588
|
+
throw error;
|
|
15589
|
+
}
|
|
15590
|
+
};
|
|
15591
|
+
assertBaseReplayCoverage = (runtime, symbol, window, baseMs) => {
|
|
15592
|
+
let index = 0;
|
|
15593
|
+
for (let timestamp = Math.ceil(window.start / baseMs) * baseMs; timestamp <= window.end; timestamp += baseMs) {
|
|
15594
|
+
if (runtime?.replayData[index]?.timestamp !== timestamp) {
|
|
15595
|
+
throw new Error(`Missing base replay candle: ${symbol} at ${timestamp}`);
|
|
15596
|
+
}
|
|
15597
|
+
index += 1;
|
|
15598
|
+
}
|
|
15599
|
+
};
|
|
15600
|
+
prepareHistoricalReplay = async (context, adapters) => {
|
|
15601
|
+
const {
|
|
15602
|
+
userName: userName3,
|
|
15603
|
+
projectRoot: projectRoot18,
|
|
15604
|
+
preparedRun,
|
|
15605
|
+
interval: interval4,
|
|
15606
|
+
connectorName,
|
|
15607
|
+
replayConnector,
|
|
15608
|
+
strategies,
|
|
15609
|
+
references
|
|
15610
|
+
} = context;
|
|
15611
|
+
const symbolRuntimes = [];
|
|
15612
|
+
const orderedTimestamps = /* @__PURE__ */ new Set();
|
|
15613
|
+
const sharedReplayKeyPrefixes = [];
|
|
15614
|
+
const runtimeLineages = [];
|
|
15615
|
+
let skippedSymbols = 0;
|
|
15616
|
+
try {
|
|
15617
|
+
for (const symbol of preparedRun.tickers) {
|
|
15618
|
+
const data = await preparedRun.marketConnector.kline({
|
|
15619
|
+
symbol,
|
|
15620
|
+
start: preparedRun.preloadStart,
|
|
15621
|
+
end: preparedRun.window.end,
|
|
15622
|
+
cacheOnly: true,
|
|
15623
|
+
interval: interval4
|
|
15624
|
+
});
|
|
15625
|
+
if (symbolRuntimes.length % 50 === 0)
|
|
15626
|
+
adapters.sampleMemory?.("history:loaded", {
|
|
15627
|
+
symbols: symbolRuntimes.length + 1,
|
|
15628
|
+
candles: data.length
|
|
15629
|
+
});
|
|
15630
|
+
const preparedData = buildPreparedData({
|
|
15631
|
+
data,
|
|
15632
|
+
btcData: references.btcMarketData,
|
|
15633
|
+
ethData: references.ethMarketData,
|
|
15634
|
+
btcBinanceData: references.btcBinanceData,
|
|
15635
|
+
btcCoinbaseData: references.btcCoinbaseData,
|
|
15636
|
+
start: preparedRun.window.start,
|
|
15637
|
+
preloadStart: preparedRun.preloadStart
|
|
15638
|
+
});
|
|
15639
|
+
if (!preparedData.replayData.length || !preparedData.btcReplayData.length) {
|
|
15640
|
+
skippedSymbols += 1;
|
|
15641
|
+
adapters.progress.tick({
|
|
15642
|
+
skipped: adapters.display.skipped(skippedSymbols),
|
|
15643
|
+
symbol: adapters.display.symbol(symbol)
|
|
15644
|
+
});
|
|
15645
|
+
continue;
|
|
15646
|
+
}
|
|
15647
|
+
const sharedIndicatorsReplayKey = buildSymbolSharedReplayKey({
|
|
15648
|
+
userName: userName3,
|
|
15649
|
+
connectorName,
|
|
15650
|
+
interval: interval4,
|
|
15651
|
+
symbol,
|
|
15652
|
+
start: preparedRun.window.start,
|
|
15653
|
+
end: preparedRun.window.end
|
|
15654
|
+
});
|
|
15655
|
+
sharedReplayKeyPrefixes.push(sharedIndicatorsReplayKey);
|
|
15656
|
+
const initializedStrategies = await Promise.allSettled(
|
|
15657
|
+
strategies.filter((strategy) => strategyIncludesSymbol(strategy, symbol)).map(async (strategy) => {
|
|
15658
|
+
const replayStrategyConfig = buildReplayStrategyConfig({
|
|
15659
|
+
strategyConfig: strategy.strategyConfig,
|
|
15660
|
+
interval: interval4
|
|
15661
|
+
});
|
|
15662
|
+
const runtimeLineage = await adapters.buildLineage({
|
|
15663
|
+
projectRoot: projectRoot18,
|
|
15664
|
+
strategyName: strategy.strategyName,
|
|
15665
|
+
strategyRevision: strategy.strategyRevision,
|
|
15666
|
+
deploymentCompositionId: strategy.deploymentCompositionId,
|
|
15667
|
+
strategyPackageVersion: strategy.strategyPackageVersion,
|
|
15668
|
+
strategyDependencyVersions: strategy.strategyDependencyVersions,
|
|
15669
|
+
runtimePackageVersion: strategy.runtimePackageVersion,
|
|
15670
|
+
config: {
|
|
15671
|
+
configId: strategy.strategyRevision,
|
|
15672
|
+
strategyConfig: strategy.strategyConfig,
|
|
15673
|
+
symbolResultConfig: strategy.strategyResults?.[symbol]?.config ?? null
|
|
15674
|
+
},
|
|
15675
|
+
runContext: {
|
|
15676
|
+
connectorName: connectorName.toLowerCase(),
|
|
15677
|
+
interval: String(interval4),
|
|
15678
|
+
universe: preparedRun.universe ?? null
|
|
15679
|
+
}
|
|
15680
|
+
});
|
|
15681
|
+
runtimeLineages.push({
|
|
15682
|
+
strategy: strategy.strategyName,
|
|
15683
|
+
symbol,
|
|
15684
|
+
...preparedRun.deploymentId ? { deploymentId: preparedRun.deploymentId } : {},
|
|
15685
|
+
...preparedRun.accountId ? { accountId: preparedRun.accountId } : {},
|
|
15686
|
+
lineage: runtimeLineage
|
|
15687
|
+
});
|
|
15688
|
+
return {
|
|
15689
|
+
strategyName: strategy.strategyName,
|
|
15690
|
+
strategyConfig: strategy.strategyConfig,
|
|
15691
|
+
runtimeLineage,
|
|
15692
|
+
run: await strategy.strategyCreator({
|
|
15693
|
+
userName: userName3,
|
|
15694
|
+
connectorName,
|
|
15695
|
+
runtimeConfigId: strategy.strategyRevision,
|
|
15696
|
+
strategyRevision: strategy.strategyRevision,
|
|
15697
|
+
runtimeLineage,
|
|
15698
|
+
universe: preparedRun.universe,
|
|
15699
|
+
accountId: preparedRun.accountId,
|
|
15700
|
+
deploymentId: preparedRun.deploymentId,
|
|
15701
|
+
runtimeConfigSnapshot: {
|
|
15702
|
+
userConfig: replayStrategyConfig
|
|
15703
|
+
},
|
|
15704
|
+
config: replayStrategyConfig,
|
|
15705
|
+
symbol,
|
|
15706
|
+
data: preparedData.prevData,
|
|
15707
|
+
btcData: preparedData.btcPrevData,
|
|
15708
|
+
ethData: preparedData.ethPrevData,
|
|
15709
|
+
btcBinanceData: preparedData.btcBinancePrevData,
|
|
15710
|
+
btcCoinbaseData: preparedData.btcCoinbasePrevData,
|
|
15711
|
+
connector: replayConnector,
|
|
15712
|
+
sharedIndicatorsReplayKey
|
|
15713
|
+
})
|
|
15714
|
+
};
|
|
15715
|
+
})
|
|
15716
|
+
);
|
|
15717
|
+
const strategiesForSymbol = initializedStrategies.map((result) => {
|
|
15718
|
+
if (result.status === "rejected") throw result.reason;
|
|
15719
|
+
return result.value;
|
|
15720
|
+
});
|
|
15721
|
+
const symbolRuntime = {
|
|
15722
|
+
symbol,
|
|
15723
|
+
replayData: preparedData.replayData,
|
|
15724
|
+
btcReplayData: preparedData.btcReplayData,
|
|
15725
|
+
ethReplayData: preparedData.ethReplayData,
|
|
15726
|
+
currentIndex: 0,
|
|
15727
|
+
strategies: strategiesForSymbol
|
|
15728
|
+
};
|
|
15729
|
+
symbolRuntimes.push(symbolRuntime);
|
|
15730
|
+
if (symbolRuntimes.length % 50 === 0 || symbol === preparedRun.tickers.at(-1))
|
|
15731
|
+
adapters.sampleMemory?.("strategies:initializing", {
|
|
15732
|
+
symbols: symbolRuntimes.length,
|
|
15733
|
+
strategiesPerSymbol: strategiesForSymbol.length
|
|
15734
|
+
});
|
|
15735
|
+
adapters.progress.tick({
|
|
15736
|
+
skipped: adapters.display.skipped(skippedSymbols),
|
|
15737
|
+
symbol: adapters.display.symbol(symbol)
|
|
15738
|
+
});
|
|
15739
|
+
for (const candle of preparedData.replayData) {
|
|
15740
|
+
orderedTimestamps.add(candle.timestamp);
|
|
15741
|
+
}
|
|
15742
|
+
}
|
|
15743
|
+
return {
|
|
15744
|
+
symbolRuntimes,
|
|
15745
|
+
orderedTimestamps: [...orderedTimestamps].sort(
|
|
15746
|
+
(left, right) => left - right
|
|
15747
|
+
),
|
|
15748
|
+
sharedReplayKeyPrefixes,
|
|
15749
|
+
runtimeLineages
|
|
15750
|
+
};
|
|
15751
|
+
} catch (error) {
|
|
15752
|
+
releaseHistoricalReplayCaches({ sharedReplayKeyPrefixes }, adapters);
|
|
15753
|
+
throw error;
|
|
15754
|
+
}
|
|
15755
|
+
};
|
|
15756
|
+
releaseHistoricalReplayPlan = (plan) => {
|
|
15757
|
+
plan.symbolRuntimes.length = 0;
|
|
15758
|
+
plan.sharedReplayKeyPrefixes.length = 0;
|
|
15759
|
+
};
|
|
15760
|
+
releaseHistoricalReplayCaches = (plan, adapters) => {
|
|
15761
|
+
for (const keyPrefix of plan.sharedReplayKeyPrefixes) {
|
|
15762
|
+
adapters.releaseIndicatorsCache(keyPrefix);
|
|
15763
|
+
adapters.releaseReplayCache(keyPrefix);
|
|
15764
|
+
}
|
|
15765
|
+
};
|
|
15766
|
+
}
|
|
15767
|
+
});
|
|
15768
|
+
|
|
15262
15769
|
// src/lib/replay/cliConfig.ts
|
|
15263
15770
|
var import_args7, REPLAY_UNSUPPORTED_FLAGS, hasCliFlag2, assertNoUnsupportedReplayFlags, replayNormalizedArgv, replayFlags, replayInterval, replayUserName, replayProjectRoot, replayRuntimeEvidencePath, replayDeploymentId, isReplayUpdateOnlyRun;
|
|
15264
15771
|
var init_cliConfig2 = __esm({
|
|
@@ -15636,149 +16143,23 @@ var init_runtimeEvidenceSource = __esm({
|
|
|
15636
16143
|
assertRuntimeRowsMatchDeployment({
|
|
15637
16144
|
label: "evaluation",
|
|
15638
16145
|
rows: evaluations,
|
|
15639
|
-
deployment
|
|
15640
|
-
});
|
|
15641
|
-
assertRuntimeRowsMatchDeployment({
|
|
15642
|
-
label: "lineage scope",
|
|
15643
|
-
rows: storedLineageScopes,
|
|
15644
|
-
deployment
|
|
15645
|
-
});
|
|
15646
|
-
return {
|
|
15647
|
-
path: resolvedPath,
|
|
15648
|
-
userName: userName3,
|
|
15649
|
-
startTime,
|
|
15650
|
-
endTime,
|
|
15651
|
-
trades,
|
|
15652
|
-
signals: signals2,
|
|
15653
|
-
evaluations,
|
|
15654
|
-
lineageScopes: storedLineageScopes.length ? storedLineageScopes : buildRuntimeEvidenceLineageScopes({ signals: signals2, evaluations }),
|
|
15655
|
-
deployment
|
|
15656
|
-
};
|
|
15657
|
-
};
|
|
15658
|
-
}
|
|
15659
|
-
});
|
|
15660
|
-
|
|
15661
|
-
// src/lib/runtimeModeConfig.ts
|
|
15662
|
-
var hasRuntimeEntryGateEnabled, resolveReplayStrategyEnv, buildRuntimeModeStrategyConfig;
|
|
15663
|
-
var init_runtimeModeConfig = __esm({
|
|
15664
|
-
"src/lib/runtimeModeConfig.ts"() {
|
|
15665
|
-
"use strict";
|
|
15666
|
-
hasRuntimeEntryGateEnabled = (strategyConfig) => strategyConfig.AI_ENABLED === true || strategyConfig.ML_ENABLED === true;
|
|
15667
|
-
resolveReplayStrategyEnv = ({
|
|
15668
|
-
strategyConfig,
|
|
15669
|
-
forceRuntimeGates = false
|
|
15670
|
-
}) => forceRuntimeGates || hasRuntimeEntryGateEnabled(strategyConfig) ? "PARITY" : "BACKTEST";
|
|
15671
|
-
buildRuntimeModeStrategyConfig = ({
|
|
15672
|
-
strategyConfig,
|
|
15673
|
-
env,
|
|
15674
|
-
interval: interval4,
|
|
15675
|
-
makeOrders,
|
|
15676
|
-
recordRuntimeTrades,
|
|
15677
|
-
aiReplayAnalyses
|
|
15678
|
-
}) => ({
|
|
15679
|
-
...strategyConfig,
|
|
15680
|
-
ENV: env,
|
|
15681
|
-
MAKE_ORDERS: makeOrders,
|
|
15682
|
-
INTERVAL: strategyConfig.INTERVAL ?? interval4,
|
|
15683
|
-
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
15684
|
-
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
15685
|
-
});
|
|
15686
|
-
}
|
|
15687
|
-
});
|
|
15688
|
-
|
|
15689
|
-
// src/lib/replay/support.ts
|
|
15690
|
-
var import_chalk16, REPLAY_RESULTS_BY_STRATEGY_HEADERS, REPLAY_RUNTIME_COMPARISON_HEADERS, REPLAY_RESULTS_CONFIG, REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS, REPLAY_RUNTIME_COMPARE_TOLERANCE_MS, formatReplayRuntimeCompareTolerance, getReplayRuntimeUnmatchedCount, buildReplayStrategyConfig, toRecord, compactReplayAdditionalIndicators, compactReplaySignal;
|
|
15691
|
-
var init_support = __esm({
|
|
15692
|
-
"src/lib/replay/support.ts"() {
|
|
15693
|
-
"use strict";
|
|
15694
|
-
import_chalk16 = __toESM(require("chalk"));
|
|
15695
|
-
init_runtimeModeConfig();
|
|
15696
|
-
REPLAY_RESULTS_BY_STRATEGY_HEADERS = [
|
|
15697
|
-
import_chalk16.default.blue("STRATEGY"),
|
|
15698
|
-
import_chalk16.default.yellow("TICKERS"),
|
|
15699
|
-
import_chalk16.default.yellow("TRADE TICKERS"),
|
|
15700
|
-
import_chalk16.default.cyan("ORDERS"),
|
|
15701
|
-
import_chalk16.default.cyan("WIN/LOSS (%)"),
|
|
15702
|
-
import_chalk16.default.cyan("PROFIT"),
|
|
15703
|
-
import_chalk16.default.cyan("AVG TRADE")
|
|
15704
|
-
];
|
|
15705
|
-
REPLAY_RUNTIME_COMPARISON_HEADERS = [
|
|
15706
|
-
import_chalk16.default.blue("STRATEGY"),
|
|
15707
|
-
import_chalk16.default.cyan("BT ENTRIES"),
|
|
15708
|
-
import_chalk16.default.cyan("BT PNL"),
|
|
15709
|
-
import_chalk16.default.yellow("RT TRADES"),
|
|
15710
|
-
import_chalk16.default.yellow("RT PNL"),
|
|
15711
|
-
import_chalk16.default.green("MATCHED"),
|
|
15712
|
-
import_chalk16.default.red("ORDER FAILED"),
|
|
15713
|
-
import_chalk16.default.yellow("RT ONLY"),
|
|
15714
|
-
import_chalk16.default.magenta("BT ONLY"),
|
|
15715
|
-
import_chalk16.default.red("UNMATCHED")
|
|
15716
|
-
];
|
|
15717
|
-
REPLAY_RESULTS_CONFIG = "replay";
|
|
15718
|
-
REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS = 1;
|
|
15719
|
-
REPLAY_RUNTIME_COMPARE_TOLERANCE_MS = REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS * 15 * 60 * 1e3;
|
|
15720
|
-
formatReplayRuntimeCompareTolerance = () => `${REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS} ${REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS === 1 ? "bar" : "bars"}`;
|
|
15721
|
-
getReplayRuntimeUnmatchedCount = (row) => row.orderFailed + row.runtimeOnly + row.backtestOnly;
|
|
15722
|
-
buildReplayStrategyConfig = ({
|
|
15723
|
-
strategyConfig,
|
|
15724
|
-
interval: interval4
|
|
15725
|
-
}) => ({
|
|
15726
|
-
...buildRuntimeModeStrategyConfig({
|
|
15727
|
-
strategyConfig,
|
|
15728
|
-
env: "PARITY",
|
|
15729
|
-
interval: interval4,
|
|
15730
|
-
makeOrders: false,
|
|
15731
|
-
recordRuntimeTrades: false
|
|
15732
|
-
}),
|
|
15733
|
-
SIMULATE_ORDERS: true
|
|
15734
|
-
});
|
|
15735
|
-
toRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
15736
|
-
compactReplayAdditionalIndicators = (additionalIndicators) => {
|
|
15737
|
-
const additional = toRecord(additionalIndicators);
|
|
15738
|
-
if (!additional) {
|
|
15739
|
-
return void 0;
|
|
15740
|
-
}
|
|
15741
|
-
const compact = {};
|
|
15742
|
-
if (additional.executionSlippage != null) {
|
|
15743
|
-
compact.executionSlippage = additional.executionSlippage;
|
|
15744
|
-
}
|
|
15745
|
-
if (additional.marketContext != null) {
|
|
15746
|
-
compact.marketContext = additional.marketContext;
|
|
15747
|
-
}
|
|
15748
|
-
const baseContext = toRecord(additional.baseContext);
|
|
15749
|
-
const relative = toRecord(baseContext?.relative);
|
|
15750
|
-
const execution = toRecord(relative?.execution);
|
|
15751
|
-
if (execution) {
|
|
15752
|
-
compact.baseContext = {
|
|
15753
|
-
relative: {
|
|
15754
|
-
execution
|
|
15755
|
-
}
|
|
15756
|
-
};
|
|
15757
|
-
}
|
|
15758
|
-
return Object.keys(compact).length ? compact : void 0;
|
|
15759
|
-
};
|
|
15760
|
-
compactReplaySignal = (signal) => {
|
|
15761
|
-
if (!signal) {
|
|
15762
|
-
return void 0;
|
|
15763
|
-
}
|
|
16146
|
+
deployment
|
|
16147
|
+
});
|
|
16148
|
+
assertRuntimeRowsMatchDeployment({
|
|
16149
|
+
label: "lineage scope",
|
|
16150
|
+
rows: storedLineageScopes,
|
|
16151
|
+
deployment
|
|
16152
|
+
});
|
|
15764
16153
|
return {
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
additionalIndicators: compactReplayAdditionalIndicators(
|
|
15775
|
-
signal.additionalIndicators
|
|
15776
|
-
),
|
|
15777
|
-
isConfigFromBacktest: signal.isConfigFromBacktest,
|
|
15778
|
-
...signal.orderStatus ? { orderStatus: signal.orderStatus } : {},
|
|
15779
|
-
...signal.orderSkipReason ? { orderSkipReason: signal.orderSkipReason } : {},
|
|
15780
|
-
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
|
|
15781
|
-
...signal.ml ? { ml: signal.ml } : {}
|
|
16154
|
+
path: resolvedPath,
|
|
16155
|
+
userName: userName3,
|
|
16156
|
+
startTime,
|
|
16157
|
+
endTime,
|
|
16158
|
+
trades,
|
|
16159
|
+
signals: signals2,
|
|
16160
|
+
evaluations,
|
|
16161
|
+
lineageScopes: storedLineageScopes.length ? storedLineageScopes : buildRuntimeEvidenceLineageScopes({ signals: signals2, evaluations }),
|
|
16162
|
+
deployment
|
|
15782
16163
|
};
|
|
15783
16164
|
};
|
|
15784
16165
|
}
|
|
@@ -15846,6 +16227,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
15846
16227
|
createPortfolioReplayConnector = (connector) => {
|
|
15847
16228
|
let state = {};
|
|
15848
16229
|
let amount = import_constants10.INITIAL_BACKTEST_AMOUNT;
|
|
16230
|
+
let executionTimestamp = null;
|
|
15849
16231
|
const positionsBySymbol = /* @__PURE__ */ new Map();
|
|
15850
16232
|
const currentPriceBySymbol = /* @__PURE__ */ new Map();
|
|
15851
16233
|
const orderLog = [];
|
|
@@ -16107,6 +16489,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
16107
16489
|
});
|
|
16108
16490
|
const nextPosition = {
|
|
16109
16491
|
...order,
|
|
16492
|
+
timestamp: executionTimestamp ?? order.timestamp,
|
|
16110
16493
|
price: entryPrice,
|
|
16111
16494
|
signal: compactReplaySignal(order.signal),
|
|
16112
16495
|
amount,
|
|
@@ -16131,6 +16514,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
16131
16514
|
positionState,
|
|
16132
16515
|
data: {
|
|
16133
16516
|
...order,
|
|
16517
|
+
timestamp: executionTimestamp ?? order.timestamp,
|
|
16134
16518
|
price: entryPrice,
|
|
16135
16519
|
profit,
|
|
16136
16520
|
fee,
|
|
@@ -16194,6 +16578,7 @@ var init_portfolioReplayConnector = __esm({
|
|
|
16194
16578
|
positionState,
|
|
16195
16579
|
data: {
|
|
16196
16580
|
...order,
|
|
16581
|
+
timestamp: executionTimestamp ?? order.timestamp,
|
|
16197
16582
|
price: executionPrice,
|
|
16198
16583
|
qty: position.qty,
|
|
16199
16584
|
profit,
|
|
@@ -16202,11 +16587,12 @@ var init_portfolioReplayConnector = __esm({
|
|
|
16202
16587
|
...getExecutionSlippageLogData(slippageBreakdown, "exit")
|
|
16203
16588
|
}
|
|
16204
16589
|
});
|
|
16205
|
-
clearPosition(order.symbol, order.timestamp);
|
|
16590
|
+
clearPosition(order.symbol, executionTimestamp ?? order.timestamp);
|
|
16206
16591
|
return true;
|
|
16207
16592
|
},
|
|
16208
16593
|
getTickers: connector.getTickers,
|
|
16209
16594
|
advanceMarket: async ({ symbol, candle }) => {
|
|
16595
|
+
executionTimestamp = candle.timestamp;
|
|
16210
16596
|
currentPriceBySymbol.set(symbol, candle.close);
|
|
16211
16597
|
await checkSl({ symbol, candle });
|
|
16212
16598
|
await checkTp({ symbol, candle });
|
|
@@ -16255,270 +16641,12 @@ var init_hooks = __esm({
|
|
|
16255
16641
|
}
|
|
16256
16642
|
});
|
|
16257
16643
|
|
|
16258
|
-
// src/lib/marketData/windows.ts
|
|
16259
|
-
var import_indicators2, resolveOpenTimestamp, getClosedCandlesForInterval, splitCandlesForReplayWindow, alignSymbolWithBtcReference;
|
|
16260
|
-
var init_windows = __esm({
|
|
16261
|
-
"src/lib/marketData/windows.ts"() {
|
|
16262
|
-
"use strict";
|
|
16263
|
-
import_indicators2 = require("@tradejs/core/indicators");
|
|
16264
|
-
resolveOpenTimestamp = (timestamp, intervalMs) => Number.isFinite(intervalMs) && intervalMs > 0 ? Math.floor(timestamp / intervalMs) * intervalMs : timestamp;
|
|
16265
|
-
getClosedCandlesForInterval = (candles, currentTimestamp, intervalMs) => {
|
|
16266
|
-
const currentOpenTimestamp = resolveOpenTimestamp(
|
|
16267
|
-
currentTimestamp,
|
|
16268
|
-
intervalMs
|
|
16269
|
-
);
|
|
16270
|
-
return candles.filter((candle) => candle.timestamp < currentOpenTimestamp);
|
|
16271
|
-
};
|
|
16272
|
-
splitCandlesForReplayWindow = (candles, start, preloadStart) => {
|
|
16273
|
-
const prevData = [];
|
|
16274
|
-
const replayData = [];
|
|
16275
|
-
for (const candle of candles) {
|
|
16276
|
-
if (candle.timestamp < preloadStart) {
|
|
16277
|
-
continue;
|
|
16278
|
-
}
|
|
16279
|
-
if (candle.timestamp < start) {
|
|
16280
|
-
prevData.push(candle);
|
|
16281
|
-
continue;
|
|
16282
|
-
}
|
|
16283
|
-
replayData.push(candle);
|
|
16284
|
-
}
|
|
16285
|
-
return { prevData, replayData };
|
|
16286
|
-
};
|
|
16287
|
-
alignSymbolWithBtcReference = (symbolCandles, btcCandles) => (0, import_indicators2.alignSortedCandlesByTimestamp)(symbolCandles, btcCandles);
|
|
16288
|
-
}
|
|
16289
|
-
});
|
|
16290
|
-
|
|
16291
|
-
// src/lib/replay/historicalSignalsReplayPreparation.ts
|
|
16292
|
-
var buildPreparedData, strategyIncludesSymbol, buildSymbolSharedReplayKey, prepareHistoricalReplay, releaseHistoricalReplayPlan;
|
|
16293
|
-
var init_historicalSignalsReplayPreparation = __esm({
|
|
16294
|
-
"src/lib/replay/historicalSignalsReplayPreparation.ts"() {
|
|
16295
|
-
"use strict";
|
|
16296
|
-
init_support();
|
|
16297
|
-
init_windows();
|
|
16298
|
-
buildPreparedData = ({
|
|
16299
|
-
data,
|
|
16300
|
-
btcData,
|
|
16301
|
-
ethData,
|
|
16302
|
-
btcBinanceData,
|
|
16303
|
-
btcCoinbaseData,
|
|
16304
|
-
start,
|
|
16305
|
-
preloadStart
|
|
16306
|
-
}) => {
|
|
16307
|
-
const { prevData: prevDataRaw, replayData: replayDataRaw } = splitCandlesForReplayWindow(data, start, preloadStart);
|
|
16308
|
-
const { prevData: btcPrevDataRaw, replayData: btcReplayDataRaw } = splitCandlesForReplayWindow(btcData, start, preloadStart);
|
|
16309
|
-
const { prevData: ethPrevDataRaw, replayData: ethReplayDataRaw } = splitCandlesForReplayWindow(ethData, start, preloadStart);
|
|
16310
|
-
const { prevData: btcBinancePrevDataRaw } = splitCandlesForReplayWindow(
|
|
16311
|
-
btcBinanceData,
|
|
16312
|
-
start,
|
|
16313
|
-
preloadStart
|
|
16314
|
-
);
|
|
16315
|
-
const { prevData: btcCoinbasePrevDataRaw } = splitCandlesForReplayWindow(
|
|
16316
|
-
btcCoinbaseData,
|
|
16317
|
-
start,
|
|
16318
|
-
preloadStart
|
|
16319
|
-
);
|
|
16320
|
-
const { alignedCoinCandles: prevData, alignedBtcCandles: btcPrevData } = alignSymbolWithBtcReference(prevDataRaw, btcPrevDataRaw);
|
|
16321
|
-
const { alignedCoinCandles: replayData, alignedBtcCandles: btcReplayData } = alignSymbolWithBtcReference(replayDataRaw, btcReplayDataRaw);
|
|
16322
|
-
const { alignedBtcCandles: ethPrevData } = alignSymbolWithBtcReference(
|
|
16323
|
-
prevData,
|
|
16324
|
-
ethPrevDataRaw
|
|
16325
|
-
);
|
|
16326
|
-
const { alignedBtcCandles: ethReplayData } = alignSymbolWithBtcReference(
|
|
16327
|
-
replayData,
|
|
16328
|
-
ethReplayDataRaw
|
|
16329
|
-
);
|
|
16330
|
-
const { alignedBtcCandles: btcBinancePrevData } = alignSymbolWithBtcReference(
|
|
16331
|
-
prevDataRaw,
|
|
16332
|
-
btcBinancePrevDataRaw
|
|
16333
|
-
);
|
|
16334
|
-
const { alignedBtcCandles: btcCoinbasePrevData } = alignSymbolWithBtcReference(prevDataRaw, btcCoinbasePrevDataRaw);
|
|
16335
|
-
return {
|
|
16336
|
-
prevData,
|
|
16337
|
-
btcPrevData,
|
|
16338
|
-
ethPrevData,
|
|
16339
|
-
replayData,
|
|
16340
|
-
btcReplayData,
|
|
16341
|
-
ethReplayData,
|
|
16342
|
-
btcBinancePrevData,
|
|
16343
|
-
btcCoinbasePrevData
|
|
16344
|
-
};
|
|
16345
|
-
};
|
|
16346
|
-
strategyIncludesSymbol = (strategy, symbol) => {
|
|
16347
|
-
const tickers = strategy.selection?.tickers;
|
|
16348
|
-
if (!tickers) return true;
|
|
16349
|
-
const normalizedSymbol = symbol.trim().toUpperCase();
|
|
16350
|
-
return tickers.some(
|
|
16351
|
-
(ticker) => ticker.trim().toUpperCase() === normalizedSymbol
|
|
16352
|
-
);
|
|
16353
|
-
};
|
|
16354
|
-
buildSymbolSharedReplayKey = ({
|
|
16355
|
-
userName: userName3,
|
|
16356
|
-
connectorName,
|
|
16357
|
-
interval: interval4,
|
|
16358
|
-
symbol,
|
|
16359
|
-
start,
|
|
16360
|
-
end
|
|
16361
|
-
}) => ["replay", userName3, connectorName, symbol, interval4, start, end].join(":");
|
|
16362
|
-
prepareHistoricalReplay = async (context, adapters) => {
|
|
16363
|
-
const {
|
|
16364
|
-
userName: userName3,
|
|
16365
|
-
projectRoot: projectRoot18,
|
|
16366
|
-
preparedRun,
|
|
16367
|
-
interval: interval4,
|
|
16368
|
-
connectorName,
|
|
16369
|
-
replayConnector,
|
|
16370
|
-
strategies,
|
|
16371
|
-
references
|
|
16372
|
-
} = context;
|
|
16373
|
-
const symbolRuntimes = [];
|
|
16374
|
-
const orderedTimestamps = /* @__PURE__ */ new Set();
|
|
16375
|
-
const sharedReplayKeyPrefixes = [];
|
|
16376
|
-
const runtimeLineages = [];
|
|
16377
|
-
let skippedSymbols = 0;
|
|
16378
|
-
for (const symbol of preparedRun.tickers) {
|
|
16379
|
-
const data = await preparedRun.marketConnector.kline({
|
|
16380
|
-
symbol,
|
|
16381
|
-
start: preparedRun.preloadStart,
|
|
16382
|
-
end: preparedRun.window.end,
|
|
16383
|
-
cacheOnly: true,
|
|
16384
|
-
interval: interval4
|
|
16385
|
-
});
|
|
16386
|
-
if (symbolRuntimes.length % 50 === 0)
|
|
16387
|
-
adapters.sampleMemory?.("history:loaded", {
|
|
16388
|
-
symbols: symbolRuntimes.length + 1,
|
|
16389
|
-
candles: data.length
|
|
16390
|
-
});
|
|
16391
|
-
const preparedData = buildPreparedData({
|
|
16392
|
-
data,
|
|
16393
|
-
btcData: references.btcMarketData,
|
|
16394
|
-
ethData: references.ethMarketData,
|
|
16395
|
-
btcBinanceData: references.btcBinanceData,
|
|
16396
|
-
btcCoinbaseData: references.btcCoinbaseData,
|
|
16397
|
-
start: preparedRun.window.start,
|
|
16398
|
-
preloadStart: preparedRun.preloadStart
|
|
16399
|
-
});
|
|
16400
|
-
if (!preparedData.replayData.length || !preparedData.btcReplayData.length) {
|
|
16401
|
-
skippedSymbols += 1;
|
|
16402
|
-
adapters.progress.tick({
|
|
16403
|
-
skipped: adapters.display.skipped(skippedSymbols),
|
|
16404
|
-
symbol: adapters.display.symbol(symbol)
|
|
16405
|
-
});
|
|
16406
|
-
continue;
|
|
16407
|
-
}
|
|
16408
|
-
const sharedIndicatorsReplayKey = buildSymbolSharedReplayKey({
|
|
16409
|
-
userName: userName3,
|
|
16410
|
-
connectorName,
|
|
16411
|
-
interval: interval4,
|
|
16412
|
-
symbol,
|
|
16413
|
-
start: preparedRun.window.start,
|
|
16414
|
-
end: preparedRun.window.end
|
|
16415
|
-
});
|
|
16416
|
-
sharedReplayKeyPrefixes.push(sharedIndicatorsReplayKey);
|
|
16417
|
-
const strategiesForSymbol = await Promise.all(
|
|
16418
|
-
strategies.filter((strategy) => strategyIncludesSymbol(strategy, symbol)).map(async (strategy) => {
|
|
16419
|
-
const replayStrategyConfig = buildReplayStrategyConfig({
|
|
16420
|
-
strategyConfig: strategy.strategyConfig,
|
|
16421
|
-
interval: interval4
|
|
16422
|
-
});
|
|
16423
|
-
const runtimeLineage = await adapters.buildLineage({
|
|
16424
|
-
projectRoot: projectRoot18,
|
|
16425
|
-
strategyName: strategy.strategyName,
|
|
16426
|
-
strategyRevision: strategy.strategyRevision,
|
|
16427
|
-
deploymentCompositionId: strategy.deploymentCompositionId,
|
|
16428
|
-
strategyPackageVersion: strategy.strategyPackageVersion,
|
|
16429
|
-
strategyDependencyVersions: strategy.strategyDependencyVersions,
|
|
16430
|
-
runtimePackageVersion: strategy.runtimePackageVersion,
|
|
16431
|
-
config: {
|
|
16432
|
-
configId: strategy.strategyRevision,
|
|
16433
|
-
strategyConfig: strategy.strategyConfig,
|
|
16434
|
-
symbolResultConfig: strategy.strategyResults?.[symbol]?.config ?? null
|
|
16435
|
-
},
|
|
16436
|
-
runContext: {
|
|
16437
|
-
connectorName: connectorName.toLowerCase(),
|
|
16438
|
-
interval: String(interval4),
|
|
16439
|
-
universe: preparedRun.universe ?? null
|
|
16440
|
-
}
|
|
16441
|
-
});
|
|
16442
|
-
runtimeLineages.push({
|
|
16443
|
-
strategy: strategy.strategyName,
|
|
16444
|
-
symbol,
|
|
16445
|
-
...preparedRun.deploymentId ? { deploymentId: preparedRun.deploymentId } : {},
|
|
16446
|
-
...preparedRun.accountId ? { accountId: preparedRun.accountId } : {},
|
|
16447
|
-
lineage: runtimeLineage
|
|
16448
|
-
});
|
|
16449
|
-
return {
|
|
16450
|
-
strategyName: strategy.strategyName,
|
|
16451
|
-
strategyConfig: strategy.strategyConfig,
|
|
16452
|
-
runtimeLineage,
|
|
16453
|
-
run: await strategy.strategyCreator({
|
|
16454
|
-
userName: userName3,
|
|
16455
|
-
connectorName,
|
|
16456
|
-
runtimeConfigId: strategy.strategyRevision,
|
|
16457
|
-
strategyRevision: strategy.strategyRevision,
|
|
16458
|
-
runtimeLineage,
|
|
16459
|
-
universe: preparedRun.universe,
|
|
16460
|
-
accountId: preparedRun.accountId,
|
|
16461
|
-
deploymentId: preparedRun.deploymentId,
|
|
16462
|
-
runtimeConfigSnapshot: {
|
|
16463
|
-
userConfig: replayStrategyConfig
|
|
16464
|
-
},
|
|
16465
|
-
config: replayStrategyConfig,
|
|
16466
|
-
symbol,
|
|
16467
|
-
data: preparedData.prevData,
|
|
16468
|
-
btcData: preparedData.btcPrevData,
|
|
16469
|
-
ethData: preparedData.ethPrevData,
|
|
16470
|
-
btcBinanceData: preparedData.btcBinancePrevData,
|
|
16471
|
-
btcCoinbaseData: preparedData.btcCoinbasePrevData,
|
|
16472
|
-
connector: replayConnector,
|
|
16473
|
-
sharedIndicatorsReplayKey
|
|
16474
|
-
})
|
|
16475
|
-
};
|
|
16476
|
-
})
|
|
16477
|
-
);
|
|
16478
|
-
const symbolRuntime = {
|
|
16479
|
-
symbol,
|
|
16480
|
-
replayData: preparedData.replayData,
|
|
16481
|
-
btcReplayData: preparedData.btcReplayData,
|
|
16482
|
-
ethReplayData: preparedData.ethReplayData,
|
|
16483
|
-
currentIndex: 0,
|
|
16484
|
-
strategies: strategiesForSymbol
|
|
16485
|
-
};
|
|
16486
|
-
symbolRuntimes.push(symbolRuntime);
|
|
16487
|
-
if (symbolRuntimes.length % 50 === 0 || symbol === preparedRun.tickers.at(-1))
|
|
16488
|
-
adapters.sampleMemory?.("strategies:initializing", {
|
|
16489
|
-
symbols: symbolRuntimes.length,
|
|
16490
|
-
strategiesPerSymbol: strategiesForSymbol.length
|
|
16491
|
-
});
|
|
16492
|
-
adapters.progress.tick({
|
|
16493
|
-
skipped: adapters.display.skipped(skippedSymbols),
|
|
16494
|
-
symbol: adapters.display.symbol(symbol)
|
|
16495
|
-
});
|
|
16496
|
-
for (const candle of preparedData.replayData) {
|
|
16497
|
-
orderedTimestamps.add(candle.timestamp);
|
|
16498
|
-
}
|
|
16499
|
-
}
|
|
16500
|
-
return {
|
|
16501
|
-
symbolRuntimes,
|
|
16502
|
-
orderedTimestamps: [...orderedTimestamps].sort(
|
|
16503
|
-
(left, right) => left - right
|
|
16504
|
-
),
|
|
16505
|
-
sharedReplayKeyPrefixes,
|
|
16506
|
-
runtimeLineages
|
|
16507
|
-
};
|
|
16508
|
-
};
|
|
16509
|
-
releaseHistoricalReplayPlan = (plan) => {
|
|
16510
|
-
plan.symbolRuntimes.length = 0;
|
|
16511
|
-
plan.sharedReplayKeyPrefixes.length = 0;
|
|
16512
|
-
};
|
|
16513
|
-
}
|
|
16514
|
-
});
|
|
16515
|
-
|
|
16516
16644
|
// src/lib/replay/historicalSignalsReplaySkipEvidence.ts
|
|
16517
|
-
var
|
|
16645
|
+
var import_data3, replayScopeKey, appendReplaySignalEvaluationRun, createHistoricalReplaySkipEvidence;
|
|
16518
16646
|
var init_historicalSignalsReplaySkipEvidence = __esm({
|
|
16519
16647
|
"src/lib/replay/historicalSignalsReplaySkipEvidence.ts"() {
|
|
16520
16648
|
"use strict";
|
|
16521
|
-
|
|
16649
|
+
import_data3 = require("@tradejs/core/data");
|
|
16522
16650
|
replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
|
|
16523
16651
|
appendReplaySignalEvaluationRun = ({
|
|
16524
16652
|
runs = [],
|
|
@@ -16526,7 +16654,7 @@ var init_historicalSignalsReplaySkipEvidence = __esm({
|
|
|
16526
16654
|
timestamp,
|
|
16527
16655
|
interval: interval4
|
|
16528
16656
|
}) => {
|
|
16529
|
-
const stepMs = (0,
|
|
16657
|
+
const stepMs = (0, import_data3.intervalToMs)(interval4);
|
|
16530
16658
|
const last = runs.at(-1);
|
|
16531
16659
|
if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
|
|
16532
16660
|
return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
|
|
@@ -16602,14 +16730,16 @@ var advanceCycleMarket, advanceAbortedCycle, executeHistoricalReplay;
|
|
|
16602
16730
|
var init_historicalSignalsReplayExecution = __esm({
|
|
16603
16731
|
"src/lib/replay/historicalSignalsReplayExecution.ts"() {
|
|
16604
16732
|
"use strict";
|
|
16733
|
+
init_historicalSignalsReplayPreparation();
|
|
16605
16734
|
init_historicalSignalsReplaySkipEvidence();
|
|
16606
16735
|
advanceCycleMarket = async (plan, connector, timestamp) => {
|
|
16607
16736
|
const cycleSymbols = plan.symbolRuntimes.filter(
|
|
16608
|
-
(symbolRuntime) => symbolRuntime.replayData[symbolRuntime.currentIndex]?.timestamp === timestamp
|
|
16737
|
+
(symbolRuntime) => (symbolRuntime.replayData[symbolRuntime.currentIndex]?.timestamp ?? NaN) + (symbolRuntime.timestampOffsetMs ?? 0) === timestamp
|
|
16609
16738
|
);
|
|
16610
16739
|
for (const symbolRuntime of cycleSymbols) {
|
|
16611
16740
|
const candle = symbolRuntime.replayData[symbolRuntime.currentIndex];
|
|
16612
|
-
if (candle
|
|
16741
|
+
if (candle && candle.timestamp + (symbolRuntime.timestampOffsetMs ?? 0) === timestamp) {
|
|
16742
|
+
if (symbolRuntime.advanceMarket === false) continue;
|
|
16613
16743
|
await connector.advanceMarket({
|
|
16614
16744
|
symbol: symbolRuntime.symbol,
|
|
16615
16745
|
candle
|
|
@@ -16621,7 +16751,7 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
16621
16751
|
advanceAbortedCycle = (cycleSymbols, timestamp) => {
|
|
16622
16752
|
for (const symbolRuntime of cycleSymbols ?? []) {
|
|
16623
16753
|
const candle = symbolRuntime.replayData[symbolRuntime.currentIndex];
|
|
16624
|
-
if (candle
|
|
16754
|
+
if (candle && candle.timestamp + (symbolRuntime.timestampOffsetMs ?? 0) === timestamp) {
|
|
16625
16755
|
symbolRuntime.currentIndex += 1;
|
|
16626
16756
|
}
|
|
16627
16757
|
}
|
|
@@ -16670,21 +16800,21 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
16670
16800
|
const candle = symbolRuntime.replayData[symbolRuntime.currentIndex];
|
|
16671
16801
|
const btcCandle = symbolRuntime.btcReplayData[symbolRuntime.currentIndex];
|
|
16672
16802
|
const ethCandle = symbolRuntime.ethReplayData[symbolRuntime.currentIndex];
|
|
16673
|
-
if (!candle || !btcCandle || candle.timestamp !== timestamp || btcCandle.timestamp !== timestamp) {
|
|
16803
|
+
if (!candle || !btcCandle || candle.timestamp + (symbolRuntime.timestampOffsetMs ?? 0) !== timestamp || btcCandle.timestamp !== candle.timestamp) {
|
|
16674
16804
|
continue;
|
|
16675
16805
|
}
|
|
16676
16806
|
for (const strategyRuntime of symbolRuntime.strategies) {
|
|
16677
16807
|
const result = await strategyRuntime.run(
|
|
16678
16808
|
candle,
|
|
16679
16809
|
btcCandle,
|
|
16680
|
-
ethCandle?.timestamp === timestamp ? ethCandle : void 0
|
|
16810
|
+
ethCandle?.timestamp === candle.timestamp ? ethCandle : void 0
|
|
16681
16811
|
);
|
|
16682
16812
|
skipEvidence.record({
|
|
16683
16813
|
strategyName: strategyRuntime.strategyName,
|
|
16684
16814
|
symbol: symbolRuntime.symbol,
|
|
16685
16815
|
strategyConfig: strategyRuntime.strategyConfig,
|
|
16686
16816
|
runtimeLineage: strategyRuntime.runtimeLineage,
|
|
16687
|
-
timestamp,
|
|
16817
|
+
timestamp: candle.timestamp,
|
|
16688
16818
|
result
|
|
16689
16819
|
});
|
|
16690
16820
|
if (result && typeof result !== "string") {
|
|
@@ -16705,10 +16835,7 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
16705
16835
|
reportProgress(timestamp);
|
|
16706
16836
|
}
|
|
16707
16837
|
} finally {
|
|
16708
|
-
|
|
16709
|
-
adapters.releaseIndicatorsCache(keyPrefix);
|
|
16710
|
-
adapters.releaseReplayCache(keyPrefix);
|
|
16711
|
-
}
|
|
16838
|
+
releaseHistoricalReplayCaches(context.plan, adapters);
|
|
16712
16839
|
}
|
|
16713
16840
|
return {
|
|
16714
16841
|
signals: signals2,
|
|
@@ -17013,7 +17140,19 @@ var init_historicalSignalsReplay = __esm({
|
|
|
17013
17140
|
}
|
|
17014
17141
|
);
|
|
17015
17142
|
memory?.("references:loaded");
|
|
17016
|
-
const
|
|
17143
|
+
const cacheAdapters = {
|
|
17144
|
+
releaseIndicatorsCache: (keyPrefix) => releaseReplayCacheCopies(
|
|
17145
|
+
keyPrefix,
|
|
17146
|
+
import_strategies5.releaseStrategyIndicatorsReplayCache,
|
|
17147
|
+
getProjectReplayCacheReleasers()?.releaseStrategyIndicatorsReplayCache
|
|
17148
|
+
),
|
|
17149
|
+
releaseReplayCache: (keyPrefix) => releaseReplayCacheCopies(
|
|
17150
|
+
keyPrefix,
|
|
17151
|
+
import_strategies5.releaseStrategyReplayCache,
|
|
17152
|
+
getProjectReplayCacheReleasers()?.releaseStrategyReplayCache
|
|
17153
|
+
)
|
|
17154
|
+
};
|
|
17155
|
+
const plan = await prepareMultiIntervalHistoricalReplay(
|
|
17017
17156
|
{
|
|
17018
17157
|
userName: replayUserName,
|
|
17019
17158
|
projectRoot: replayProjectRoot,
|
|
@@ -17030,6 +17169,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
17030
17169
|
}
|
|
17031
17170
|
},
|
|
17032
17171
|
{
|
|
17172
|
+
...cacheAdapters,
|
|
17033
17173
|
progress: {
|
|
17034
17174
|
tick: (tokens) => prepareBar.tick(1, tokens)
|
|
17035
17175
|
},
|
|
@@ -17039,7 +17179,11 @@ var init_historicalSignalsReplay = __esm({
|
|
|
17039
17179
|
},
|
|
17040
17180
|
buildLineage: buildRuntimeLineage,
|
|
17041
17181
|
sampleMemory: memory
|
|
17042
|
-
}
|
|
17182
|
+
},
|
|
17183
|
+
(nativeInterval, nativeRun) => loadHistoricalReplayReferences({
|
|
17184
|
+
preparedRun: nativeRun,
|
|
17185
|
+
interval: nativeInterval
|
|
17186
|
+
})
|
|
17043
17187
|
);
|
|
17044
17188
|
memory?.("strategies:prepared", { symbols: plan.symbolRuntimes.length });
|
|
17045
17189
|
const hookContext = buildAfterSignalsContext({
|
|
@@ -17066,6 +17210,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
17066
17210
|
hookContext
|
|
17067
17211
|
},
|
|
17068
17212
|
{
|
|
17213
|
+
...cacheAdapters,
|
|
17069
17214
|
clock: { now: Date.now },
|
|
17070
17215
|
progress: {
|
|
17071
17216
|
enabled: showProgress,
|
|
@@ -17078,17 +17223,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
17078
17223
|
},
|
|
17079
17224
|
invokeBeforeSignals: invokeBeforeSignalsHooks,
|
|
17080
17225
|
invokeAfterSignals: invokeAfterSignalsHooks,
|
|
17081
|
-
enrichSignal: (signal) => (0, import_strategies6.enrichSignalWithBinanceMarketContext)({ signal, env: "PARITY" })
|
|
17082
|
-
releaseIndicatorsCache: (keyPrefix) => releaseReplayCacheCopies(
|
|
17083
|
-
keyPrefix,
|
|
17084
|
-
import_strategies5.releaseStrategyIndicatorsReplayCache,
|
|
17085
|
-
getProjectReplayCacheReleasers()?.releaseStrategyIndicatorsReplayCache
|
|
17086
|
-
),
|
|
17087
|
-
releaseReplayCache: (keyPrefix) => releaseReplayCacheCopies(
|
|
17088
|
-
keyPrefix,
|
|
17089
|
-
import_strategies5.releaseStrategyReplayCache,
|
|
17090
|
-
getProjectReplayCacheReleasers()?.releaseStrategyReplayCache
|
|
17091
|
-
)
|
|
17226
|
+
enrichSignal: (signal) => (0, import_strategies6.enrichSignalWithBinanceMarketContext)({ signal, env: "PARITY" })
|
|
17092
17227
|
}
|
|
17093
17228
|
);
|
|
17094
17229
|
memory?.("execution:complete", { signals: execution.signals.length });
|
|
@@ -17668,18 +17803,18 @@ var init_paritySummary = __esm({
|
|
|
17668
17803
|
});
|
|
17669
17804
|
|
|
17670
17805
|
// src/lib/runtimeSignalsStorage.ts
|
|
17671
|
-
var import_constants12,
|
|
17806
|
+
var import_constants12, import_data4, import_time5, appendRuntimeSignalEvaluationRun, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
|
|
17672
17807
|
var init_runtimeSignalsStorage = __esm({
|
|
17673
17808
|
"src/lib/runtimeSignalsStorage.ts"() {
|
|
17674
17809
|
"use strict";
|
|
17675
17810
|
import_constants12 = require("@tradejs/core/constants");
|
|
17676
|
-
|
|
17811
|
+
import_data4 = require("@tradejs/core/data");
|
|
17677
17812
|
import_time5 = require("@tradejs/core/time");
|
|
17678
17813
|
appendRuntimeSignalEvaluationRun = (runs = [], evaluation) => {
|
|
17679
17814
|
if (evaluation.status !== "skip") {
|
|
17680
17815
|
return [...runs];
|
|
17681
17816
|
}
|
|
17682
|
-
const stepMs = (0,
|
|
17817
|
+
const stepMs = (0, import_data4.intervalToMs)(evaluation.interval);
|
|
17683
17818
|
const reason = evaluation.reason?.trim() || "NO_SIGNAL";
|
|
17684
17819
|
const existing = runs.find(
|
|
17685
17820
|
(run) => run.status === "skip" && run.reason === reason && run.stepMs === stepMs && evaluation.timestamp >= run.firstTimestamp && evaluation.timestamp <= run.lastTimestamp && (evaluation.timestamp - run.firstTimestamp) % stepMs === 0
|
|
@@ -19419,7 +19554,10 @@ var init_runtimeComparisonCalculations = __esm({
|
|
|
19419
19554
|
return candidates.map((candidate) => ({
|
|
19420
19555
|
...candidate,
|
|
19421
19556
|
timestampDiffMs: Math.abs(
|
|
19422
|
-
candidate.timestamp +
|
|
19557
|
+
candidate.timestamp + resolveTradeParityTimestampOffset(
|
|
19558
|
+
strategyName,
|
|
19559
|
+
signalTimestampOffsetMs
|
|
19560
|
+
) - exchangeEntry.entryTimestamp
|
|
19423
19561
|
)
|
|
19424
19562
|
})).filter((candidate) => candidate.timestampDiffMs <= toleranceMs).sort(
|
|
19425
19563
|
(left, right) => left.timestampDiffMs - right.timestampDiffMs || Number(right.orderStatus === "failed") - Number(left.orderStatus === "failed")
|
|
@@ -19669,11 +19807,12 @@ var init_runtimeComparisonReporting = __esm({
|
|
|
19669
19807
|
});
|
|
19670
19808
|
|
|
19671
19809
|
// src/lib/replay/runtimeComparison.ts
|
|
19672
|
-
var import_chalk20,
|
|
19810
|
+
var import_chalk20, import_data5, replayStrategyIntervals, buildReplaySignalEvaluations, toFiniteNumberOrNull4, sumOptionalNumbers, firstFiniteNumber, firstString, getExchangeExecutionMergeKey, mergeExchangeExecutionGroup, mergeExchangeEntryExecutions, loadExchangeEntryRows, loadExchangeEntriesForComparison, saveAndPrintReplayExchangeComparison, saveAndPrintReplayRuntimeComparison;
|
|
19673
19811
|
var init_runtimeComparison = __esm({
|
|
19674
19812
|
"src/lib/replay/runtimeComparison.ts"() {
|
|
19675
19813
|
"use strict";
|
|
19676
19814
|
import_chalk20 = __toESM(require("chalk"));
|
|
19815
|
+
import_data5 = require("@tradejs/core/data");
|
|
19677
19816
|
init_runtimeParity();
|
|
19678
19817
|
init_paritySummary();
|
|
19679
19818
|
init_runtimeRedis();
|
|
@@ -19688,10 +19827,13 @@ var init_runtimeComparison = __esm({
|
|
|
19688
19827
|
init_runtimeComparisonCalculations();
|
|
19689
19828
|
init_runtimeComparisonReporting();
|
|
19690
19829
|
init_runtimeComparisonCalculations();
|
|
19691
|
-
|
|
19692
|
-
const
|
|
19693
|
-
|
|
19694
|
-
|
|
19830
|
+
replayStrategyIntervals = (summaries) => summaries.map(({ strategyName, strategyConfig }) => {
|
|
19831
|
+
const durationMs = (0, import_data5.intervalToMs)(strategyConfig.INTERVAL);
|
|
19832
|
+
if (!Number.isFinite(durationMs) || durationMs <= 0) {
|
|
19833
|
+
throw new Error(`Invalid replay interval for ${strategyName}`);
|
|
19834
|
+
}
|
|
19835
|
+
return { strategyName, interval: String(durationMs / 6e4) };
|
|
19836
|
+
});
|
|
19695
19837
|
buildReplaySignalEvaluations = (signals2) => signals2.map((signal) => ({
|
|
19696
19838
|
evaluationId: `${signal.strategy}:${signal.symbol}:${signal.timestamp}`,
|
|
19697
19839
|
userName: replayUserName,
|
|
@@ -19908,7 +20050,8 @@ var init_runtimeComparison = __esm({
|
|
|
19908
20050
|
runtimeSignals,
|
|
19909
20051
|
runtimeSignalEvaluations,
|
|
19910
20052
|
runtimeLineageScopes,
|
|
19911
|
-
lineage
|
|
20053
|
+
lineage,
|
|
20054
|
+
timestampOffsetMs
|
|
19912
20055
|
}) => {
|
|
19913
20056
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
19914
20057
|
const rawExchangeEntries = await loadExchangeEntriesForComparison({
|
|
@@ -19933,7 +20076,7 @@ var init_runtimeComparison = __esm({
|
|
|
19933
20076
|
runtimeSignals,
|
|
19934
20077
|
runtimeSignalEvaluations,
|
|
19935
20078
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
19936
|
-
signalTimestampOffsetMs:
|
|
20079
|
+
signalTimestampOffsetMs: timestampOffsetMs
|
|
19937
20080
|
});
|
|
19938
20081
|
});
|
|
19939
20082
|
const comparisonLineage = {
|
|
@@ -19955,7 +20098,7 @@ var init_runtimeComparison = __esm({
|
|
|
19955
20098
|
backtestEntries,
|
|
19956
20099
|
strategyNameByOrderLinkKey,
|
|
19957
20100
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
19958
|
-
backtestTimestampOffsetMs:
|
|
20101
|
+
backtestTimestampOffsetMs: timestampOffsetMs,
|
|
19959
20102
|
runtimeSignals,
|
|
19960
20103
|
runtimeSignalEvaluations,
|
|
19961
20104
|
replaySignals,
|
|
@@ -19994,7 +20137,7 @@ var init_runtimeComparison = __esm({
|
|
|
19994
20137
|
exchangeEntries,
|
|
19995
20138
|
backtestEntries,
|
|
19996
20139
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
19997
|
-
backtestTimestampOffsetMs:
|
|
20140
|
+
backtestTimestampOffsetMs: timestampOffsetMs
|
|
19998
20141
|
});
|
|
19999
20142
|
const { completed: matched, orderFailed } = splitExchangeMatchesByRuntimeOrderStatus({
|
|
20000
20143
|
matched: comparison.matched,
|
|
@@ -20002,7 +20145,7 @@ var init_runtimeComparison = __esm({
|
|
|
20002
20145
|
runtimeSignals,
|
|
20003
20146
|
runtimeSignalEvaluations,
|
|
20004
20147
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
20005
|
-
signalTimestampOffsetMs:
|
|
20148
|
+
signalTimestampOffsetMs: timestampOffsetMs
|
|
20006
20149
|
});
|
|
20007
20150
|
const details = buildReplayExchangeComparisonDetails({
|
|
20008
20151
|
matched,
|
|
@@ -20013,7 +20156,7 @@ var init_runtimeComparison = __esm({
|
|
|
20013
20156
|
backtestEntries,
|
|
20014
20157
|
strategyNameByOrderLinkKey,
|
|
20015
20158
|
toleranceMs: REPLAY_RUNTIME_COMPARE_TOLERANCE_MS,
|
|
20016
|
-
backtestTimestampOffsetMs:
|
|
20159
|
+
backtestTimestampOffsetMs: timestampOffsetMs,
|
|
20017
20160
|
runtimeSignals,
|
|
20018
20161
|
runtimeSignalEvaluations,
|
|
20019
20162
|
replaySignals,
|
|
@@ -20074,9 +20217,16 @@ var init_runtimeComparison = __esm({
|
|
|
20074
20217
|
expectedUserName: replayUserName,
|
|
20075
20218
|
expectedWindow: window
|
|
20076
20219
|
}) : null;
|
|
20077
|
-
const
|
|
20078
|
-
|
|
20079
|
-
|
|
20220
|
+
const declaredIntervals = runtimeEvidence2 ? [] : replayStrategyIntervals(liveStrategySummaries);
|
|
20221
|
+
const replayTimestampOffset = buildTradeParityTimestampOffset(
|
|
20222
|
+
runtimeEvidence2 ? (0, runtimeEvidenceDeployment_exports.activeRuntimeEvidenceStrategies)(runtimeEvidence2.deployment) : declaredIntervals
|
|
20223
|
+
);
|
|
20224
|
+
const metadataStart = runtimeEvidence2 ? window.start : window.start - Math.max(
|
|
20225
|
+
0,
|
|
20226
|
+
...declaredIntervals.map(
|
|
20227
|
+
({ interval: interval4 }) => Number(interval4) * 6e4 - (0, import_data5.intervalToMs)(replayInterval)
|
|
20228
|
+
)
|
|
20229
|
+
);
|
|
20080
20230
|
const [
|
|
20081
20231
|
rawRuntimeTrades,
|
|
20082
20232
|
runtimeSignals,
|
|
@@ -20093,15 +20243,15 @@ var init_runtimeComparison = __esm({
|
|
|
20093
20243
|
endTime: window.end
|
|
20094
20244
|
}),
|
|
20095
20245
|
loadRuntimeSignals(replayUserName, {
|
|
20096
|
-
startTime:
|
|
20246
|
+
startTime: metadataStart,
|
|
20097
20247
|
endTime: window.end
|
|
20098
20248
|
}),
|
|
20099
20249
|
loadRuntimeSignalEvaluations(replayUserName, {
|
|
20100
|
-
startTime:
|
|
20250
|
+
startTime: metadataStart,
|
|
20101
20251
|
endTime: window.end
|
|
20102
20252
|
}),
|
|
20103
20253
|
loadRuntimeLineageScopes(replayUserName, {
|
|
20104
|
-
startTime:
|
|
20254
|
+
startTime: metadataStart,
|
|
20105
20255
|
endTime: window.end
|
|
20106
20256
|
})
|
|
20107
20257
|
]);
|
|
@@ -20169,6 +20319,7 @@ var init_runtimeComparison = __esm({
|
|
|
20169
20319
|
);
|
|
20170
20320
|
return saveAndPrintReplayExchangeComparison({
|
|
20171
20321
|
liveStrategySummaries,
|
|
20322
|
+
timestampOffsetMs: replayTimestampOffset,
|
|
20172
20323
|
backtestEntries: comparableBacktestEntries,
|
|
20173
20324
|
replaySignals,
|
|
20174
20325
|
replaySignalEvaluations,
|
|
@@ -21086,13 +21237,14 @@ ${markdownTable2(strategyRows)}
|
|
|
21086
21237
|
});
|
|
21087
21238
|
|
|
21088
21239
|
// src/scripts/replayRunner.ts
|
|
21089
|
-
var import_chalk21, import_constants14,
|
|
21240
|
+
var import_chalk21, import_constants14, import_data6, import_time8, import_redis11, import_candles, import_runtimeStrategies4, import_strategies7, prepareReplayBinanceMarketContext, replayMarketContextInterval, cachedTickerSymbols, finishReplay, replayBacktest;
|
|
21090
21241
|
var init_replayRunner = __esm({
|
|
21091
21242
|
"src/scripts/replayRunner.ts"() {
|
|
21092
21243
|
"use strict";
|
|
21244
|
+
init_historicalSignalsReplayPreparation();
|
|
21093
21245
|
import_chalk21 = __toESM(require("chalk"));
|
|
21094
21246
|
import_constants14 = require("@tradejs/core/constants");
|
|
21095
|
-
|
|
21247
|
+
import_data6 = require("@tradejs/core/data");
|
|
21096
21248
|
import_time8 = require("@tradejs/core/time");
|
|
21097
21249
|
import_redis11 = require("@tradejs/infra/redis");
|
|
21098
21250
|
import_candles = require("@tradejs/infra/timescale/candles");
|
|
@@ -21368,16 +21520,10 @@ var init_replayRunner = __esm({
|
|
|
21368
21520
|
if (!replayStrategies.length) {
|
|
21369
21521
|
throw new Error(`No enabled strategies in deployment ${deployment.id}`);
|
|
21370
21522
|
}
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
)
|
|
21523
|
+
resolveHistoricalReplayIntervals(
|
|
21524
|
+
replayInterval,
|
|
21525
|
+
replayStrategies.map(({ strategyConfig }) => strategyConfig.INTERVAL)
|
|
21375
21526
|
);
|
|
21376
|
-
if (strategyIntervals.size !== 1 || !strategyIntervals.has(replayInterval)) {
|
|
21377
|
-
throw new Error(
|
|
21378
|
-
`Replay interval does not match deployment ${deployment.id}: replay=${replayInterval}, strategies=${[...strategyIntervals].join(",")}`
|
|
21379
|
-
);
|
|
21380
|
-
}
|
|
21381
21527
|
const strategyUniverses = new Set(
|
|
21382
21528
|
replayStrategies.map(
|
|
21383
21529
|
({ strategyConfig }) => String(strategyConfig.UNIVERSE)
|
|
@@ -21423,13 +21569,13 @@ var init_replayRunner = __esm({
|
|
|
21423
21569
|
deploymentId: deployment.id,
|
|
21424
21570
|
assetClasses: deployment.assetClasses,
|
|
21425
21571
|
deployment,
|
|
21426
|
-
closedIntervalMs: (0,
|
|
21572
|
+
closedIntervalMs: (0, import_data6.intervalToMs)(replayInterval)
|
|
21427
21573
|
});
|
|
21428
21574
|
if (!preparedRun || isReplayUpdateOnlyRun) {
|
|
21429
21575
|
return;
|
|
21430
21576
|
}
|
|
21431
21577
|
if (useAllData) {
|
|
21432
|
-
const intervalMs = (0,
|
|
21578
|
+
const intervalMs = (0, import_data6.intervalToMs)(replayInterval);
|
|
21433
21579
|
const edges = await (0, import_candles.getDataEdgesForSymbols)(
|
|
21434
21580
|
deployment.provider,
|
|
21435
21581
|
preparedRun.tickers,
|
|
@@ -21914,13 +22060,13 @@ var init_binanceMarketIngest = __esm({
|
|
|
21914
22060
|
});
|
|
21915
22061
|
|
|
21916
22062
|
// src/lib/runBot.ts
|
|
21917
|
-
var import_lodash, import_connectors10,
|
|
22063
|
+
var import_lodash, import_connectors10, import_data7, import_strategies10, import_async3, import_constants15, import_time9, import_logger2, import_redis12, projectRoot4, runBot;
|
|
21918
22064
|
var init_runBot = __esm({
|
|
21919
22065
|
"src/lib/runBot.ts"() {
|
|
21920
22066
|
"use strict";
|
|
21921
22067
|
import_lodash = __toESM(require("lodash"));
|
|
21922
22068
|
import_connectors10 = require("@tradejs/node/connectors");
|
|
21923
|
-
|
|
22069
|
+
import_data7 = require("@tradejs/core/data");
|
|
21924
22070
|
import_strategies10 = require("@tradejs/node/strategies");
|
|
21925
22071
|
import_async3 = require("@tradejs/core/async");
|
|
21926
22072
|
import_constants15 = require("@tradejs/core/constants");
|
|
@@ -22039,11 +22185,11 @@ var init_runBot = __esm({
|
|
|
22039
22185
|
status: JSON.stringify(status)
|
|
22040
22186
|
});
|
|
22041
22187
|
} catch (err) {
|
|
22042
|
-
import_logger2.logger.log("error", "bot %s error: %s", bot.symbol, (0,
|
|
22188
|
+
import_logger2.logger.log("error", "bot %s error: %s", bot.symbol, (0, import_data7.toJson)(err, false));
|
|
22043
22189
|
}
|
|
22044
22190
|
}
|
|
22045
22191
|
}
|
|
22046
|
-
import_logger2.logger.log("info", "botResults: %s", (0,
|
|
22192
|
+
import_logger2.logger.log("info", "botResults: %s", (0, import_data7.toJson)(botResults, true));
|
|
22047
22193
|
return botResults;
|
|
22048
22194
|
};
|
|
22049
22195
|
}
|
|
@@ -23502,12 +23648,12 @@ var init_doctor = __esm({
|
|
|
23502
23648
|
});
|
|
23503
23649
|
|
|
23504
23650
|
// src/lib/executionCalibration.ts
|
|
23505
|
-
var import_constants17,
|
|
23651
|
+
var import_constants17, import_data8, import_trade3, roundMetric, asRecord3, asArray, finiteNumber2, finiteString, finiteDirection, metricValues, quantile, summarizeNumbers, getIntervalMs, getSignalKey, addSignalToMap, getRuntimePayload, extractRuntimeTradeRows, normalizeReplayMatch, extractReplayMatches, buildReplayMatchMaps, getSignalCandles, adverseEntryBps, feeBps, latencyDelta, resolveTelemetryQuality, finiteTelemetryQuality, countBy, toLatencyBucket, toSpreadBucket, buildSample, buildReplayOnlySample, hasTelemetry, hasFullTelemetry, buildGroupSummary, groupSamples, positiveMetricValues, buildRecommendation, buildExecutionCalibrationReport;
|
|
23506
23652
|
var init_executionCalibration = __esm({
|
|
23507
23653
|
"src/lib/executionCalibration.ts"() {
|
|
23508
23654
|
"use strict";
|
|
23509
23655
|
import_constants17 = require("@tradejs/core/constants");
|
|
23510
|
-
|
|
23656
|
+
import_data8 = require("@tradejs/core/data");
|
|
23511
23657
|
import_trade3 = require("@tradejs/core/trade");
|
|
23512
23658
|
roundMetric = (value, decimals = 6) => typeof value === "number" && Number.isFinite(value) ? Number(value.toFixed(decimals)) : null;
|
|
23513
23659
|
asRecord3 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -23567,7 +23713,7 @@ var init_executionCalibration = __esm({
|
|
|
23567
23713
|
return null;
|
|
23568
23714
|
}
|
|
23569
23715
|
try {
|
|
23570
|
-
return (0,
|
|
23716
|
+
return (0, import_data8.intervalToMs)(interval4);
|
|
23571
23717
|
} catch {
|
|
23572
23718
|
return null;
|
|
23573
23719
|
}
|
|
@@ -24795,14 +24941,16 @@ const timer = setInterval(() => {
|
|
|
24795
24941
|
if (result.exitCode !== 0) {
|
|
24796
24942
|
let fd;
|
|
24797
24943
|
try {
|
|
24798
|
-
|
|
24944
|
+
const logId = result.logRequestId === undefined ? id : result.logRequestId;
|
|
24945
|
+
if (typeof logId !== 'string' || !/^[a-f0-9]{64}$/.test(logId)) throw new Error('Invalid replay log identity');
|
|
24946
|
+
fd = fs.openSync(path.join(root, logId) + '.log', fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
24799
24947
|
const size = fs.fstatSync(fd).size;
|
|
24800
24948
|
const tail = Buffer.alloc(Math.min(size, 65536));
|
|
24801
24949
|
fs.readSync(fd, tail, 0, tail.length, Math.max(0, size - tail.length));
|
|
24802
24950
|
// The worker redacts each line before persisting or returning it through MCP.
|
|
24803
24951
|
for (const line of tail.toString('utf8').split(/[\\r\\n]+/).filter(Boolean).slice(-150)) console.error('Host replay: ' + line);
|
|
24804
24952
|
} catch (error) {
|
|
24805
|
-
console.error('Host replay log unavailable: ' + error.code);
|
|
24953
|
+
console.error('Host replay: ' + result.message + '; log unavailable: ' + (error.code || error.message));
|
|
24806
24954
|
} finally { if (fd !== undefined) fs.closeSync(fd); }
|
|
24807
24955
|
}
|
|
24808
24956
|
clearInterval(timer);
|
|
@@ -31438,6 +31586,10 @@ var init_specification = __esm({
|
|
|
31438
31586
|
};
|
|
31439
31587
|
if (!spec.budget || !spec.selection || !spec.diagnostics)
|
|
31440
31588
|
throw new Error("Missing research budgets or criteria");
|
|
31589
|
+
if (spec.featurePaths !== void 0 && (!Array.isArray(spec.featurePaths) || !spec.featurePaths.length || spec.featurePaths.length > 64 || new Set(spec.featurePaths).size !== spec.featurePaths.length || spec.featurePaths.some(
|
|
31590
|
+
(path56) => typeof path56 !== "string" || !/^additionalIndicators\.[a-zA-Z0-9_.]+$/.test(path56) || classifyAiPocketFeaturePath(path56.split(".")) !== "eligible"
|
|
31591
|
+
)))
|
|
31592
|
+
throw new Error("Feature paths must be unique causal market features");
|
|
31441
31593
|
positive(spec.budget.maxVariants, "maxVariants", 12);
|
|
31442
31594
|
if (!Number.isInteger(spec.minQuality) || spec.minQuality < 1 || spec.minQuality > 5)
|
|
31443
31595
|
throw new Error("minQuality must be 1 through 5");
|
|
@@ -33609,6 +33761,7 @@ var init_orchestrator2 = __esm({
|
|
|
33609
33761
|
parentSpec.selection,
|
|
33610
33762
|
parentSpec.portfolio,
|
|
33611
33763
|
parentSpec.minQuality,
|
|
33764
|
+
parentSpec.featurePaths,
|
|
33612
33765
|
parentSpec.diagnostics
|
|
33613
33766
|
]) !== sha256Json([
|
|
33614
33767
|
spec.core.variants.map((item) => item.resolvedConfig),
|
|
@@ -33617,6 +33770,7 @@ var init_orchestrator2 = __esm({
|
|
|
33617
33770
|
spec.selection,
|
|
33618
33771
|
spec.portfolio,
|
|
33619
33772
|
spec.minQuality,
|
|
33773
|
+
spec.featurePaths,
|
|
33620
33774
|
spec.diagnostics
|
|
33621
33775
|
]) || parentState.lineage.runtimeSha256 !== state.lineage.runtimeSha256 || parentState.lineage.contextEnvironmentSha256 !== state.lineage.contextEnvironmentSha256)
|
|
33622
33776
|
throw new Error(
|
|
@@ -34132,7 +34286,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
34132
34286
|
});
|
|
34133
34287
|
|
|
34134
34288
|
// src/lib/strategyResearch/native.ts
|
|
34135
|
-
var import_promises32, import_node_fs9, import_node_path29, import_node_os4, import_node_readline4, import_node_child_process8, import_node_module3, import_redis17, import_ai9, import_backtest7, import_registry5, import_connectors14,
|
|
34289
|
+
var import_promises32, import_node_fs9, import_node_path29, import_node_os4, import_node_readline4, import_node_child_process8, import_node_module3, import_redis17, import_ai9, import_backtest7, import_registry5, import_connectors14, import_data9, import_coreResearch2, import_jev6, validateResearchJevTraining, nativeConfig, runResearchCommand, createNativeStrategyResearchBackend;
|
|
34136
34290
|
var init_native = __esm({
|
|
34137
34291
|
"src/lib/strategyResearch/native.ts"() {
|
|
34138
34292
|
"use strict";
|
|
@@ -34157,7 +34311,7 @@ var init_native = __esm({
|
|
|
34157
34311
|
init_io2();
|
|
34158
34312
|
init_aiTrainResearch();
|
|
34159
34313
|
init_events();
|
|
34160
|
-
|
|
34314
|
+
import_data9 = require("@tradejs/core/data");
|
|
34161
34315
|
import_coreResearch2 = require("@tradejs/infra/coreResearch");
|
|
34162
34316
|
init_trace();
|
|
34163
34317
|
import_jev6 = require("@tradejs/core/jev");
|
|
@@ -34325,9 +34479,10 @@ var init_native = __esm({
|
|
|
34325
34479
|
throw new Error(
|
|
34326
34480
|
"Tester workers are already active; research will resume when the host is free"
|
|
34327
34481
|
);
|
|
34328
|
-
|
|
34482
|
+
const availableBytes = import_node_os4.default.platform() === "darwin" ? process.availableMemory() : import_node_os4.default.freemem();
|
|
34483
|
+
if (!Number.isFinite(availableBytes) || availableBytes < spec.budget.minimumFreeMemoryMb * 1024 * 1024)
|
|
34329
34484
|
throw new Error(
|
|
34330
|
-
"Insufficient
|
|
34485
|
+
"Insufficient available host memory for the frozen research budget"
|
|
34331
34486
|
);
|
|
34332
34487
|
};
|
|
34333
34488
|
return {
|
|
@@ -34551,7 +34706,7 @@ var init_native = __esm({
|
|
|
34551
34706
|
);
|
|
34552
34707
|
}
|
|
34553
34708
|
if (!coverage.some(
|
|
34554
|
-
(item) => (item.last ?? 0) >= spec.core.window.end - 2 * (0,
|
|
34709
|
+
(item) => (item.last ?? 0) >= spec.core.window.end - 2 * (0, import_data9.intervalToMs)(spec.core.execution.interval)
|
|
34555
34710
|
))
|
|
34556
34711
|
throw new Error(
|
|
34557
34712
|
"Cached market history ends before the requested window; choose a covered end or explicitly refresh history"
|
|
@@ -34780,9 +34935,14 @@ var init_native = __esm({
|
|
|
34780
34935
|
throw new Error(
|
|
34781
34936
|
`Native/export reconciliation is ${reconciliation.status}: ${reconciliation.reasons.join("; ")}`
|
|
34782
34937
|
);
|
|
34938
|
+
const researchSignalId = (symbol, signalId) => JSON.stringify([symbol, signalId]);
|
|
34783
34939
|
const trades = loaded.trades.filter(
|
|
34784
34940
|
(trade) => trade.signalTimestamp >= spec.core.window.start && trade.signalTimestamp < spec.core.window.end && trade.exitTimestamp < spec.core.window.end
|
|
34785
|
-
)
|
|
34941
|
+
).map((trade) => ({
|
|
34942
|
+
...trade,
|
|
34943
|
+
// Strategy-generated signal IDs need not be unique across symbols.
|
|
34944
|
+
signalId: researchSignalId(trade.symbol, trade.signalId)
|
|
34945
|
+
}));
|
|
34786
34946
|
const tradeBySignal = new Map(
|
|
34787
34947
|
trades.map((trade) => [trade.signalId, trade])
|
|
34788
34948
|
);
|
|
@@ -34806,9 +34966,10 @@ var init_native = __esm({
|
|
|
34806
34966
|
for await (const line of lines) {
|
|
34807
34967
|
if (!line.trim()) continue;
|
|
34808
34968
|
const row = JSON.parse(line);
|
|
34809
|
-
const
|
|
34810
|
-
|
|
34811
|
-
seen.
|
|
34969
|
+
const signalId = researchSignalId(row.symbol, row.signalId);
|
|
34970
|
+
const trade = tradeBySignal.get(signalId);
|
|
34971
|
+
if (!trade || seen.has(signalId)) continue;
|
|
34972
|
+
seen.add(signalId);
|
|
34812
34973
|
if (discoveryOnly && (row.timestamp >= spec.testSince || trade.exitTimestamp >= spec.testSince)) {
|
|
34813
34974
|
if (row.timestamp < spec.testSince) purgedLabels++;
|
|
34814
34975
|
continue;
|
|
@@ -34846,7 +35007,7 @@ var init_native = __esm({
|
|
|
34846
35007
|
featureProfile: "all"
|
|
34847
35008
|
});
|
|
34848
35009
|
for (const key of Object.keys(features))
|
|
34849
|
-
if (!key.startsWith("additionalIndicators.") || features[key] == null)
|
|
35010
|
+
if (!key.startsWith("additionalIndicators.") || features[key] == null || spec.featurePaths && !spec.featurePaths.includes(key))
|
|
34850
35011
|
delete features[key];
|
|
34851
35012
|
featureValues += Object.keys(features).length;
|
|
34852
35013
|
if (featureValues > 5e6)
|
|
@@ -34865,7 +35026,7 @@ var init_native = __esm({
|
|
|
34865
35026
|
pathCoverage[key]++;
|
|
34866
35027
|
}
|
|
34867
35028
|
rows.push({
|
|
34868
|
-
signalId
|
|
35029
|
+
signalId,
|
|
34869
35030
|
symbol: row.symbol,
|
|
34870
35031
|
strategy: row.strategyName,
|
|
34871
35032
|
timestamp: row.timestamp,
|
|
@@ -34880,7 +35041,7 @@ var init_native = __esm({
|
|
|
34880
35041
|
});
|
|
34881
35042
|
if (discoveryOnly) {
|
|
34882
35043
|
eventInputs.push({
|
|
34883
|
-
signalId
|
|
35044
|
+
signalId,
|
|
34884
35045
|
timestamp: row.timestamp,
|
|
34885
35046
|
symbol: row.symbol,
|
|
34886
35047
|
direction: row.direction,
|
|
@@ -34891,8 +35052,8 @@ var init_native = __esm({
|
|
|
34891
35052
|
});
|
|
34892
35053
|
const key = `${row.direction}:${trade.netProfit > 0}`;
|
|
34893
35054
|
const bucket = sampleBuckets.get(key) ?? [];
|
|
34894
|
-
bucket.push(
|
|
34895
|
-
sampleInputs.set(
|
|
35055
|
+
bucket.push(signalId);
|
|
35056
|
+
sampleInputs.set(signalId, row);
|
|
34896
35057
|
bucket.sort((a, b) => sha256Json(a).localeCompare(sha256Json(b)));
|
|
34897
35058
|
while (bucket.length > spec.diagnostics.samplePerSideAndOutcome)
|
|
34898
35059
|
sampleInputs.delete(bucket.pop());
|
|
@@ -34927,7 +35088,7 @@ var init_native = __esm({
|
|
|
34927
35088
|
grouped.set(input.symbol, group);
|
|
34928
35089
|
}
|
|
34929
35090
|
for (const [symbol, events] of grouped) {
|
|
34930
|
-
const intervalMs = (0,
|
|
35091
|
+
const intervalMs = (0, import_data9.intervalToMs)(
|
|
34931
35092
|
spec.core.execution.interval
|
|
34932
35093
|
);
|
|
34933
35094
|
const candles = await provider.kline({
|
|
@@ -34960,7 +35121,7 @@ var init_native = __esm({
|
|
|
34960
35121
|
const trade = tradeBySignal.get(row.signalId);
|
|
34961
35122
|
const original = sampleInputs.get(row.signalId);
|
|
34962
35123
|
if (!trade || !original) continue;
|
|
34963
|
-
const intervalMs = (0,
|
|
35124
|
+
const intervalMs = (0, import_data9.intervalToMs)(
|
|
34964
35125
|
spec.core.execution.interval
|
|
34965
35126
|
);
|
|
34966
35127
|
const candles = await provider.kline({
|