@tradejs/cli 2.0.0 → 2.0.1

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 CHANGED
@@ -6151,7 +6151,6 @@ var init_aiTrainResearch = __esm({
6151
6151
  "INTERVAL",
6152
6152
  "DERIVATIVES_CONTEXT_ENABLED",
6153
6153
  "DERIVATIVES_CONTEXT_TARGET_ENABLED",
6154
- "DERIVATIVES_CONTEXT_INTERVALS",
6155
6154
  "DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
6156
6155
  "DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
6157
6156
  "DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
@@ -8591,7 +8590,7 @@ var init_binanceMarketContextBackfill = __esm({
8591
8590
  });
8592
8591
 
8593
8592
  // src/lib/derivativesContextBackfill.ts
8594
- var import_chalk7, import_progress4, import_async, import_constants5, import_indicators, import_timescale2, import_userSettings2, HOUR_MS, DAY_MS6, DEFAULT_LOOKBACK_HOURS, DEFAULT_INTERVALS, coinalyzeIntervalMap, derivativesIntervalMs, lastRequestTs, asInt2, parseList, parseBooleanFlag, normalizeSymbols, isDerivativesTargetContextEnabled, resolveDerivativesContextBackfillSymbols, chunkArray, isBacktestDerivativesContextEnabled, isSignalsDerivativesContextEnabled, isDerivativesContextBackfillEnabled, shouldBackfillDerivativesContextForBacktest, shouldBackfillDerivativesContextForSignals, resolveDerivativesContextIntervals, resolveDerivativesContextLookbackMs, resolveDerivativesContextBackfillWindow, resolveDerivativesContextIntervalBackfillWindow, resolveDerivativesContextMissingFetchFromMs, countBackfillWindows, buildBackfillWindows, hasDerivativesWindowCoverage, resolveDerivativesContextMissingCoverageFetchFromMs, groupDerivativesContextMissingFetchRanges, coverageKey, extendEdges, getCoinalyzeApiKey, getCoinalyzeBaseUrl, getRequestDelayMs, getRequestTimeoutMs, networkErrorCodes, getNestedErrorValue, getCoinalyzeErrorCause, isRetryableCoinalyzeFetchError, formatCoinalyzeRequestError, fetchJsonWithRateLimit, fetchCoinalyzeMarkets, selectBestMarket, buildMatches, normalizeMetricPoint, toSeriesMap, fetchMetricBatch, skippedBackfillResult2, backfillDerivativesContext, backfillDerivativesContextForBacktest, backfillDerivativesContextForSignals;
8593
+ var import_chalk7, import_progress4, import_async, import_constants5, import_indicators, import_timescale2, import_userSettings2, HOUR_MS, DAY_MS6, DEFAULT_LOOKBACK_HOURS, SOURCE_INTERVALS, coinalyzeIntervalMap, derivativesIntervalMs, lastRequestTs, asInt2, parseList, parseBooleanFlag, normalizeSymbols, isDerivativesTargetContextEnabled, resolveDerivativesContextBackfillSymbols, chunkArray, isBacktestDerivativesContextEnabled, isSignalsDerivativesContextEnabled, isDerivativesContextBackfillEnabled, shouldBackfillDerivativesContextForBacktest, shouldBackfillDerivativesContextForSignals, resolveDerivativesContextIntervals, resolveDerivativesContextLookbackMs, resolveDerivativesContextBackfillWindow, resolveDerivativesContextIntervalBackfillWindow, resolveDerivativesContextMissingFetchFromMs, resolveDerivativesContextFetchFromMs, countBackfillWindows, buildBackfillWindows, hasDerivativesWindowCoverage, resolveDerivativesContextMissingCoverageFetchFromMs, groupDerivativesContextMissingFetchRanges, getMissingClosedDerivativesSymbols, coverageKey, extendEdges, getCoinalyzeApiKey, getCoinalyzeBaseUrl, getRequestDelayMs, getRequestTimeoutMs, networkErrorCodes, getNestedErrorValue, getCoinalyzeErrorCause, isRetryableCoinalyzeFetchError, formatCoinalyzeRequestError, fetchJsonWithRateLimit, fetchCoinalyzeMarkets, selectBestMarket, buildMatches, normalizeMetricPoint, toSeriesMap, fetchMetricBatch, skippedBackfillResult2, backfillDerivativesContext, backfillDerivativesContextForBacktest, backfillDerivativesContextForSignals;
8595
8594
  var init_derivativesContextBackfill = __esm({
8596
8595
  "src/lib/derivativesContextBackfill.ts"() {
8597
8596
  "use strict";
@@ -8605,7 +8604,7 @@ var init_derivativesContextBackfill = __esm({
8605
8604
  HOUR_MS = 60 * 60 * 1e3;
8606
8605
  DAY_MS6 = 24 * HOUR_MS;
8607
8606
  DEFAULT_LOOKBACK_HOURS = 48;
8608
- DEFAULT_INTERVALS = ["15m", "1h"];
8607
+ SOURCE_INTERVALS = ["15m"];
8609
8608
  coinalyzeIntervalMap = {
8610
8609
  "15m": "15min",
8611
8610
  "1h": "1hour"
@@ -8666,10 +8665,7 @@ var init_derivativesContextBackfill = __esm({
8666
8665
  shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
8667
8666
  shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
8668
8667
  resolveDerivativesContextIntervals = () => {
8669
- const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
8670
- process.env.DERIVATIVES_CONTEXT_INTERVALS
8671
- );
8672
- return intervals.length ? intervals : DEFAULT_INTERVALS;
8668
+ return [...SOURCE_INTERVALS];
8673
8669
  };
8674
8670
  resolveDerivativesContextLookbackMs = () => {
8675
8671
  const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
@@ -8704,9 +8700,10 @@ var init_derivativesContextBackfill = __esm({
8704
8700
  };
8705
8701
  resolveDerivativesContextIntervalBackfillWindow = (params) => {
8706
8702
  const intervalMs2 = derivativesIntervalMs(params.interval);
8703
+ const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs2) * intervalMs2;
8707
8704
  return {
8708
8705
  fromMs: Math.floor(params.fromMs / intervalMs2) * intervalMs2,
8709
- toMs: Math.floor(params.toMs / intervalMs2) * intervalMs2,
8706
+ toMs: alignedToMs,
8710
8707
  intervalMs: intervalMs2
8711
8708
  };
8712
8709
  };
@@ -8724,6 +8721,7 @@ var init_derivativesContextBackfill = __esm({
8724
8721
  }
8725
8722
  return null;
8726
8723
  };
8724
+ resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
8727
8725
  countBackfillWindows = (params) => {
8728
8726
  let count = 0;
8729
8727
  let cursor = params.fromMs;
@@ -8787,6 +8785,14 @@ var init_derivativesContextBackfill = __esm({
8787
8785
  }
8788
8786
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
8789
8787
  };
8788
+ getMissingClosedDerivativesSymbols = (params) => {
8789
+ const availableSymbols = new Set(
8790
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
8791
+ );
8792
+ return params.symbols.filter(
8793
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
8794
+ );
8795
+ };
8790
8796
  coverageKey = (params) => [
8791
8797
  params.symbol.trim().toUpperCase(),
8792
8798
  params.interval,
@@ -9066,7 +9072,8 @@ var init_derivativesContextBackfill = __esm({
9066
9072
  ...resolveDerivativesContextIntervalBackfillWindow({
9067
9073
  fromMs,
9068
9074
  toMs: safeEndMs,
9069
- interval: interval5
9075
+ interval: interval5,
9076
+ closedOnly: mode === "signals"
9070
9077
  })
9071
9078
  })).filter((item) => item.toMs > item.fromMs);
9072
9079
  if (!intervalWindows.length) {
@@ -9125,7 +9132,7 @@ var init_derivativesContextBackfill = __esm({
9125
9132
  }),
9126
9133
  0
9127
9134
  );
9128
- const allBackfillWindowsCached = intervalWindows.every((window2) => {
9135
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
9129
9136
  const edgesBySymbol = edgesByInterval.get(window2.interval);
9130
9137
  const coverageKeys = coverageKeysByInterval.get(window2.interval);
9131
9138
  const backfillWindows = buildBackfillWindows({
@@ -9255,7 +9262,7 @@ var init_derivativesContextBackfill = __esm({
9255
9262
  return null;
9256
9263
  }
9257
9264
  const normalizedSymbol = item.symbol.toUpperCase();
9258
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
9265
+ const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
9259
9266
  ranges: coverageRangesBySymbol.get(normalizedSymbol),
9260
9267
  fromMs: cursor,
9261
9268
  toMs,
@@ -9265,16 +9272,20 @@ var init_derivativesContextBackfill = __esm({
9265
9272
  return null;
9266
9273
  }
9267
9274
  const edges = edgesBySymbol.get(normalizedSymbol);
9268
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
9275
+ const edgesFromMs = resolveDerivativesContextFetchFromMs({
9269
9276
  edges,
9270
9277
  fromMs: cursor,
9271
9278
  toMs,
9272
- intervalMs: intervalMs2
9279
+ intervalMs: intervalMs2,
9280
+ refreshClosedTail: mode === "signals"
9273
9281
  });
9274
9282
  if (edgesFromMs == null) {
9275
9283
  return null;
9276
9284
  }
9277
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
9285
+ return {
9286
+ item,
9287
+ fromMs: Math.max(coverageFromMs, edgesFromMs)
9288
+ };
9278
9289
  }).filter(
9279
9290
  (item) => item != null
9280
9291
  );
@@ -9288,85 +9299,113 @@ var init_derivativesContextBackfill = __esm({
9288
9299
  const marketSymbols = missingBatch.map(
9289
9300
  (item) => item.marketSymbol
9290
9301
  );
9291
- const oiMap = await fetchMetricBatch({
9292
- endpoint: oiPath,
9293
- metric: "oi",
9294
- marketSymbols,
9295
- apiKey,
9296
- interval: interval5,
9297
- fromMs: group.fromMs,
9298
- toMs
9299
- });
9300
- const fundingMap = await fetchMetricBatch({
9301
- endpoint: fundingPath,
9302
- metric: "funding",
9303
- marketSymbols,
9304
- apiKey,
9305
- interval: interval5,
9306
- fromMs: group.fromMs,
9307
- toMs
9308
- });
9309
- const liqMap = await fetchMetricBatch({
9310
- endpoint: liqPath,
9311
- metric: "liq",
9312
- marketSymbols,
9313
- apiKey,
9314
- interval: interval5,
9315
- fromMs: group.fromMs,
9316
- toMs
9317
- });
9318
- const rows = missingBatch.flatMap((item) => {
9319
- const marketSymbol = item.marketSymbol.toUpperCase();
9320
- const points = (0, import_indicators.mergeCoinalyzeMetrics)({
9321
- symbol: item.symbol,
9322
- oiRaw: oiMap.get(marketSymbol) ?? [],
9323
- fundingRaw: fundingMap.get(marketSymbol) ?? [],
9324
- liqRaw: liqMap.get(marketSymbol) ?? []
9302
+ const maxClosedBarAttempts = mode === "signals" ? asInt2(
9303
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
9304
+ 3
9305
+ ) : 1;
9306
+ const closedBarRetryDelayMs = asInt2(
9307
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
9308
+ 2e3
9309
+ );
9310
+ let rows = [];
9311
+ let missingClosedSymbols = [];
9312
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
9313
+ const oiMap = await fetchMetricBatch({
9314
+ endpoint: oiPath,
9315
+ metric: "oi",
9316
+ marketSymbols,
9317
+ apiKey,
9318
+ interval: interval5,
9319
+ fromMs: group.fromMs,
9320
+ toMs
9321
+ });
9322
+ const fundingMap = await fetchMetricBatch({
9323
+ endpoint: fundingPath,
9324
+ metric: "funding",
9325
+ marketSymbols,
9326
+ apiKey,
9327
+ interval: interval5,
9328
+ fromMs: group.fromMs,
9329
+ toMs
9330
+ });
9331
+ const liqMap = await fetchMetricBatch({
9332
+ endpoint: liqPath,
9333
+ metric: "liq",
9334
+ marketSymbols,
9335
+ apiKey,
9336
+ interval: interval5,
9337
+ fromMs: group.fromMs,
9338
+ toMs
9325
9339
  });
9326
- return (0, import_indicators.coinalyzePointsToRows)(points, interval5, "coinalyze");
9327
- });
9340
+ rows = missingBatch.flatMap((item) => {
9341
+ const marketSymbol = item.marketSymbol.toUpperCase();
9342
+ const points = (0, import_indicators.mergeCoinalyzeMetrics)({
9343
+ symbol: item.symbol,
9344
+ oiRaw: oiMap.get(marketSymbol) ?? [],
9345
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
9346
+ liqRaw: liqMap.get(marketSymbol) ?? []
9347
+ });
9348
+ return (0, import_indicators.coinalyzePointsToRows)(points, interval5, "coinalyze");
9349
+ });
9350
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
9351
+ symbols: missingBatch.map((item) => item.symbol),
9352
+ rows,
9353
+ expectedTimestamp: toMs
9354
+ }) : [];
9355
+ if (!missingClosedSymbols.length) break;
9356
+ if (attempt < maxClosedBarAttempts) {
9357
+ await (0, import_async.delay)(closedBarRetryDelayMs);
9358
+ }
9359
+ }
9360
+ if (missingClosedSymbols.length) {
9361
+ throw new Error(
9362
+ `Coinalyze closed ${interval5} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
9363
+ );
9364
+ }
9328
9365
  if (rows.length) {
9329
9366
  await (0, import_timescale2.upsertDerivatives)(rows);
9330
9367
  totalRows += rows.length;
9331
9368
  }
9332
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
9333
- for (const row of rows) {
9334
- const symbol = row.symbol.toUpperCase();
9335
- rowsCountBySymbol.set(
9336
- symbol,
9337
- (rowsCountBySymbol.get(symbol) ?? 0) + 1
9338
- );
9339
- }
9340
- const coverageRows = missingBatch.map((item) => {
9341
- const normalizedSymbol = item.symbol.toUpperCase();
9342
- const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
9343
- return {
9344
- source: "coinalyze",
9345
- symbol: item.symbol,
9346
- interval: interval5,
9347
- fromMs: cursor,
9348
- toMs,
9349
- rowsCount
9350
- };
9351
- });
9352
- await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
9353
- for (const coverageRow of coverageRows) {
9354
- const symbol = coverageRow.symbol.toUpperCase();
9355
- edgesBySymbol.set(
9356
- symbol,
9357
- extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
9358
- );
9359
- coverageKeys.add(
9360
- coverageKey({
9369
+ if (mode === "backtest") {
9370
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
9371
+ for (const row of rows) {
9372
+ const symbol = row.symbol.toUpperCase();
9373
+ rowsCountBySymbol.set(
9361
9374
  symbol,
9375
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
9376
+ );
9377
+ }
9378
+ const coverageRows = missingBatch.map((item) => {
9379
+ const normalizedSymbol = item.symbol.toUpperCase();
9380
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
9381
+ return {
9382
+ source: "coinalyze",
9383
+ symbol: item.symbol,
9362
9384
  interval: interval5,
9363
9385
  fromMs: cursor,
9364
- toMs
9365
- })
9366
- );
9367
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
9368
- coverageRanges.push({ fromMs: cursor, toMs });
9369
- coverageRangesBySymbol.set(symbol, coverageRanges);
9386
+ toMs,
9387
+ rowsCount
9388
+ };
9389
+ });
9390
+ await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
9391
+ for (const coverageRow of coverageRows) {
9392
+ const symbol = coverageRow.symbol.toUpperCase();
9393
+ edgesBySymbol.set(
9394
+ symbol,
9395
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
9396
+ );
9397
+ coverageKeys.add(
9398
+ coverageKey({
9399
+ symbol,
9400
+ interval: interval5,
9401
+ fromMs: cursor,
9402
+ toMs
9403
+ })
9404
+ );
9405
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
9406
+ coverageRanges.push({ fromMs: cursor, toMs });
9407
+ coverageRangesBySymbol.set(symbol, coverageRanges);
9408
+ }
9370
9409
  }
9371
9410
  }
9372
9411
  }
@@ -18915,11 +18954,11 @@ var init_derivativesIngest = __esm({
18915
18954
  import_userSettings4 = require("@tradejs/infra/userSettings");
18916
18955
  import_connectors9 = require("@tradejs/connectors");
18917
18956
  import_args12.default.example(
18918
- "yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m,1h --days 120",
18957
+ "yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m --days 120",
18919
18958
  "Ingest market features (derivatives/spread) into Timescale by provider"
18920
18959
  );
18921
18960
  import_args12.default.option(["s", "symbols"], "Comma-separated symbols", "BTCUSDT,ETHUSDT");
18922
- import_args12.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m,1h");
18961
+ import_args12.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m");
18923
18962
  import_args12.default.option(["d", "days"], "Lookback in days", 120);
18924
18963
  import_args12.default.option(
18925
18964
  ["p", "provider"],
@@ -18956,9 +18995,16 @@ var init_derivativesIngest = __esm({
18956
18995
  let totalSpreadRows = 0;
18957
18996
  for (const symbol of symbols) {
18958
18997
  for (const interval5 of intervals) {
18998
+ const lastClosedStartMs = (0, import_indicators2.getLastClosedDerivativesBarStartMs)(
18999
+ now2,
19000
+ interval5
19001
+ );
18959
19002
  let cursor = fromMs;
18960
- while (cursor < now2) {
18961
- const toMs = Math.min(now2, cursor + batchDays * 24 * 60 * 60 * 1e3);
19003
+ while (cursor < lastClosedStartMs) {
19004
+ const toMs = Math.min(
19005
+ lastClosedStartMs,
19006
+ cursor + batchDays * 24 * 60 * 60 * 1e3
19007
+ );
18962
19008
  process.stdout.write(
18963
19009
  `\r${import_chalk20.default.cyan(providerName)} ${import_chalk20.default.yellow(symbol)} ${interval5} ${new Date(cursor).toISOString()} .. ${new Date(toMs).toISOString()} `
18964
19010
  );
@@ -19018,7 +19064,7 @@ var init_derivativesIngestCoinalyzeAll = __esm({
19018
19064
  "1h": "1hour"
19019
19065
  };
19020
19066
  import_args13.default.example(
19021
- "yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m,1h",
19067
+ "yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m",
19022
19068
  "Fetch derivatives for all getTickers symbols matched to Coinalyze markets"
19023
19069
  );
19024
19070
  import_args13.default.option(["U", "user"], "User settings profile name from Redis", "root");
@@ -19026,7 +19072,7 @@ var init_derivativesIngestCoinalyzeAll = __esm({
19026
19072
  import_args13.default.option(["e", "exclude"], "Comma-separated exclude symbols");
19027
19073
  import_args13.default.option(["l", "tickersLimit"], "Tickers limit");
19028
19074
  import_args13.default.option(["c", "chunk"], "Chunk selector, e.g. 1/4");
19029
- import_args13.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m,1h");
19075
+ import_args13.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m");
19030
19076
  import_args13.default.option(["d", "days"], "Lookback in days", 120);
19031
19077
  import_args13.default.option(["b", "batchDays"], "Request chunk size in days", 120);
19032
19078
  import_args13.default.option(
@@ -19295,12 +19341,16 @@ var init_derivativesIngestCoinalyzeAll = __esm({
19295
19341
  let totalRows = 0;
19296
19342
  let failedWindows = 0;
19297
19343
  for (const interval5 of intervals) {
19344
+ const lastClosedStartMs = (0, import_indicators3.getLastClosedDerivativesBarStartMs)(now2, interval5);
19298
19345
  for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
19299
19346
  const batch = symbolBatches[batchIdx];
19300
19347
  const marketSymbols = batch.map((item) => item.marketSymbol);
19301
19348
  let cursor = fromMs;
19302
- while (cursor < now2) {
19303
- const toMs = Math.min(now2, cursor + batchDays * 24 * 60 * 60 * 1e3);
19349
+ while (cursor < lastClosedStartMs) {
19350
+ const toMs = Math.min(
19351
+ lastClosedStartMs,
19352
+ cursor + batchDays * 24 * 60 * 60 * 1e3
19353
+ );
19304
19354
  try {
19305
19355
  const oiMap = await fetchMetricBatch2({
19306
19356
  endpoint: oiPath,
@@ -273,7 +273,6 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
273
273
  "INTERVAL",
274
274
  "DERIVATIVES_CONTEXT_ENABLED",
275
275
  "DERIVATIVES_CONTEXT_TARGET_ENABLED",
276
- "DERIVATIVES_CONTEXT_INTERVALS",
277
276
  "DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
278
277
  "DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
279
278
  "DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",