@tradejs/node 3.1.29-beta.288 → 3.1.29-beta.290
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backtest.js +442 -234
- package/dist/backtest.mjs +10 -5
- package/dist/{chunk-F7CLF3PT.mjs → chunk-PB2KHBGH.mjs} +415 -212
- package/dist/cli.js +3 -2
- package/dist/cli.mjs +3 -2
- package/dist/diagnostics.js +416 -213
- package/dist/diagnostics.mjs +1 -1
- package/dist/mcp.d.mts +3 -1
- package/dist/mcp.d.ts +3 -1
- package/dist/mcp.js +455 -230
- package/dist/mcp.mjs +24 -3
- package/dist/registry.js +416 -213
- package/dist/registry.mjs +1 -1
- package/dist/runtimeDashboard.js +418 -215
- package/dist/runtimeDashboard.mjs +1 -1
- package/dist/runtimeStrategies.js +416 -213
- package/dist/runtimeStrategies.mjs +1 -1
- package/dist/strategies.d.mts +32 -22
- package/dist/strategies.d.ts +32 -22
- package/dist/strategies.js +424 -221
- package/dist/strategies.mjs +1 -1
- package/package.json +5 -5
|
@@ -1048,13 +1048,210 @@ var assessSignalWithJev = async ({
|
|
|
1048
1048
|
// src/strategyRuntime.ts
|
|
1049
1049
|
var import_constants5 = require("@tradejs/core/constants");
|
|
1050
1050
|
var import_strategies6 = require("@tradejs/core/strategies");
|
|
1051
|
-
var
|
|
1051
|
+
var import_logger11 = require("@tradejs/infra/logger");
|
|
1052
1052
|
|
|
1053
1053
|
// src/strategyHelpers/runtime.ts
|
|
1054
|
-
var
|
|
1054
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
1055
1055
|
var import_constants3 = require("@tradejs/core/constants");
|
|
1056
1056
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
1057
1057
|
|
|
1058
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1059
|
+
var import_logger = require("@tradejs/infra/logger");
|
|
1060
|
+
|
|
1061
|
+
// src/strategy/entryExecutionValidation.ts
|
|
1062
|
+
var EntrySubmissionValidationError = class extends Error {
|
|
1063
|
+
constructor() {
|
|
1064
|
+
super(...arguments);
|
|
1065
|
+
this.name = "EntrySubmissionValidationError";
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
var resolveEntryExecutionLimits = (config, direction) => {
|
|
1069
|
+
const side = config[direction];
|
|
1070
|
+
const minimum = side && typeof side === "object" && "minRiskRatio" in side ? side.minRiskRatio : void 0;
|
|
1071
|
+
const maximum = config.MAX_LOSS_VALUE;
|
|
1072
|
+
if (minimum == null && maximum == null) return void 0;
|
|
1073
|
+
const minimumNetRiskRatio = minimum == null ? void 0 : Number(minimum);
|
|
1074
|
+
const maxLossValue = maximum == null ? void 0 : Number(maximum);
|
|
1075
|
+
const feeRate = Number(config.RISK_FEE_RATE ?? 0);
|
|
1076
|
+
const slippage = Number(config.RISK_SLIPPAGE_BPS ?? 0);
|
|
1077
|
+
const impact = Number(config.RISK_MARKET_IMPACT_BPS ?? 0);
|
|
1078
|
+
const slippageBps = slippage + impact;
|
|
1079
|
+
if (minimumNetRiskRatio != null && (!Number.isFinite(minimumNetRiskRatio) || minimumNetRiskRatio < 0) || maxLossValue != null && (!Number.isFinite(maxLossValue) || maxLossValue <= 0) || !Number.isFinite(feeRate) || feeRate < 0 || feeRate >= 1 || !Number.isFinite(slippage) || slippage < 0 || !Number.isFinite(impact) || impact < 0 || !Number.isFinite(slippageBps) || slippageBps < 0 || slippageBps >= 1e4)
|
|
1080
|
+
throw new Error("INVALID_ENTRY_EXECUTION_LIMITS");
|
|
1081
|
+
return { minimumNetRiskRatio, maxLossValue, feeRate, slippageBps };
|
|
1082
|
+
};
|
|
1083
|
+
var validateEntryExecution = ({
|
|
1084
|
+
direction,
|
|
1085
|
+
price,
|
|
1086
|
+
qty,
|
|
1087
|
+
stopLossPrice,
|
|
1088
|
+
takeProfitPrice,
|
|
1089
|
+
limits
|
|
1090
|
+
}) => {
|
|
1091
|
+
if (!Number.isFinite(price) || price <= 0 || !Number.isFinite(qty) || qty <= 0 || stopLossPrice == null || !Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || !Number.isFinite(takeProfitPrice) || takeProfitPrice <= 0)
|
|
1092
|
+
throw new EntrySubmissionValidationError(
|
|
1093
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1094
|
+
);
|
|
1095
|
+
const side = direction === "LONG" ? 1 : -1;
|
|
1096
|
+
if (side * (price - stopLossPrice) <= 0 || side * (takeProfitPrice - price) <= 0)
|
|
1097
|
+
throw new EntrySubmissionValidationError(
|
|
1098
|
+
"INVALID_ENTRY_PROTECTION_AT_SUBMISSION"
|
|
1099
|
+
);
|
|
1100
|
+
const slippage = limits.slippageBps / 1e4;
|
|
1101
|
+
const cost = (value, sign) => value * slippage + value * (1 + sign * slippage) * limits.feeRate;
|
|
1102
|
+
const entryCost = cost(price, side);
|
|
1103
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + entryCost + cost(stopLossPrice, -side);
|
|
1104
|
+
const rewardPerUnit = Math.max(
|
|
1105
|
+
0,
|
|
1106
|
+
Math.abs(takeProfitPrice - price) - entryCost - cost(takeProfitPrice, -side)
|
|
1107
|
+
);
|
|
1108
|
+
const netRiskRatio = rewardPerUnit / lossPerUnit;
|
|
1109
|
+
const plannedLossValue = qty * lossPerUnit;
|
|
1110
|
+
if (!Number.isFinite(netRiskRatio) || !Number.isFinite(plannedLossValue))
|
|
1111
|
+
throw new EntrySubmissionValidationError(
|
|
1112
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1113
|
+
);
|
|
1114
|
+
if (limits.minimumNetRiskRatio != null && netRiskRatio <= limits.minimumNetRiskRatio)
|
|
1115
|
+
throw new EntrySubmissionValidationError(
|
|
1116
|
+
"ENTRY_RR_BELOW_MIN_AT_SUBMISSION"
|
|
1117
|
+
);
|
|
1118
|
+
const riskExceeded = limits.maxLossValue != null && plannedLossValue > limits.maxLossValue * (1 + 1e-9);
|
|
1119
|
+
return { netRiskRatio, plannedLossValue, riskExceeded };
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1123
|
+
var MAX_ENTRY_QUOTE_AGE_MS = 5e3;
|
|
1124
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1125
|
+
var getOrderArrivalSnapshot = async ({
|
|
1126
|
+
connector,
|
|
1127
|
+
symbol,
|
|
1128
|
+
requireTimestamp = false
|
|
1129
|
+
}) => {
|
|
1130
|
+
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
1131
|
+
return {
|
|
1132
|
+
arrivalSnapshotTime: Date.now(),
|
|
1133
|
+
arrivalSource: "unavailable",
|
|
1134
|
+
bid: null,
|
|
1135
|
+
ask: null,
|
|
1136
|
+
arrivalMid: null,
|
|
1137
|
+
spreadBps: null
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
1142
|
+
const arrivalSnapshotTime = toFiniteNumberOrNull(ticker?.timestamp);
|
|
1143
|
+
const timestampUnavailable = requireTimestamp && arrivalSnapshotTime == null;
|
|
1144
|
+
const bid = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.bidPrice);
|
|
1145
|
+
const ask = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.askPrice);
|
|
1146
|
+
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
1147
|
+
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
1148
|
+
return {
|
|
1149
|
+
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
1150
|
+
arrivalSource: "top_of_book",
|
|
1151
|
+
bid,
|
|
1152
|
+
ask,
|
|
1153
|
+
arrivalMid,
|
|
1154
|
+
spreadBps
|
|
1155
|
+
};
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
import_logger.logger.warn(
|
|
1158
|
+
"runtime order arrival snapshot failed: %s %s",
|
|
1159
|
+
symbol,
|
|
1160
|
+
error?.message || String(error)
|
|
1161
|
+
);
|
|
1162
|
+
return {
|
|
1163
|
+
arrivalSnapshotTime: Date.now(),
|
|
1164
|
+
arrivalSource: "top_of_book_error",
|
|
1165
|
+
bid: null,
|
|
1166
|
+
ask: null,
|
|
1167
|
+
arrivalMid: null,
|
|
1168
|
+
spreadBps: null
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
var validateEntryProtectionAtArrival = ({
|
|
1173
|
+
direction,
|
|
1174
|
+
signalPrice,
|
|
1175
|
+
bid,
|
|
1176
|
+
ask,
|
|
1177
|
+
arrivalMid,
|
|
1178
|
+
takeProfits,
|
|
1179
|
+
stopLossPrice
|
|
1180
|
+
}) => {
|
|
1181
|
+
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
1182
|
+
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
1183
|
+
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
1184
|
+
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
1185
|
+
}
|
|
1186
|
+
for (const takeProfit of takeProfits) {
|
|
1187
|
+
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
1188
|
+
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
1192
|
+
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
var createEntrySubmissionValidation = ({
|
|
1196
|
+
connector,
|
|
1197
|
+
symbol,
|
|
1198
|
+
direction,
|
|
1199
|
+
takeProfits,
|
|
1200
|
+
stopLossPrice,
|
|
1201
|
+
limits,
|
|
1202
|
+
onValidated
|
|
1203
|
+
}) => {
|
|
1204
|
+
if (!limits) return void 0;
|
|
1205
|
+
if (!connector.capabilities?.orderSubmissionValidation)
|
|
1206
|
+
throw new EntrySubmissionValidationError(
|
|
1207
|
+
"ENTRY_SUBMISSION_VALIDATION_UNSUPPORTED"
|
|
1208
|
+
);
|
|
1209
|
+
return async ({ qty, executionPrice }) => {
|
|
1210
|
+
const simulated = Reflect.get(connector, "__tradejsTestConnector") === true;
|
|
1211
|
+
const snapshot2 = simulated && executionPrice != null ? {
|
|
1212
|
+
arrivalSnapshotTime: Date.now(),
|
|
1213
|
+
arrivalSource: "simulation",
|
|
1214
|
+
bid: executionPrice,
|
|
1215
|
+
ask: executionPrice,
|
|
1216
|
+
arrivalMid: executionPrice,
|
|
1217
|
+
spreadBps: 0
|
|
1218
|
+
} : await getOrderArrivalSnapshot({
|
|
1219
|
+
connector,
|
|
1220
|
+
symbol,
|
|
1221
|
+
requireTimestamp: true
|
|
1222
|
+
});
|
|
1223
|
+
const age = Date.now() - snapshot2.arrivalSnapshotTime;
|
|
1224
|
+
if (snapshot2.bid == null || snapshot2.ask == null || !Number.isFinite(snapshot2.bid) || !Number.isFinite(snapshot2.ask) || snapshot2.bid <= 0 || snapshot2.ask < snapshot2.bid)
|
|
1225
|
+
throw new EntrySubmissionValidationError(
|
|
1226
|
+
"ENTRY_QUOTE_UNAVAILABLE_AT_SUBMISSION"
|
|
1227
|
+
);
|
|
1228
|
+
if (!Number.isFinite(age) || age < -MAX_ENTRY_QUOTE_AGE_MS || age > MAX_ENTRY_QUOTE_AGE_MS)
|
|
1229
|
+
throw new EntrySubmissionValidationError(
|
|
1230
|
+
"ENTRY_QUOTE_STALE_AT_SUBMISSION"
|
|
1231
|
+
);
|
|
1232
|
+
const price = direction === "LONG" ? snapshot2.ask : snapshot2.bid;
|
|
1233
|
+
validateEntryProtectionAtArrival({
|
|
1234
|
+
direction,
|
|
1235
|
+
signalPrice: price,
|
|
1236
|
+
bid: snapshot2.bid,
|
|
1237
|
+
ask: snapshot2.ask,
|
|
1238
|
+
arrivalMid: snapshot2.arrivalMid,
|
|
1239
|
+
takeProfits,
|
|
1240
|
+
stopLossPrice
|
|
1241
|
+
});
|
|
1242
|
+
const prices = takeProfits.map((tp) => tp.price);
|
|
1243
|
+
const economics2 = validateEntryExecution({
|
|
1244
|
+
direction,
|
|
1245
|
+
price,
|
|
1246
|
+
qty,
|
|
1247
|
+
stopLossPrice,
|
|
1248
|
+
takeProfitPrice: direction === "LONG" ? Math.max(...prices) : Math.min(...prices),
|
|
1249
|
+
limits
|
|
1250
|
+
});
|
|
1251
|
+
onValidated?.(snapshot2, economics2);
|
|
1252
|
+
};
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1058
1255
|
// src/ai.ts
|
|
1059
1256
|
var import_aiLanguages2 = require("@tradejs/core/aiLanguages");
|
|
1060
1257
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -1639,7 +1836,7 @@ var import_fs = __toESM(require("fs"));
|
|
|
1639
1836
|
var import_path = __toESM(require("path"));
|
|
1640
1837
|
var import_url = require("url");
|
|
1641
1838
|
var import_config = require("@tradejs/core/config");
|
|
1642
|
-
var
|
|
1839
|
+
var import_logger2 = require("@tradejs/infra/logger");
|
|
1643
1840
|
var CONFIG_FILE_NAMES = [
|
|
1644
1841
|
"tradejs.config.ts",
|
|
1645
1842
|
"tradejs.config.mts",
|
|
@@ -1906,11 +2103,11 @@ var loadTradejsConfig = async (cwd = getTradejsProjectCwd()) => {
|
|
|
1906
2103
|
cachedByCwd.set(cwd, config);
|
|
1907
2104
|
if (!announcedConfigFile.has(configFilePath)) {
|
|
1908
2105
|
announcedConfigFile.add(configFilePath);
|
|
1909
|
-
|
|
2106
|
+
import_logger2.logger.log("debug", "Loaded TradeJS config: %s", configFilePath);
|
|
1910
2107
|
}
|
|
1911
2108
|
return config;
|
|
1912
2109
|
} catch (error) {
|
|
1913
|
-
|
|
2110
|
+
import_logger2.logger.log(
|
|
1914
2111
|
"warn",
|
|
1915
2112
|
"Failed to load TradeJS config from %s: %s",
|
|
1916
2113
|
configFilePath,
|
|
@@ -2876,7 +3073,7 @@ var import_node_crypto = require("crypto");
|
|
|
2876
3073
|
var import_constants = require("@tradejs/core/constants");
|
|
2877
3074
|
var import_time = require("@tradejs/core/time");
|
|
2878
3075
|
var import_trade = require("@tradejs/core/trade");
|
|
2879
|
-
var
|
|
3076
|
+
var import_logger3 = require("@tradejs/infra/logger");
|
|
2880
3077
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
2881
3078
|
var now = () => Date.now();
|
|
2882
3079
|
var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
|
|
@@ -2935,7 +3132,7 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
2935
3132
|
)
|
|
2936
3133
|
]);
|
|
2937
3134
|
} catch (error) {
|
|
2938
|
-
|
|
3135
|
+
import_logger3.logger.error(
|
|
2939
3136
|
"runtime trade open journal failed: %s %s",
|
|
2940
3137
|
record.symbol,
|
|
2941
3138
|
error?.message || String(error)
|
|
@@ -3003,7 +3200,7 @@ var recordRuntimeTradeIncrease = async (params) => {
|
|
|
3003
3200
|
)
|
|
3004
3201
|
]);
|
|
3005
3202
|
} catch (error) {
|
|
3006
|
-
|
|
3203
|
+
import_logger3.logger.error(
|
|
3007
3204
|
"runtime trade increase journal failed: %s %s",
|
|
3008
3205
|
symbol,
|
|
3009
3206
|
error?.message || String(error)
|
|
@@ -3110,7 +3307,7 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3110
3307
|
)
|
|
3111
3308
|
]);
|
|
3112
3309
|
} catch (error) {
|
|
3113
|
-
|
|
3310
|
+
import_logger3.logger.error(
|
|
3114
3311
|
"runtime trade close journal failed: %s %s",
|
|
3115
3312
|
symbol,
|
|
3116
3313
|
error?.message || String(error)
|
|
@@ -3120,11 +3317,11 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3120
3317
|
};
|
|
3121
3318
|
|
|
3122
3319
|
// src/strategyHelpers/marketContextStages.ts
|
|
3123
|
-
var
|
|
3320
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
3124
3321
|
|
|
3125
3322
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
3126
3323
|
var import_marketContext = require("@tradejs/infra/timescale/marketContext");
|
|
3127
|
-
var
|
|
3324
|
+
var import_logger4 = require("@tradejs/infra/logger");
|
|
3128
3325
|
var import_strategies = require("@tradejs/core/strategies");
|
|
3129
3326
|
|
|
3130
3327
|
// src/binanceBreadthUniverses.ts
|
|
@@ -3488,7 +3685,7 @@ var parseEnabledFlag = (value, env) => {
|
|
|
3488
3685
|
if (normalized === "live") return env !== "BACKTEST";
|
|
3489
3686
|
return false;
|
|
3490
3687
|
};
|
|
3491
|
-
var
|
|
3688
|
+
var toFiniteNumberOrNull2 = (value) => {
|
|
3492
3689
|
const numeric = typeof value === "number" ? value : Number(value);
|
|
3493
3690
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3494
3691
|
};
|
|
@@ -3613,14 +3810,14 @@ var toTradeFlowContext = (row, interval) => row ? {
|
|
|
3613
3810
|
asOfTs: row.ts.getTime(),
|
|
3614
3811
|
ageMs: row.ageMs,
|
|
3615
3812
|
stale: row.stale,
|
|
3616
|
-
trades:
|
|
3617
|
-
buyPressurePct:
|
|
3618
|
-
buyBaseVolume:
|
|
3619
|
-
sellBaseVolume:
|
|
3620
|
-
buyQuoteVolume:
|
|
3621
|
-
sellQuoteVolume:
|
|
3622
|
-
netBaseDelta:
|
|
3623
|
-
netQuoteDelta:
|
|
3813
|
+
trades: toFiniteNumberOrNull2(row.trades),
|
|
3814
|
+
buyPressurePct: toFiniteNumberOrNull2(row.buyPressurePct),
|
|
3815
|
+
buyBaseVolume: toFiniteNumberOrNull2(row.buyBaseVolume),
|
|
3816
|
+
sellBaseVolume: toFiniteNumberOrNull2(row.sellBaseVolume),
|
|
3817
|
+
buyQuoteVolume: toFiniteNumberOrNull2(row.buyQuoteVolume),
|
|
3818
|
+
sellQuoteVolume: toFiniteNumberOrNull2(row.sellQuoteVolume),
|
|
3819
|
+
netBaseDelta: toFiniteNumberOrNull2(row.netBaseDelta),
|
|
3820
|
+
netQuoteDelta: toFiniteNumberOrNull2(row.netQuoteDelta)
|
|
3624
3821
|
} : null;
|
|
3625
3822
|
var getCachedReferenceRows = ({
|
|
3626
3823
|
referenceSymbols,
|
|
@@ -3709,16 +3906,16 @@ var toMarketBreadthContext = (breadth, interval) => ({
|
|
|
3709
3906
|
asOfTs: breadth.ts.getTime(),
|
|
3710
3907
|
ageMs: breadth.ageMs,
|
|
3711
3908
|
stale: breadth.stale,
|
|
3712
|
-
symbolsCount:
|
|
3713
|
-
advancers:
|
|
3714
|
-
decliners:
|
|
3715
|
-
unchanged:
|
|
3716
|
-
advanceDeclineRatio:
|
|
3717
|
-
pctAboveMa20:
|
|
3718
|
-
pctAboveMa50:
|
|
3719
|
-
equalWeightedReturn:
|
|
3720
|
-
volumeWeightedReturn:
|
|
3721
|
-
dispersion:
|
|
3909
|
+
symbolsCount: toFiniteNumberOrNull2(breadth.symbolsCount),
|
|
3910
|
+
advancers: toFiniteNumberOrNull2(breadth.advancers),
|
|
3911
|
+
decliners: toFiniteNumberOrNull2(breadth.decliners),
|
|
3912
|
+
unchanged: toFiniteNumberOrNull2(breadth.unchanged),
|
|
3913
|
+
advanceDeclineRatio: toFiniteNumberOrNull2(breadth.advanceDeclineRatio),
|
|
3914
|
+
pctAboveMa20: toFiniteNumberOrNull2(breadth.pctAboveMa20),
|
|
3915
|
+
pctAboveMa50: toFiniteNumberOrNull2(breadth.pctAboveMa50),
|
|
3916
|
+
equalWeightedReturn: toFiniteNumberOrNull2(breadth.equalWeightedReturn),
|
|
3917
|
+
volumeWeightedReturn: toFiniteNumberOrNull2(breadth.volumeWeightedReturn),
|
|
3918
|
+
dispersion: toFiniteNumberOrNull2(breadth.dispersion)
|
|
3722
3919
|
});
|
|
3723
3920
|
var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
3724
3921
|
const {
|
|
@@ -3819,46 +4016,46 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3819
4016
|
asOfTs: primaryBreadth.ts.getTime(),
|
|
3820
4017
|
ageMs: primaryBreadth.ageMs,
|
|
3821
4018
|
stale: primaryBreadth.stale,
|
|
3822
|
-
btcReturn1h:
|
|
4019
|
+
btcReturn1h: toFiniteNumberOrNull2(
|
|
3823
4020
|
primaryBreadth.btcReturn1h
|
|
3824
4021
|
),
|
|
3825
|
-
btcReturn4h:
|
|
4022
|
+
btcReturn4h: toFiniteNumberOrNull2(
|
|
3826
4023
|
primaryBreadth.btcReturn4h
|
|
3827
4024
|
),
|
|
3828
|
-
btcReturn24h:
|
|
4025
|
+
btcReturn24h: toFiniteNumberOrNull2(
|
|
3829
4026
|
primaryBreadth.btcReturn24h
|
|
3830
4027
|
),
|
|
3831
|
-
altBasketReturn1h:
|
|
4028
|
+
altBasketReturn1h: toFiniteNumberOrNull2(
|
|
3832
4029
|
primaryBreadth.altBasketReturn1h
|
|
3833
4030
|
),
|
|
3834
|
-
altBasketReturn4h:
|
|
4031
|
+
altBasketReturn4h: toFiniteNumberOrNull2(
|
|
3835
4032
|
primaryBreadth.altBasketReturn4h
|
|
3836
4033
|
),
|
|
3837
|
-
altBasketReturn24h:
|
|
4034
|
+
altBasketReturn24h: toFiniteNumberOrNull2(
|
|
3838
4035
|
primaryBreadth.altBasketReturn24h
|
|
3839
4036
|
),
|
|
3840
|
-
btcVsAltReturn1h:
|
|
4037
|
+
btcVsAltReturn1h: toFiniteNumberOrNull2(
|
|
3841
4038
|
primaryBreadth.btcVsAltReturn1h
|
|
3842
4039
|
),
|
|
3843
|
-
btcVsAltReturn4h:
|
|
4040
|
+
btcVsAltReturn4h: toFiniteNumberOrNull2(
|
|
3844
4041
|
primaryBreadth.btcVsAltReturn4h
|
|
3845
4042
|
),
|
|
3846
|
-
btcVsAltReturn24h:
|
|
4043
|
+
btcVsAltReturn24h: toFiniteNumberOrNull2(
|
|
3847
4044
|
primaryBreadth.btcVsAltReturn24h
|
|
3848
4045
|
),
|
|
3849
|
-
btcTurnoverShare1h:
|
|
4046
|
+
btcTurnoverShare1h: toFiniteNumberOrNull2(
|
|
3850
4047
|
primaryBreadth.btcTurnoverShare1h
|
|
3851
4048
|
),
|
|
3852
|
-
btcTurnoverShare24h:
|
|
4049
|
+
btcTurnoverShare24h: toFiniteNumberOrNull2(
|
|
3853
4050
|
primaryBreadth.btcTurnoverShare24h
|
|
3854
4051
|
),
|
|
3855
|
-
btcTurnoverShareChange24h:
|
|
4052
|
+
btcTurnoverShareChange24h: toFiniteNumberOrNull2(
|
|
3856
4053
|
primaryBreadth.btcTurnoverShareChange24h
|
|
3857
4054
|
),
|
|
3858
|
-
altVolToBtcVol24h:
|
|
4055
|
+
altVolToBtcVol24h: toFiniteNumberOrNull2(
|
|
3859
4056
|
primaryBreadth.altVolToBtcVol24h
|
|
3860
4057
|
),
|
|
3861
|
-
altDispersion24h:
|
|
4058
|
+
altDispersion24h: toFiniteNumberOrNull2(
|
|
3862
4059
|
primaryBreadth.altDispersion24h
|
|
3863
4060
|
),
|
|
3864
4061
|
regime: primaryBreadth.btcAltRegime ?? "unknown"
|
|
@@ -3875,7 +4072,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3875
4072
|
throw error;
|
|
3876
4073
|
}
|
|
3877
4074
|
binanceMarketContextUnavailable = true;
|
|
3878
|
-
|
|
4075
|
+
import_logger4.logger.warn(
|
|
3879
4076
|
"Binance market context disabled after Timescale read failure: %s",
|
|
3880
4077
|
String(error)
|
|
3881
4078
|
);
|
|
@@ -3885,7 +4082,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3885
4082
|
|
|
3886
4083
|
// src/strategyHelpers/coinMarketCapContext.ts
|
|
3887
4084
|
var import_strategies2 = require("@tradejs/core/strategies");
|
|
3888
|
-
var
|
|
4085
|
+
var import_logger5 = require("@tradejs/infra/logger");
|
|
3889
4086
|
var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
|
|
3890
4087
|
var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
|
|
3891
4088
|
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
@@ -3923,7 +4120,7 @@ var asInt = (value, fallback) => {
|
|
|
3923
4120
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
3924
4121
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
3925
4122
|
};
|
|
3926
|
-
var
|
|
4123
|
+
var toFiniteNumberOrNull3 = (value) => {
|
|
3927
4124
|
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
3928
4125
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3929
4126
|
};
|
|
@@ -4157,12 +4354,12 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4157
4354
|
const ethRow = references.get("ETHUSDT") ?? null;
|
|
4158
4355
|
const previousBtcRow = previousReferences.get("BTCUSDT") ?? null;
|
|
4159
4356
|
const previousEthRow = previousReferences.get("ETHUSDT") ?? null;
|
|
4160
|
-
const btcMarketCapUsd =
|
|
4161
|
-
const ethMarketCapUsd =
|
|
4162
|
-
const previousBtcMarketCapUsd =
|
|
4357
|
+
const btcMarketCapUsd = toFiniteNumberOrNull3(btcRow?.marketCapUsd);
|
|
4358
|
+
const ethMarketCapUsd = toFiniteNumberOrNull3(ethRow?.marketCapUsd);
|
|
4359
|
+
const previousBtcMarketCapUsd = toFiniteNumberOrNull3(
|
|
4163
4360
|
previousBtcRow?.marketCapUsd
|
|
4164
4361
|
);
|
|
4165
|
-
const previousEthMarketCapUsd =
|
|
4362
|
+
const previousEthMarketCapUsd = toFiniteNumberOrNull3(
|
|
4166
4363
|
previousEthRow?.marketCapUsd
|
|
4167
4364
|
);
|
|
4168
4365
|
const ethBtcMarketCapRatio = safeDivide(ethMarketCapUsd, btcMarketCapUsd);
|
|
@@ -4171,16 +4368,16 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4171
4368
|
previousBtcMarketCapUsd
|
|
4172
4369
|
);
|
|
4173
4370
|
const ethBtcMarketCapRatioChange24hPct = ethBtcMarketCapRatio != null && previousEthBtcMarketCapRatio != null && previousEthBtcMarketCapRatio > 0 ? (ethBtcMarketCapRatio - previousEthBtcMarketCapRatio) / previousEthBtcMarketCapRatio : null;
|
|
4174
|
-
const btcVolumeUsd =
|
|
4175
|
-
const ethVolumeUsd =
|
|
4371
|
+
const btcVolumeUsd = toFiniteNumberOrNull3(btcRow?.volumeUsd);
|
|
4372
|
+
const ethVolumeUsd = toFiniteNumberOrNull3(ethRow?.volumeUsd);
|
|
4176
4373
|
const referenceStale = btcRow?.stale === true || ethRow?.stale === true || !btcRow || !ethRow;
|
|
4177
|
-
const btcDominanceChange24hPct =
|
|
4374
|
+
const btcDominanceChange24hPct = toFiniteNumberOrNull3(
|
|
4178
4375
|
globalRow?.btcDominanceChange24hPct
|
|
4179
4376
|
);
|
|
4180
|
-
const altMarketCapChange24hPct =
|
|
4377
|
+
const altMarketCapChange24hPct = toFiniteNumberOrNull3(
|
|
4181
4378
|
globalRow?.altMarketCapChange24hPct
|
|
4182
4379
|
);
|
|
4183
|
-
const altVolumeChange24hPct =
|
|
4380
|
+
const altVolumeChange24hPct = toFiniteNumberOrNull3(
|
|
4184
4381
|
globalRow?.altVolumeChange24hPct
|
|
4185
4382
|
);
|
|
4186
4383
|
const altLiquidityRegime = globalRow ? toAltLiquidityRegime({
|
|
@@ -4191,19 +4388,19 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4191
4388
|
}) : "unknown";
|
|
4192
4389
|
const exchangeLiquidityRegime = exchangeLiquidityRow ? toExchangeLiquidityRegime({
|
|
4193
4390
|
stale: exchangeLiquidityRow.stale,
|
|
4194
|
-
totalVolumeChange24hPct:
|
|
4391
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4195
4392
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4196
4393
|
),
|
|
4197
4394
|
fallback: exchangeLiquidityRow.liquidityRegime ?? "unknown"
|
|
4198
4395
|
}) : "unknown";
|
|
4199
4396
|
const cmc100Row = indexRows.get("cmc100") ?? null;
|
|
4200
4397
|
const cmc20Row = indexRows.get("cmc20") ?? null;
|
|
4201
|
-
const cmc100Value =
|
|
4202
|
-
const cmc20Value =
|
|
4203
|
-
const cmc100Change24hPct =
|
|
4398
|
+
const cmc100Value = toFiniteNumberOrNull3(cmc100Row?.value);
|
|
4399
|
+
const cmc20Value = toFiniteNumberOrNull3(cmc20Row?.value);
|
|
4400
|
+
const cmc100Change24hPct = toFiniteNumberOrNull3(
|
|
4204
4401
|
cmc100Row?.valueChange24hPct
|
|
4205
4402
|
);
|
|
4206
|
-
const cmc20Change24hPct =
|
|
4403
|
+
const cmc20Change24hPct = toFiniteNumberOrNull3(cmc20Row?.valueChange24hPct);
|
|
4207
4404
|
const cmc20ToCmc100Ratio = safeDivide(cmc20Value, cmc100Value);
|
|
4208
4405
|
const cmc20ToCmc100RatioChange24hPct = cmc20Change24hPct != null && cmc100Change24hPct != null ? (1 + cmc20Change24hPct) / (1 + cmc100Change24hPct) - 1 : null;
|
|
4209
4406
|
const indexStale = cmc100Row?.stale === true || cmc20Row?.stale === true || !cmc100Row || !cmc20Row;
|
|
@@ -4227,41 +4424,41 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4227
4424
|
asOfTs: globalRow.ts.getTime(),
|
|
4228
4425
|
ageMs: globalRow.ageMs,
|
|
4229
4426
|
stale: globalRow.stale,
|
|
4230
|
-
totalMarketCapUsd:
|
|
4427
|
+
totalMarketCapUsd: toFiniteNumberOrNull3(
|
|
4231
4428
|
globalRow.totalMarketCapUsd
|
|
4232
4429
|
),
|
|
4233
|
-
totalVolumeUsd:
|
|
4430
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4234
4431
|
globalRow.totalVolumeUsd
|
|
4235
4432
|
),
|
|
4236
|
-
totalVolumeReportedUsd:
|
|
4433
|
+
totalVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4237
4434
|
globalRow.totalVolumeReportedUsd
|
|
4238
4435
|
),
|
|
4239
|
-
altMarketCapUsd:
|
|
4436
|
+
altMarketCapUsd: toFiniteNumberOrNull3(
|
|
4240
4437
|
globalRow.altMarketCapUsd
|
|
4241
4438
|
),
|
|
4242
|
-
altVolumeUsd:
|
|
4243
|
-
altVolumeReportedUsd:
|
|
4439
|
+
altVolumeUsd: toFiniteNumberOrNull3(globalRow.altVolumeUsd),
|
|
4440
|
+
altVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4244
4441
|
globalRow.altVolumeReportedUsd
|
|
4245
4442
|
),
|
|
4246
|
-
btcDominancePct:
|
|
4443
|
+
btcDominancePct: toFiniteNumberOrNull3(
|
|
4247
4444
|
globalRow.btcDominancePct
|
|
4248
4445
|
),
|
|
4249
|
-
ethDominancePct:
|
|
4446
|
+
ethDominancePct: toFiniteNumberOrNull3(
|
|
4250
4447
|
globalRow.ethDominancePct
|
|
4251
4448
|
),
|
|
4252
4449
|
btcDominanceChange24hPct,
|
|
4253
|
-
ethDominanceChange24hPct:
|
|
4450
|
+
ethDominanceChange24hPct: toFiniteNumberOrNull3(
|
|
4254
4451
|
globalRow.ethDominanceChange24hPct
|
|
4255
4452
|
),
|
|
4256
4453
|
altMarketCapChange24hPct,
|
|
4257
4454
|
altVolumeChange24hPct,
|
|
4258
|
-
activeCryptocurrencies:
|
|
4455
|
+
activeCryptocurrencies: toFiniteNumberOrNull3(
|
|
4259
4456
|
globalRow.activeCryptocurrencies
|
|
4260
4457
|
),
|
|
4261
|
-
activeExchanges:
|
|
4458
|
+
activeExchanges: toFiniteNumberOrNull3(
|
|
4262
4459
|
globalRow.activeExchanges
|
|
4263
4460
|
),
|
|
4264
|
-
activeMarketPairs:
|
|
4461
|
+
activeMarketPairs: toFiniteNumberOrNull3(
|
|
4265
4462
|
globalRow.activeMarketPairs
|
|
4266
4463
|
),
|
|
4267
4464
|
altLiquidityRegime
|
|
@@ -4306,22 +4503,22 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4306
4503
|
asOfTs: exchangeLiquidityRow.ts.getTime(),
|
|
4307
4504
|
ageMs: exchangeLiquidityRow.ageMs,
|
|
4308
4505
|
stale: exchangeLiquidityRow.stale,
|
|
4309
|
-
exchangesCount:
|
|
4506
|
+
exchangesCount: toFiniteNumberOrNull3(
|
|
4310
4507
|
exchangeLiquidityRow.exchangesCount
|
|
4311
4508
|
),
|
|
4312
|
-
totalVolumeUsd:
|
|
4509
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4313
4510
|
exchangeLiquidityRow.totalVolumeUsd
|
|
4314
4511
|
),
|
|
4315
|
-
totalVolumeChange24hPct:
|
|
4512
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4316
4513
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4317
4514
|
),
|
|
4318
|
-
binanceVolumeUsd:
|
|
4515
|
+
binanceVolumeUsd: toFiniteNumberOrNull3(
|
|
4319
4516
|
exchangeLiquidityRow.binanceVolumeUsd
|
|
4320
4517
|
),
|
|
4321
|
-
binanceVolumeShare:
|
|
4518
|
+
binanceVolumeShare: toFiniteNumberOrNull3(
|
|
4322
4519
|
exchangeLiquidityRow.binanceVolumeShare
|
|
4323
4520
|
),
|
|
4324
|
-
topExchangeVolumeShare:
|
|
4521
|
+
topExchangeVolumeShare: toFiniteNumberOrNull3(
|
|
4325
4522
|
exchangeLiquidityRow.topExchangeVolumeShare
|
|
4326
4523
|
),
|
|
4327
4524
|
liquidityRegime: exchangeLiquidityRegime
|
|
@@ -4334,11 +4531,11 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4334
4531
|
asOfTs: fearGreedRow.ts.getTime(),
|
|
4335
4532
|
ageMs: fearGreedRow.ageMs,
|
|
4336
4533
|
stale: fearGreedRow.stale,
|
|
4337
|
-
value:
|
|
4338
|
-
valueChange24h:
|
|
4534
|
+
value: toFiniteNumberOrNull3(fearGreedRow.value),
|
|
4535
|
+
valueChange24h: toFiniteNumberOrNull3(
|
|
4339
4536
|
fearGreedRow.valueChange24h
|
|
4340
4537
|
),
|
|
4341
|
-
valueChange7d:
|
|
4538
|
+
valueChange7d: toFiniteNumberOrNull3(
|
|
4342
4539
|
fearGreedRow.valueChange7d
|
|
4343
4540
|
),
|
|
4344
4541
|
classification: fearGreedRow.classification ?? "Unknown",
|
|
@@ -4358,13 +4555,13 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4358
4555
|
cmc100Value,
|
|
4359
4556
|
cmc100Change24hPct,
|
|
4360
4557
|
cmc100TopConstituentSymbol: cmc100Row?.topConstituentSymbol ?? null,
|
|
4361
|
-
cmc100TopConstituentWeightPct:
|
|
4558
|
+
cmc100TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4362
4559
|
cmc100Row?.topConstituentWeightPct
|
|
4363
4560
|
),
|
|
4364
4561
|
cmc20Value,
|
|
4365
4562
|
cmc20Change24hPct,
|
|
4366
4563
|
cmc20TopConstituentSymbol: cmc20Row?.topConstituentSymbol ?? null,
|
|
4367
|
-
cmc20TopConstituentWeightPct:
|
|
4564
|
+
cmc20TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4368
4565
|
cmc20Row?.topConstituentWeightPct
|
|
4369
4566
|
),
|
|
4370
4567
|
cmc20ToCmc100Ratio,
|
|
@@ -4382,7 +4579,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4382
4579
|
throw error;
|
|
4383
4580
|
}
|
|
4384
4581
|
coinMarketCapContextUnavailable = true;
|
|
4385
|
-
|
|
4582
|
+
import_logger5.logger.warn(
|
|
4386
4583
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
4387
4584
|
String(error)
|
|
4388
4585
|
);
|
|
@@ -4396,7 +4593,7 @@ var import_data2 = require("@tradejs/core/data");
|
|
|
4396
4593
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
4397
4594
|
var import_constants2 = require("@tradejs/core/constants");
|
|
4398
4595
|
var import_derivatives = require("@tradejs/infra/timescale/derivatives");
|
|
4399
|
-
var
|
|
4596
|
+
var import_logger6 = require("@tradejs/infra/logger");
|
|
4400
4597
|
var STORED_INTERVALS = ["15m", "1h"];
|
|
4401
4598
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
4402
4599
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
@@ -4451,7 +4648,7 @@ var resolvePrimaryReferenceSymbol2 = () => PRIMARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
|
4451
4648
|
var resolveSecondaryReferenceSymbol = () => SECONDARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
4452
4649
|
var getPrimaryIntervalContext = (context) => context?.intervals["15m"] ?? context?.intervals["1h"] ?? null;
|
|
4453
4650
|
var hasDerivativesSymbolData = (context) => Object.keys(context.intervals).length > 0 && !context.summary.riskFlags.includes("missing_derivatives");
|
|
4454
|
-
var
|
|
4651
|
+
var toFiniteNumberOrNull4 = (value) => {
|
|
4455
4652
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4456
4653
|
if (typeof value === "string" && value.trim()) {
|
|
4457
4654
|
const parsed = Number(value);
|
|
@@ -4465,8 +4662,8 @@ var roundNullable = (value, digits = 4) => {
|
|
|
4465
4662
|
return Math.round(value * multiplier) / multiplier;
|
|
4466
4663
|
};
|
|
4467
4664
|
var deltaNullable = (targetValue, referenceValue) => {
|
|
4468
|
-
const target =
|
|
4469
|
-
const reference =
|
|
4665
|
+
const target = toFiniteNumberOrNull4(targetValue);
|
|
4666
|
+
const reference = toFiniteNumberOrNull4(referenceValue);
|
|
4470
4667
|
return target == null || reference == null ? null : roundNullable(target - reference);
|
|
4471
4668
|
};
|
|
4472
4669
|
var buildTargetDerivedContext = (params) => {
|
|
@@ -4628,7 +4825,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4628
4825
|
throw error;
|
|
4629
4826
|
}
|
|
4630
4827
|
derivativesContextUnavailable = true;
|
|
4631
|
-
|
|
4828
|
+
import_logger6.logger.warn(
|
|
4632
4829
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
4633
4830
|
String(error)
|
|
4634
4831
|
);
|
|
@@ -4640,7 +4837,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4640
4837
|
var import_data3 = require("@tradejs/core/data");
|
|
4641
4838
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
4642
4839
|
var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
|
|
4643
|
-
var
|
|
4840
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
4644
4841
|
|
|
4645
4842
|
// src/hyperliquidWhaleUniverse.ts
|
|
4646
4843
|
var import_node_crypto3 = require("crypto");
|
|
@@ -5160,7 +5357,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
5160
5357
|
throw error;
|
|
5161
5358
|
}
|
|
5162
5359
|
hyperliquidWhaleContextUnavailable = true;
|
|
5163
|
-
|
|
5360
|
+
import_logger7.logger.warn(
|
|
5164
5361
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
5165
5362
|
String(error)
|
|
5166
5363
|
);
|
|
@@ -5243,7 +5440,7 @@ var runMarketContextStage = async ({
|
|
|
5243
5440
|
elapsedMs: Date.now() - startedAt
|
|
5244
5441
|
};
|
|
5245
5442
|
if (status === "timed_out") {
|
|
5246
|
-
|
|
5443
|
+
import_logger8.logger.warn(
|
|
5247
5444
|
"Market context stage timed out: %s after %sms",
|
|
5248
5445
|
stage,
|
|
5249
5446
|
result.elapsedMs
|
|
@@ -5433,79 +5630,10 @@ var enrichSignalWithAi = async ({
|
|
|
5433
5630
|
signal.aiAnalysis = analysis;
|
|
5434
5631
|
return resolveAiQuality(analysis, direction);
|
|
5435
5632
|
} catch (err) {
|
|
5436
|
-
|
|
5633
|
+
import_logger9.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
|
|
5437
5634
|
}
|
|
5438
5635
|
return void 0;
|
|
5439
5636
|
};
|
|
5440
|
-
var toFiniteNumberOrNull4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5441
|
-
var getOrderArrivalSnapshot = async ({
|
|
5442
|
-
connector,
|
|
5443
|
-
symbol
|
|
5444
|
-
}) => {
|
|
5445
|
-
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
5446
|
-
return {
|
|
5447
|
-
arrivalSnapshotTime: Date.now(),
|
|
5448
|
-
arrivalSource: "unavailable",
|
|
5449
|
-
bid: null,
|
|
5450
|
-
ask: null,
|
|
5451
|
-
arrivalMid: null,
|
|
5452
|
-
spreadBps: null
|
|
5453
|
-
};
|
|
5454
|
-
}
|
|
5455
|
-
try {
|
|
5456
|
-
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
5457
|
-
const arrivalSnapshotTime = toFiniteNumberOrNull4(ticker?.timestamp);
|
|
5458
|
-
const bid = toFiniteNumberOrNull4(ticker?.bidPrice);
|
|
5459
|
-
const ask = toFiniteNumberOrNull4(ticker?.askPrice);
|
|
5460
|
-
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
5461
|
-
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
5462
|
-
return {
|
|
5463
|
-
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
5464
|
-
arrivalSource: "top_of_book",
|
|
5465
|
-
bid,
|
|
5466
|
-
ask,
|
|
5467
|
-
arrivalMid,
|
|
5468
|
-
spreadBps
|
|
5469
|
-
};
|
|
5470
|
-
} catch (error) {
|
|
5471
|
-
import_logger8.logger.warn(
|
|
5472
|
-
"runtime order arrival snapshot failed: %s %s",
|
|
5473
|
-
symbol,
|
|
5474
|
-
error?.message || String(error)
|
|
5475
|
-
);
|
|
5476
|
-
return {
|
|
5477
|
-
arrivalSnapshotTime: Date.now(),
|
|
5478
|
-
arrivalSource: "top_of_book_error",
|
|
5479
|
-
bid: null,
|
|
5480
|
-
ask: null,
|
|
5481
|
-
arrivalMid: null,
|
|
5482
|
-
spreadBps: null
|
|
5483
|
-
};
|
|
5484
|
-
}
|
|
5485
|
-
};
|
|
5486
|
-
var validateEntryProtectionAtArrival = ({
|
|
5487
|
-
direction,
|
|
5488
|
-
signalPrice,
|
|
5489
|
-
bid,
|
|
5490
|
-
ask,
|
|
5491
|
-
arrivalMid,
|
|
5492
|
-
takeProfits,
|
|
5493
|
-
stopLossPrice
|
|
5494
|
-
}) => {
|
|
5495
|
-
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
5496
|
-
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
5497
|
-
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
5498
|
-
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
5499
|
-
}
|
|
5500
|
-
for (const takeProfit of takeProfits) {
|
|
5501
|
-
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
5502
|
-
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
5503
|
-
}
|
|
5504
|
-
}
|
|
5505
|
-
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
5506
|
-
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
5507
|
-
}
|
|
5508
|
-
};
|
|
5509
5637
|
var resolveRuntimeTelemetryQuality = ({
|
|
5510
5638
|
signalClosePrice,
|
|
5511
5639
|
arrivalMid,
|
|
@@ -5582,7 +5710,8 @@ var executeEntryOrder = async ({
|
|
|
5582
5710
|
signal,
|
|
5583
5711
|
beforePlaceOrder,
|
|
5584
5712
|
recordRuntimeTrade = true,
|
|
5585
|
-
leverage
|
|
5713
|
+
leverage,
|
|
5714
|
+
executionLimits
|
|
5586
5715
|
}) => {
|
|
5587
5716
|
await beforePlaceOrder?.();
|
|
5588
5717
|
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
@@ -5593,23 +5722,57 @@ var executeEntryOrder = async ({
|
|
|
5593
5722
|
signal.orderQty = qty;
|
|
5594
5723
|
signal.orderValue = qty * currentPrice;
|
|
5595
5724
|
signal.orderFailureReason = void 0;
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5725
|
+
let arrivalSnapshot = {
|
|
5726
|
+
arrivalSnapshotTime: Date.now(),
|
|
5727
|
+
arrivalSource: "unavailable",
|
|
5728
|
+
bid: null,
|
|
5729
|
+
ask: null,
|
|
5730
|
+
arrivalMid: null,
|
|
5731
|
+
spreadBps: null
|
|
5732
|
+
};
|
|
5733
|
+
let orderSubmitTime = Date.now();
|
|
5734
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
5735
|
+
connector,
|
|
5736
|
+
symbol,
|
|
5737
|
+
direction,
|
|
5738
|
+
takeProfits,
|
|
5739
|
+
stopLossPrice,
|
|
5740
|
+
limits: executionLimits,
|
|
5741
|
+
onValidated: (snapshot2, economics2) => {
|
|
5742
|
+
arrivalSnapshot = snapshot2;
|
|
5743
|
+
orderSubmitTime = Date.now();
|
|
5744
|
+
if (executionLimits?.maxLossValue != null) {
|
|
5745
|
+
signal.riskDecision = {
|
|
5746
|
+
stage: "order_plan",
|
|
5747
|
+
status: economics2.riskExceeded ? "warning" : "approved",
|
|
5748
|
+
reason: economics2.riskExceeded ? "ENTRY_RISK_EXCEEDS_MAX_LOSS_AT_SUBMISSION" : "PLANNED_LOSS_WITHIN_MAX_LOSS_VALUE",
|
|
5749
|
+
plannedLossValue: economics2.plannedLossValue,
|
|
5750
|
+
maxLossValue: executionLimits.maxLossValue,
|
|
5751
|
+
limitUtilization: economics2.plannedLossValue / executionLimits.maxLossValue,
|
|
5752
|
+
enforced: false
|
|
5753
|
+
};
|
|
5754
|
+
}
|
|
5755
|
+
}
|
|
5756
|
+
});
|
|
5757
|
+
if (!beforeSubmit) {
|
|
5758
|
+
arrivalSnapshot = await getOrderArrivalSnapshot({ connector, symbol });
|
|
5759
|
+
try {
|
|
5760
|
+
validateEntryProtectionAtArrival({
|
|
5761
|
+
direction,
|
|
5762
|
+
signalPrice: currentPrice,
|
|
5763
|
+
bid: arrivalSnapshot.bid,
|
|
5764
|
+
ask: arrivalSnapshot.ask,
|
|
5765
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
5766
|
+
takeProfits,
|
|
5767
|
+
stopLossPrice
|
|
5768
|
+
});
|
|
5769
|
+
} catch (error) {
|
|
5770
|
+
signal.orderStatus = "failed";
|
|
5771
|
+
signal.orderFailureReason = error.message;
|
|
5772
|
+
throw error;
|
|
5773
|
+
}
|
|
5774
|
+
orderSubmitTime = Date.now();
|
|
5611
5775
|
}
|
|
5612
|
-
const orderSubmitTime = Date.now();
|
|
5613
5776
|
const orderPlaced = await connector.placeOrder({
|
|
5614
5777
|
symbol,
|
|
5615
5778
|
qty,
|
|
@@ -5620,7 +5783,8 @@ var executeEntryOrder = async ({
|
|
|
5620
5783
|
direction,
|
|
5621
5784
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
5622
5785
|
orderId,
|
|
5623
|
-
signal
|
|
5786
|
+
signal,
|
|
5787
|
+
...beforeSubmit ? { beforeSubmit } : {}
|
|
5624
5788
|
});
|
|
5625
5789
|
const orderAckTime = Date.now();
|
|
5626
5790
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
@@ -6449,7 +6613,7 @@ var canUseSharedReplayState = ({
|
|
|
6449
6613
|
}) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
|
|
6450
6614
|
|
|
6451
6615
|
// src/strategy/runtimeExecution.ts
|
|
6452
|
-
var
|
|
6616
|
+
var import_logger10 = require("@tradejs/infra/logger");
|
|
6453
6617
|
var import_types = require("@tradejs/types");
|
|
6454
6618
|
var buildExitOrderSignal = ({
|
|
6455
6619
|
strategyName,
|
|
@@ -6501,7 +6665,7 @@ var handleExitDecision = async ({
|
|
|
6501
6665
|
deploymentId: connector.deploymentId
|
|
6502
6666
|
});
|
|
6503
6667
|
if (!activeTrade) {
|
|
6504
|
-
|
|
6668
|
+
import_logger10.logger.warn(
|
|
6505
6669
|
"[%s] blocked closePosition for untracked runtime position: %s",
|
|
6506
6670
|
strategyName ?? "unknown",
|
|
6507
6671
|
symbol
|
|
@@ -6509,7 +6673,7 @@ var handleExitDecision = async ({
|
|
|
6509
6673
|
return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
|
|
6510
6674
|
}
|
|
6511
6675
|
if (!strategyName || activeTrade.strategy !== strategyName) {
|
|
6512
|
-
|
|
6676
|
+
import_logger10.logger.warn(
|
|
6513
6677
|
"[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
|
|
6514
6678
|
strategyName ?? "unknown",
|
|
6515
6679
|
symbol,
|
|
@@ -6562,7 +6726,7 @@ var handleExitDecision = async ({
|
|
|
6562
6726
|
exitType: closedTrade?.exitType ?? "exit"
|
|
6563
6727
|
});
|
|
6564
6728
|
} catch (notificationError) {
|
|
6565
|
-
|
|
6729
|
+
import_logger10.logger.error(
|
|
6566
6730
|
"runtime close notification error: %s %s",
|
|
6567
6731
|
symbol,
|
|
6568
6732
|
notificationError
|
|
@@ -6576,7 +6740,7 @@ var handleExitDecision = async ({
|
|
|
6576
6740
|
decision,
|
|
6577
6741
|
market
|
|
6578
6742
|
});
|
|
6579
|
-
|
|
6743
|
+
import_logger10.logger.error("close order error: %s %s", symbol, err);
|
|
6580
6744
|
return "ORDER_ERROR";
|
|
6581
6745
|
}
|
|
6582
6746
|
return decision.code;
|
|
@@ -6603,7 +6767,7 @@ var handleProtectDecision = async ({
|
|
|
6603
6767
|
decision,
|
|
6604
6768
|
market
|
|
6605
6769
|
});
|
|
6606
|
-
|
|
6770
|
+
import_logger10.logger.error("protect position error: %s %s", symbol, err);
|
|
6607
6771
|
return "ORDER_ERROR";
|
|
6608
6772
|
}
|
|
6609
6773
|
return decision.code;
|
|
@@ -6669,7 +6833,11 @@ var executeEntryDecision = async ({
|
|
|
6669
6833
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
6670
6834
|
signal,
|
|
6671
6835
|
beforePlaceOrder,
|
|
6672
|
-
recordRuntimeTrade: recordRuntimeJournal
|
|
6836
|
+
recordRuntimeTrade: recordRuntimeJournal,
|
|
6837
|
+
executionLimits: resolveEntryExecutionLimits(
|
|
6838
|
+
hookCtx.strategyConfig,
|
|
6839
|
+
decision.entryContext.direction
|
|
6840
|
+
)
|
|
6673
6841
|
});
|
|
6674
6842
|
await invokeStageHooks(
|
|
6675
6843
|
"afterPlaceOrder",
|
|
@@ -6691,19 +6859,32 @@ var executeEntryDecision = async ({
|
|
|
6691
6859
|
return signal;
|
|
6692
6860
|
}
|
|
6693
6861
|
await beforePlaceOrder();
|
|
6694
|
-
const
|
|
6862
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
6695
6863
|
connector,
|
|
6696
|
-
symbol
|
|
6697
|
-
});
|
|
6698
|
-
validateEntryProtectionAtArrival({
|
|
6864
|
+
symbol,
|
|
6699
6865
|
direction: decision.entryContext.direction,
|
|
6700
|
-
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6701
|
-
bid: arrivalSnapshot.bid,
|
|
6702
|
-
ask: arrivalSnapshot.ask,
|
|
6703
|
-
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6704
6866
|
takeProfits: decision.orderPlan.takeProfits,
|
|
6705
|
-
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6867
|
+
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
6868
|
+
limits: resolveEntryExecutionLimits(
|
|
6869
|
+
hookCtx.strategyConfig,
|
|
6870
|
+
decision.entryContext.direction
|
|
6871
|
+
)
|
|
6706
6872
|
});
|
|
6873
|
+
if (!beforeSubmit) {
|
|
6874
|
+
const arrivalSnapshot = await getOrderArrivalSnapshot({
|
|
6875
|
+
connector,
|
|
6876
|
+
symbol
|
|
6877
|
+
});
|
|
6878
|
+
validateEntryProtectionAtArrival({
|
|
6879
|
+
direction: decision.entryContext.direction,
|
|
6880
|
+
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6881
|
+
bid: arrivalSnapshot.bid,
|
|
6882
|
+
ask: arrivalSnapshot.ask,
|
|
6883
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6884
|
+
takeProfits: decision.orderPlan.takeProfits,
|
|
6885
|
+
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6886
|
+
});
|
|
6887
|
+
}
|
|
6707
6888
|
const orderPlaced = await connector.placeOrder({
|
|
6708
6889
|
symbol,
|
|
6709
6890
|
qty: decision.orderPlan.qty,
|
|
@@ -6711,6 +6892,7 @@ var executeEntryDecision = async ({
|
|
|
6711
6892
|
timestamp: decision.entryContext.timestamp,
|
|
6712
6893
|
direction: decision.entryContext.direction,
|
|
6713
6894
|
positionIntent: decision.orderPlan.positionIntent,
|
|
6895
|
+
...beforeSubmit ? { beforeSubmit } : {},
|
|
6714
6896
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
6715
6897
|
});
|
|
6716
6898
|
if (!orderPlaced) {
|
|
@@ -6752,6 +6934,23 @@ var executeEntryDecision = async ({
|
|
|
6752
6934
|
{ decision, entry, market }
|
|
6753
6935
|
);
|
|
6754
6936
|
} catch (err) {
|
|
6937
|
+
if (err instanceof EntrySubmissionValidationError) {
|
|
6938
|
+
if (signal) {
|
|
6939
|
+
signal.orderStatus = "skipped";
|
|
6940
|
+
signal.orderSkipReason = err.message;
|
|
6941
|
+
signal.allocatorDecision = {
|
|
6942
|
+
stage: "runtime_admission",
|
|
6943
|
+
status: "rejected",
|
|
6944
|
+
reason: err.message
|
|
6945
|
+
};
|
|
6946
|
+
}
|
|
6947
|
+
import_logger10.logger.warn(
|
|
6948
|
+
"entry rejected before submission: %s %s",
|
|
6949
|
+
symbol,
|
|
6950
|
+
err.message
|
|
6951
|
+
);
|
|
6952
|
+
return signal ?? err.message;
|
|
6953
|
+
}
|
|
6755
6954
|
if (signal) {
|
|
6756
6955
|
signal.orderStatus = "failed";
|
|
6757
6956
|
if (typeof signal.orderFailureReason !== "string" || !signal.orderFailureReason.trim()) {
|
|
@@ -6766,9 +6965,9 @@ var executeEntryDecision = async ({
|
|
|
6766
6965
|
market
|
|
6767
6966
|
});
|
|
6768
6967
|
if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
|
|
6769
|
-
|
|
6968
|
+
import_logger10.logger.warn("order warning: %s %s", symbol, err);
|
|
6770
6969
|
} else {
|
|
6771
|
-
|
|
6970
|
+
import_logger10.logger.error("order error: %s %s", symbol, err);
|
|
6772
6971
|
}
|
|
6773
6972
|
return signal ?? "ORDER_ERROR";
|
|
6774
6973
|
}
|
|
@@ -6876,6 +7075,9 @@ var createStrategyRuntime = ({
|
|
|
6876
7075
|
});
|
|
6877
7076
|
const strategyPolicyProfile = getPolicyProfile();
|
|
6878
7077
|
const indicatorPeriods = (0, import_strategies6.buildDefaultIndicatorPeriods)(config);
|
|
7078
|
+
const strategyConfig = { ...config };
|
|
7079
|
+
delete strategyConfig.RECORD_RUNTIME_TRADES;
|
|
7080
|
+
delete strategyConfig.SIMULATE_ORDERS;
|
|
6879
7081
|
const hookBase = {
|
|
6880
7082
|
connector,
|
|
6881
7083
|
strategyName,
|
|
@@ -6886,7 +7088,7 @@ var createStrategyRuntime = ({
|
|
|
6886
7088
|
accountId,
|
|
6887
7089
|
deploymentId,
|
|
6888
7090
|
policyProfileId: strategyPolicyProfile?.id ?? requestedPolicyProfileId,
|
|
6889
|
-
strategyConfig
|
|
7091
|
+
strategyConfig,
|
|
6890
7092
|
env,
|
|
6891
7093
|
isConfigFromBacktest
|
|
6892
7094
|
};
|
|
@@ -6933,7 +7135,7 @@ var createStrategyRuntime = ({
|
|
|
6933
7135
|
try {
|
|
6934
7136
|
await projectHook(errorParams);
|
|
6935
7137
|
} catch (hookError) {
|
|
6936
|
-
|
|
7138
|
+
import_logger11.logger.error(
|
|
6937
7139
|
"project hook onRuntimeError failed: %s %s",
|
|
6938
7140
|
strategyName,
|
|
6939
7141
|
hookError
|
|
@@ -6947,21 +7149,21 @@ var createStrategyRuntime = ({
|
|
|
6947
7149
|
try {
|
|
6948
7150
|
await onRuntimeError(errorParams);
|
|
6949
7151
|
} catch (hookError) {
|
|
6950
|
-
|
|
7152
|
+
import_logger11.logger.error(
|
|
6951
7153
|
"runtime hook onRuntimeError failed: %s %s",
|
|
6952
7154
|
strategyName,
|
|
6953
7155
|
hookError
|
|
6954
7156
|
);
|
|
6955
7157
|
}
|
|
6956
7158
|
};
|
|
6957
|
-
const invokeHook = async (stage, hook, params, errorContext = {}) => {
|
|
7159
|
+
const invokeHook = async (stage, hook, params, errorContext = {}, failureResult) => {
|
|
6958
7160
|
if (!hook) {
|
|
6959
7161
|
return void 0;
|
|
6960
7162
|
}
|
|
6961
7163
|
try {
|
|
6962
7164
|
return await hook(params);
|
|
6963
7165
|
} catch (error) {
|
|
6964
|
-
|
|
7166
|
+
import_logger11.logger.error(
|
|
6965
7167
|
'strategy hook "%s" failed for %s: %s',
|
|
6966
7168
|
stage,
|
|
6967
7169
|
strategyName,
|
|
@@ -6974,17 +7176,18 @@ var createStrategyRuntime = ({
|
|
|
6974
7176
|
entry: errorContext.entry,
|
|
6975
7177
|
market: errorContext.market
|
|
6976
7178
|
});
|
|
6977
|
-
return
|
|
7179
|
+
return failureResult;
|
|
6978
7180
|
}
|
|
6979
7181
|
};
|
|
6980
|
-
const invokeProjectHooks = async (stage, params, errorContext = {}) => {
|
|
7182
|
+
const invokeProjectHooks = async (stage, params, errorContext = {}, failureResult) => {
|
|
6981
7183
|
const results = [];
|
|
6982
7184
|
for (const hook of getProjectHookList(stage)) {
|
|
6983
7185
|
const result = await invokeHook(
|
|
6984
7186
|
stage,
|
|
6985
7187
|
hook,
|
|
6986
7188
|
params,
|
|
6987
|
-
errorContext
|
|
7189
|
+
errorContext,
|
|
7190
|
+
failureResult
|
|
6988
7191
|
);
|
|
6989
7192
|
if (result !== void 0) {
|
|
6990
7193
|
results.push(result);
|
|
@@ -6999,10 +7202,12 @@ var createStrategyRuntime = ({
|
|
|
6999
7202
|
return invokeHook(stage, hook, params, errorContext);
|
|
7000
7203
|
};
|
|
7001
7204
|
const invokeGateHooks = async (stage, hook, params, errorContext = {}) => {
|
|
7205
|
+
const failureResult = stage === "beforeEntryGate" ? { allow: false, reason: "ERROR" } : void 0;
|
|
7002
7206
|
const projectResults = await invokeProjectHooks(
|
|
7003
7207
|
stage,
|
|
7004
7208
|
params,
|
|
7005
|
-
errorContext
|
|
7209
|
+
errorContext,
|
|
7210
|
+
failureResult
|
|
7006
7211
|
);
|
|
7007
7212
|
const projectBlock = projectResults.find(
|
|
7008
7213
|
(result) => result?.allow === false
|
|
@@ -7014,7 +7219,8 @@ var createStrategyRuntime = ({
|
|
|
7014
7219
|
stage,
|
|
7015
7220
|
hook,
|
|
7016
7221
|
params,
|
|
7017
|
-
errorContext
|
|
7222
|
+
errorContext,
|
|
7223
|
+
failureResult
|
|
7018
7224
|
);
|
|
7019
7225
|
};
|
|
7020
7226
|
const applyProjectAfterCoreDecisionHooks = async ({
|
|
@@ -7160,11 +7366,8 @@ var createStrategyRuntime = ({
|
|
|
7160
7366
|
return enrichedBaseContext;
|
|
7161
7367
|
}
|
|
7162
7368
|
});
|
|
7163
|
-
const coreConfig = { ...config };
|
|
7164
|
-
delete coreConfig.RECORD_RUNTIME_TRADES;
|
|
7165
|
-
delete coreConfig.SIMULATE_ORDERS;
|
|
7166
7369
|
const core = await createCore({
|
|
7167
|
-
config:
|
|
7370
|
+
config: strategyConfig,
|
|
7168
7371
|
data,
|
|
7169
7372
|
strategyApi,
|
|
7170
7373
|
indicatorsState
|