@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
package/dist/diagnostics.js
CHANGED
|
@@ -1073,13 +1073,210 @@ var assessSignalWithJev = async ({
|
|
|
1073
1073
|
// src/strategyRuntime.ts
|
|
1074
1074
|
var import_constants5 = require("@tradejs/core/constants");
|
|
1075
1075
|
var import_strategies6 = require("@tradejs/core/strategies");
|
|
1076
|
-
var
|
|
1076
|
+
var import_logger11 = require("@tradejs/infra/logger");
|
|
1077
1077
|
|
|
1078
1078
|
// src/strategyHelpers/runtime.ts
|
|
1079
|
-
var
|
|
1079
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
1080
1080
|
var import_constants3 = require("@tradejs/core/constants");
|
|
1081
1081
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
1082
1082
|
|
|
1083
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1084
|
+
var import_logger = require("@tradejs/infra/logger");
|
|
1085
|
+
|
|
1086
|
+
// src/strategy/entryExecutionValidation.ts
|
|
1087
|
+
var EntrySubmissionValidationError = class extends Error {
|
|
1088
|
+
constructor() {
|
|
1089
|
+
super(...arguments);
|
|
1090
|
+
this.name = "EntrySubmissionValidationError";
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
var resolveEntryExecutionLimits = (config, direction) => {
|
|
1094
|
+
const side = config[direction];
|
|
1095
|
+
const minimum = side && typeof side === "object" && "minRiskRatio" in side ? side.minRiskRatio : void 0;
|
|
1096
|
+
const maximum = config.MAX_LOSS_VALUE;
|
|
1097
|
+
if (minimum == null && maximum == null) return void 0;
|
|
1098
|
+
const minimumNetRiskRatio = minimum == null ? void 0 : Number(minimum);
|
|
1099
|
+
const maxLossValue = maximum == null ? void 0 : Number(maximum);
|
|
1100
|
+
const feeRate = Number(config.RISK_FEE_RATE ?? 0);
|
|
1101
|
+
const slippage = Number(config.RISK_SLIPPAGE_BPS ?? 0);
|
|
1102
|
+
const impact = Number(config.RISK_MARKET_IMPACT_BPS ?? 0);
|
|
1103
|
+
const slippageBps = slippage + impact;
|
|
1104
|
+
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)
|
|
1105
|
+
throw new Error("INVALID_ENTRY_EXECUTION_LIMITS");
|
|
1106
|
+
return { minimumNetRiskRatio, maxLossValue, feeRate, slippageBps };
|
|
1107
|
+
};
|
|
1108
|
+
var validateEntryExecution = ({
|
|
1109
|
+
direction,
|
|
1110
|
+
price,
|
|
1111
|
+
qty,
|
|
1112
|
+
stopLossPrice,
|
|
1113
|
+
takeProfitPrice,
|
|
1114
|
+
limits
|
|
1115
|
+
}) => {
|
|
1116
|
+
if (!Number.isFinite(price) || price <= 0 || !Number.isFinite(qty) || qty <= 0 || stopLossPrice == null || !Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || !Number.isFinite(takeProfitPrice) || takeProfitPrice <= 0)
|
|
1117
|
+
throw new EntrySubmissionValidationError(
|
|
1118
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1119
|
+
);
|
|
1120
|
+
const side = direction === "LONG" ? 1 : -1;
|
|
1121
|
+
if (side * (price - stopLossPrice) <= 0 || side * (takeProfitPrice - price) <= 0)
|
|
1122
|
+
throw new EntrySubmissionValidationError(
|
|
1123
|
+
"INVALID_ENTRY_PROTECTION_AT_SUBMISSION"
|
|
1124
|
+
);
|
|
1125
|
+
const slippage = limits.slippageBps / 1e4;
|
|
1126
|
+
const cost = (value, sign) => value * slippage + value * (1 + sign * slippage) * limits.feeRate;
|
|
1127
|
+
const entryCost = cost(price, side);
|
|
1128
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + entryCost + cost(stopLossPrice, -side);
|
|
1129
|
+
const rewardPerUnit = Math.max(
|
|
1130
|
+
0,
|
|
1131
|
+
Math.abs(takeProfitPrice - price) - entryCost - cost(takeProfitPrice, -side)
|
|
1132
|
+
);
|
|
1133
|
+
const netRiskRatio = rewardPerUnit / lossPerUnit;
|
|
1134
|
+
const plannedLossValue = qty * lossPerUnit;
|
|
1135
|
+
if (!Number.isFinite(netRiskRatio) || !Number.isFinite(plannedLossValue))
|
|
1136
|
+
throw new EntrySubmissionValidationError(
|
|
1137
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1138
|
+
);
|
|
1139
|
+
if (limits.minimumNetRiskRatio != null && netRiskRatio <= limits.minimumNetRiskRatio)
|
|
1140
|
+
throw new EntrySubmissionValidationError(
|
|
1141
|
+
"ENTRY_RR_BELOW_MIN_AT_SUBMISSION"
|
|
1142
|
+
);
|
|
1143
|
+
const riskExceeded = limits.maxLossValue != null && plannedLossValue > limits.maxLossValue * (1 + 1e-9);
|
|
1144
|
+
return { netRiskRatio, plannedLossValue, riskExceeded };
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1148
|
+
var MAX_ENTRY_QUOTE_AGE_MS = 5e3;
|
|
1149
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1150
|
+
var getOrderArrivalSnapshot = async ({
|
|
1151
|
+
connector,
|
|
1152
|
+
symbol,
|
|
1153
|
+
requireTimestamp = false
|
|
1154
|
+
}) => {
|
|
1155
|
+
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
1156
|
+
return {
|
|
1157
|
+
arrivalSnapshotTime: Date.now(),
|
|
1158
|
+
arrivalSource: "unavailable",
|
|
1159
|
+
bid: null,
|
|
1160
|
+
ask: null,
|
|
1161
|
+
arrivalMid: null,
|
|
1162
|
+
spreadBps: null
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
try {
|
|
1166
|
+
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
1167
|
+
const arrivalSnapshotTime = toFiniteNumberOrNull(ticker?.timestamp);
|
|
1168
|
+
const timestampUnavailable = requireTimestamp && arrivalSnapshotTime == null;
|
|
1169
|
+
const bid = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.bidPrice);
|
|
1170
|
+
const ask = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.askPrice);
|
|
1171
|
+
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
1172
|
+
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
1173
|
+
return {
|
|
1174
|
+
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
1175
|
+
arrivalSource: "top_of_book",
|
|
1176
|
+
bid,
|
|
1177
|
+
ask,
|
|
1178
|
+
arrivalMid,
|
|
1179
|
+
spreadBps
|
|
1180
|
+
};
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
import_logger.logger.warn(
|
|
1183
|
+
"runtime order arrival snapshot failed: %s %s",
|
|
1184
|
+
symbol,
|
|
1185
|
+
error?.message || String(error)
|
|
1186
|
+
);
|
|
1187
|
+
return {
|
|
1188
|
+
arrivalSnapshotTime: Date.now(),
|
|
1189
|
+
arrivalSource: "top_of_book_error",
|
|
1190
|
+
bid: null,
|
|
1191
|
+
ask: null,
|
|
1192
|
+
arrivalMid: null,
|
|
1193
|
+
spreadBps: null
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
var validateEntryProtectionAtArrival = ({
|
|
1198
|
+
direction,
|
|
1199
|
+
signalPrice,
|
|
1200
|
+
bid,
|
|
1201
|
+
ask,
|
|
1202
|
+
arrivalMid,
|
|
1203
|
+
takeProfits,
|
|
1204
|
+
stopLossPrice
|
|
1205
|
+
}) => {
|
|
1206
|
+
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
1207
|
+
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
1208
|
+
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
1209
|
+
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
1210
|
+
}
|
|
1211
|
+
for (const takeProfit of takeProfits) {
|
|
1212
|
+
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
1213
|
+
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
1217
|
+
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
var createEntrySubmissionValidation = ({
|
|
1221
|
+
connector,
|
|
1222
|
+
symbol,
|
|
1223
|
+
direction,
|
|
1224
|
+
takeProfits,
|
|
1225
|
+
stopLossPrice,
|
|
1226
|
+
limits,
|
|
1227
|
+
onValidated
|
|
1228
|
+
}) => {
|
|
1229
|
+
if (!limits) return void 0;
|
|
1230
|
+
if (!connector.capabilities?.orderSubmissionValidation)
|
|
1231
|
+
throw new EntrySubmissionValidationError(
|
|
1232
|
+
"ENTRY_SUBMISSION_VALIDATION_UNSUPPORTED"
|
|
1233
|
+
);
|
|
1234
|
+
return async ({ qty, executionPrice }) => {
|
|
1235
|
+
const simulated = Reflect.get(connector, "__tradejsTestConnector") === true;
|
|
1236
|
+
const snapshot2 = simulated && executionPrice != null ? {
|
|
1237
|
+
arrivalSnapshotTime: Date.now(),
|
|
1238
|
+
arrivalSource: "simulation",
|
|
1239
|
+
bid: executionPrice,
|
|
1240
|
+
ask: executionPrice,
|
|
1241
|
+
arrivalMid: executionPrice,
|
|
1242
|
+
spreadBps: 0
|
|
1243
|
+
} : await getOrderArrivalSnapshot({
|
|
1244
|
+
connector,
|
|
1245
|
+
symbol,
|
|
1246
|
+
requireTimestamp: true
|
|
1247
|
+
});
|
|
1248
|
+
const age = Date.now() - snapshot2.arrivalSnapshotTime;
|
|
1249
|
+
if (snapshot2.bid == null || snapshot2.ask == null || !Number.isFinite(snapshot2.bid) || !Number.isFinite(snapshot2.ask) || snapshot2.bid <= 0 || snapshot2.ask < snapshot2.bid)
|
|
1250
|
+
throw new EntrySubmissionValidationError(
|
|
1251
|
+
"ENTRY_QUOTE_UNAVAILABLE_AT_SUBMISSION"
|
|
1252
|
+
);
|
|
1253
|
+
if (!Number.isFinite(age) || age < -MAX_ENTRY_QUOTE_AGE_MS || age > MAX_ENTRY_QUOTE_AGE_MS)
|
|
1254
|
+
throw new EntrySubmissionValidationError(
|
|
1255
|
+
"ENTRY_QUOTE_STALE_AT_SUBMISSION"
|
|
1256
|
+
);
|
|
1257
|
+
const price = direction === "LONG" ? snapshot2.ask : snapshot2.bid;
|
|
1258
|
+
validateEntryProtectionAtArrival({
|
|
1259
|
+
direction,
|
|
1260
|
+
signalPrice: price,
|
|
1261
|
+
bid: snapshot2.bid,
|
|
1262
|
+
ask: snapshot2.ask,
|
|
1263
|
+
arrivalMid: snapshot2.arrivalMid,
|
|
1264
|
+
takeProfits,
|
|
1265
|
+
stopLossPrice
|
|
1266
|
+
});
|
|
1267
|
+
const prices = takeProfits.map((tp) => tp.price);
|
|
1268
|
+
const economics2 = validateEntryExecution({
|
|
1269
|
+
direction,
|
|
1270
|
+
price,
|
|
1271
|
+
qty,
|
|
1272
|
+
stopLossPrice,
|
|
1273
|
+
takeProfitPrice: direction === "LONG" ? Math.max(...prices) : Math.min(...prices),
|
|
1274
|
+
limits
|
|
1275
|
+
});
|
|
1276
|
+
onValidated?.(snapshot2, economics2);
|
|
1277
|
+
};
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1083
1280
|
// src/ai.ts
|
|
1084
1281
|
var import_aiLanguages2 = require("@tradejs/core/aiLanguages");
|
|
1085
1282
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -1664,7 +1861,7 @@ var import_fs = __toESM(require("fs"));
|
|
|
1664
1861
|
var import_path = __toESM(require("path"));
|
|
1665
1862
|
var import_url = require("url");
|
|
1666
1863
|
var import_config = require("@tradejs/core/config");
|
|
1667
|
-
var
|
|
1864
|
+
var import_logger2 = require("@tradejs/infra/logger");
|
|
1668
1865
|
var CONFIG_FILE_NAMES = [
|
|
1669
1866
|
"tradejs.config.ts",
|
|
1670
1867
|
"tradejs.config.mts",
|
|
@@ -1931,11 +2128,11 @@ var loadTradejsConfig = async (cwd = getTradejsProjectCwd()) => {
|
|
|
1931
2128
|
cachedByCwd.set(cwd, config);
|
|
1932
2129
|
if (!announcedConfigFile.has(configFilePath)) {
|
|
1933
2130
|
announcedConfigFile.add(configFilePath);
|
|
1934
|
-
|
|
2131
|
+
import_logger2.logger.log("debug", "Loaded TradeJS config: %s", configFilePath);
|
|
1935
2132
|
}
|
|
1936
2133
|
return config;
|
|
1937
2134
|
} catch (error) {
|
|
1938
|
-
|
|
2135
|
+
import_logger2.logger.log(
|
|
1939
2136
|
"warn",
|
|
1940
2137
|
"Failed to load TradeJS config from %s: %s",
|
|
1941
2138
|
configFilePath,
|
|
@@ -2901,7 +3098,7 @@ var import_node_crypto = require("crypto");
|
|
|
2901
3098
|
var import_constants = require("@tradejs/core/constants");
|
|
2902
3099
|
var import_time = require("@tradejs/core/time");
|
|
2903
3100
|
var import_trade = require("@tradejs/core/trade");
|
|
2904
|
-
var
|
|
3101
|
+
var import_logger3 = require("@tradejs/infra/logger");
|
|
2905
3102
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
2906
3103
|
var now = () => Date.now();
|
|
2907
3104
|
var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
|
|
@@ -2960,7 +3157,7 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
2960
3157
|
)
|
|
2961
3158
|
]);
|
|
2962
3159
|
} catch (error) {
|
|
2963
|
-
|
|
3160
|
+
import_logger3.logger.error(
|
|
2964
3161
|
"runtime trade open journal failed: %s %s",
|
|
2965
3162
|
record2.symbol,
|
|
2966
3163
|
error?.message || String(error)
|
|
@@ -3028,7 +3225,7 @@ var recordRuntimeTradeIncrease = async (params) => {
|
|
|
3028
3225
|
)
|
|
3029
3226
|
]);
|
|
3030
3227
|
} catch (error) {
|
|
3031
|
-
|
|
3228
|
+
import_logger3.logger.error(
|
|
3032
3229
|
"runtime trade increase journal failed: %s %s",
|
|
3033
3230
|
symbol,
|
|
3034
3231
|
error?.message || String(error)
|
|
@@ -3135,7 +3332,7 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3135
3332
|
)
|
|
3136
3333
|
]);
|
|
3137
3334
|
} catch (error) {
|
|
3138
|
-
|
|
3335
|
+
import_logger3.logger.error(
|
|
3139
3336
|
"runtime trade close journal failed: %s %s",
|
|
3140
3337
|
symbol,
|
|
3141
3338
|
error?.message || String(error)
|
|
@@ -3145,11 +3342,11 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3145
3342
|
};
|
|
3146
3343
|
|
|
3147
3344
|
// src/strategyHelpers/marketContextStages.ts
|
|
3148
|
-
var
|
|
3345
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
3149
3346
|
|
|
3150
3347
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
3151
3348
|
var import_marketContext = require("@tradejs/infra/timescale/marketContext");
|
|
3152
|
-
var
|
|
3349
|
+
var import_logger4 = require("@tradejs/infra/logger");
|
|
3153
3350
|
var import_strategies = require("@tradejs/core/strategies");
|
|
3154
3351
|
|
|
3155
3352
|
// src/binanceBreadthUniverses.ts
|
|
@@ -3513,7 +3710,7 @@ var parseEnabledFlag = (value, env) => {
|
|
|
3513
3710
|
if (normalized === "live") return env !== "BACKTEST";
|
|
3514
3711
|
return false;
|
|
3515
3712
|
};
|
|
3516
|
-
var
|
|
3713
|
+
var toFiniteNumberOrNull2 = (value) => {
|
|
3517
3714
|
const numeric = typeof value === "number" ? value : Number(value);
|
|
3518
3715
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3519
3716
|
};
|
|
@@ -3638,14 +3835,14 @@ var toTradeFlowContext = (row, interval) => row ? {
|
|
|
3638
3835
|
asOfTs: row.ts.getTime(),
|
|
3639
3836
|
ageMs: row.ageMs,
|
|
3640
3837
|
stale: row.stale,
|
|
3641
|
-
trades:
|
|
3642
|
-
buyPressurePct:
|
|
3643
|
-
buyBaseVolume:
|
|
3644
|
-
sellBaseVolume:
|
|
3645
|
-
buyQuoteVolume:
|
|
3646
|
-
sellQuoteVolume:
|
|
3647
|
-
netBaseDelta:
|
|
3648
|
-
netQuoteDelta:
|
|
3838
|
+
trades: toFiniteNumberOrNull2(row.trades),
|
|
3839
|
+
buyPressurePct: toFiniteNumberOrNull2(row.buyPressurePct),
|
|
3840
|
+
buyBaseVolume: toFiniteNumberOrNull2(row.buyBaseVolume),
|
|
3841
|
+
sellBaseVolume: toFiniteNumberOrNull2(row.sellBaseVolume),
|
|
3842
|
+
buyQuoteVolume: toFiniteNumberOrNull2(row.buyQuoteVolume),
|
|
3843
|
+
sellQuoteVolume: toFiniteNumberOrNull2(row.sellQuoteVolume),
|
|
3844
|
+
netBaseDelta: toFiniteNumberOrNull2(row.netBaseDelta),
|
|
3845
|
+
netQuoteDelta: toFiniteNumberOrNull2(row.netQuoteDelta)
|
|
3649
3846
|
} : null;
|
|
3650
3847
|
var getCachedReferenceRows = ({
|
|
3651
3848
|
referenceSymbols,
|
|
@@ -3734,16 +3931,16 @@ var toMarketBreadthContext = (breadth, interval) => ({
|
|
|
3734
3931
|
asOfTs: breadth.ts.getTime(),
|
|
3735
3932
|
ageMs: breadth.ageMs,
|
|
3736
3933
|
stale: breadth.stale,
|
|
3737
|
-
symbolsCount:
|
|
3738
|
-
advancers:
|
|
3739
|
-
decliners:
|
|
3740
|
-
unchanged:
|
|
3741
|
-
advanceDeclineRatio:
|
|
3742
|
-
pctAboveMa20:
|
|
3743
|
-
pctAboveMa50:
|
|
3744
|
-
equalWeightedReturn:
|
|
3745
|
-
volumeWeightedReturn:
|
|
3746
|
-
dispersion:
|
|
3934
|
+
symbolsCount: toFiniteNumberOrNull2(breadth.symbolsCount),
|
|
3935
|
+
advancers: toFiniteNumberOrNull2(breadth.advancers),
|
|
3936
|
+
decliners: toFiniteNumberOrNull2(breadth.decliners),
|
|
3937
|
+
unchanged: toFiniteNumberOrNull2(breadth.unchanged),
|
|
3938
|
+
advanceDeclineRatio: toFiniteNumberOrNull2(breadth.advanceDeclineRatio),
|
|
3939
|
+
pctAboveMa20: toFiniteNumberOrNull2(breadth.pctAboveMa20),
|
|
3940
|
+
pctAboveMa50: toFiniteNumberOrNull2(breadth.pctAboveMa50),
|
|
3941
|
+
equalWeightedReturn: toFiniteNumberOrNull2(breadth.equalWeightedReturn),
|
|
3942
|
+
volumeWeightedReturn: toFiniteNumberOrNull2(breadth.volumeWeightedReturn),
|
|
3943
|
+
dispersion: toFiniteNumberOrNull2(breadth.dispersion)
|
|
3747
3944
|
});
|
|
3748
3945
|
var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
3749
3946
|
const {
|
|
@@ -3844,46 +4041,46 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3844
4041
|
asOfTs: primaryBreadth.ts.getTime(),
|
|
3845
4042
|
ageMs: primaryBreadth.ageMs,
|
|
3846
4043
|
stale: primaryBreadth.stale,
|
|
3847
|
-
btcReturn1h:
|
|
4044
|
+
btcReturn1h: toFiniteNumberOrNull2(
|
|
3848
4045
|
primaryBreadth.btcReturn1h
|
|
3849
4046
|
),
|
|
3850
|
-
btcReturn4h:
|
|
4047
|
+
btcReturn4h: toFiniteNumberOrNull2(
|
|
3851
4048
|
primaryBreadth.btcReturn4h
|
|
3852
4049
|
),
|
|
3853
|
-
btcReturn24h:
|
|
4050
|
+
btcReturn24h: toFiniteNumberOrNull2(
|
|
3854
4051
|
primaryBreadth.btcReturn24h
|
|
3855
4052
|
),
|
|
3856
|
-
altBasketReturn1h:
|
|
4053
|
+
altBasketReturn1h: toFiniteNumberOrNull2(
|
|
3857
4054
|
primaryBreadth.altBasketReturn1h
|
|
3858
4055
|
),
|
|
3859
|
-
altBasketReturn4h:
|
|
4056
|
+
altBasketReturn4h: toFiniteNumberOrNull2(
|
|
3860
4057
|
primaryBreadth.altBasketReturn4h
|
|
3861
4058
|
),
|
|
3862
|
-
altBasketReturn24h:
|
|
4059
|
+
altBasketReturn24h: toFiniteNumberOrNull2(
|
|
3863
4060
|
primaryBreadth.altBasketReturn24h
|
|
3864
4061
|
),
|
|
3865
|
-
btcVsAltReturn1h:
|
|
4062
|
+
btcVsAltReturn1h: toFiniteNumberOrNull2(
|
|
3866
4063
|
primaryBreadth.btcVsAltReturn1h
|
|
3867
4064
|
),
|
|
3868
|
-
btcVsAltReturn4h:
|
|
4065
|
+
btcVsAltReturn4h: toFiniteNumberOrNull2(
|
|
3869
4066
|
primaryBreadth.btcVsAltReturn4h
|
|
3870
4067
|
),
|
|
3871
|
-
btcVsAltReturn24h:
|
|
4068
|
+
btcVsAltReturn24h: toFiniteNumberOrNull2(
|
|
3872
4069
|
primaryBreadth.btcVsAltReturn24h
|
|
3873
4070
|
),
|
|
3874
|
-
btcTurnoverShare1h:
|
|
4071
|
+
btcTurnoverShare1h: toFiniteNumberOrNull2(
|
|
3875
4072
|
primaryBreadth.btcTurnoverShare1h
|
|
3876
4073
|
),
|
|
3877
|
-
btcTurnoverShare24h:
|
|
4074
|
+
btcTurnoverShare24h: toFiniteNumberOrNull2(
|
|
3878
4075
|
primaryBreadth.btcTurnoverShare24h
|
|
3879
4076
|
),
|
|
3880
|
-
btcTurnoverShareChange24h:
|
|
4077
|
+
btcTurnoverShareChange24h: toFiniteNumberOrNull2(
|
|
3881
4078
|
primaryBreadth.btcTurnoverShareChange24h
|
|
3882
4079
|
),
|
|
3883
|
-
altVolToBtcVol24h:
|
|
4080
|
+
altVolToBtcVol24h: toFiniteNumberOrNull2(
|
|
3884
4081
|
primaryBreadth.altVolToBtcVol24h
|
|
3885
4082
|
),
|
|
3886
|
-
altDispersion24h:
|
|
4083
|
+
altDispersion24h: toFiniteNumberOrNull2(
|
|
3887
4084
|
primaryBreadth.altDispersion24h
|
|
3888
4085
|
),
|
|
3889
4086
|
regime: primaryBreadth.btcAltRegime ?? "unknown"
|
|
@@ -3900,7 +4097,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3900
4097
|
throw error;
|
|
3901
4098
|
}
|
|
3902
4099
|
binanceMarketContextUnavailable = true;
|
|
3903
|
-
|
|
4100
|
+
import_logger4.logger.warn(
|
|
3904
4101
|
"Binance market context disabled after Timescale read failure: %s",
|
|
3905
4102
|
String(error)
|
|
3906
4103
|
);
|
|
@@ -3910,7 +4107,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3910
4107
|
|
|
3911
4108
|
// src/strategyHelpers/coinMarketCapContext.ts
|
|
3912
4109
|
var import_strategies2 = require("@tradejs/core/strategies");
|
|
3913
|
-
var
|
|
4110
|
+
var import_logger5 = require("@tradejs/infra/logger");
|
|
3914
4111
|
var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
|
|
3915
4112
|
var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
|
|
3916
4113
|
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
@@ -3948,7 +4145,7 @@ var asInt = (value, fallback) => {
|
|
|
3948
4145
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
3949
4146
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
3950
4147
|
};
|
|
3951
|
-
var
|
|
4148
|
+
var toFiniteNumberOrNull3 = (value) => {
|
|
3952
4149
|
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
3953
4150
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3954
4151
|
};
|
|
@@ -4182,12 +4379,12 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4182
4379
|
const ethRow = references.get("ETHUSDT") ?? null;
|
|
4183
4380
|
const previousBtcRow = previousReferences.get("BTCUSDT") ?? null;
|
|
4184
4381
|
const previousEthRow = previousReferences.get("ETHUSDT") ?? null;
|
|
4185
|
-
const btcMarketCapUsd =
|
|
4186
|
-
const ethMarketCapUsd =
|
|
4187
|
-
const previousBtcMarketCapUsd =
|
|
4382
|
+
const btcMarketCapUsd = toFiniteNumberOrNull3(btcRow?.marketCapUsd);
|
|
4383
|
+
const ethMarketCapUsd = toFiniteNumberOrNull3(ethRow?.marketCapUsd);
|
|
4384
|
+
const previousBtcMarketCapUsd = toFiniteNumberOrNull3(
|
|
4188
4385
|
previousBtcRow?.marketCapUsd
|
|
4189
4386
|
);
|
|
4190
|
-
const previousEthMarketCapUsd =
|
|
4387
|
+
const previousEthMarketCapUsd = toFiniteNumberOrNull3(
|
|
4191
4388
|
previousEthRow?.marketCapUsd
|
|
4192
4389
|
);
|
|
4193
4390
|
const ethBtcMarketCapRatio = safeDivide(ethMarketCapUsd, btcMarketCapUsd);
|
|
@@ -4196,16 +4393,16 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4196
4393
|
previousBtcMarketCapUsd
|
|
4197
4394
|
);
|
|
4198
4395
|
const ethBtcMarketCapRatioChange24hPct = ethBtcMarketCapRatio != null && previousEthBtcMarketCapRatio != null && previousEthBtcMarketCapRatio > 0 ? (ethBtcMarketCapRatio - previousEthBtcMarketCapRatio) / previousEthBtcMarketCapRatio : null;
|
|
4199
|
-
const btcVolumeUsd =
|
|
4200
|
-
const ethVolumeUsd =
|
|
4396
|
+
const btcVolumeUsd = toFiniteNumberOrNull3(btcRow?.volumeUsd);
|
|
4397
|
+
const ethVolumeUsd = toFiniteNumberOrNull3(ethRow?.volumeUsd);
|
|
4201
4398
|
const referenceStale = btcRow?.stale === true || ethRow?.stale === true || !btcRow || !ethRow;
|
|
4202
|
-
const btcDominanceChange24hPct =
|
|
4399
|
+
const btcDominanceChange24hPct = toFiniteNumberOrNull3(
|
|
4203
4400
|
globalRow?.btcDominanceChange24hPct
|
|
4204
4401
|
);
|
|
4205
|
-
const altMarketCapChange24hPct =
|
|
4402
|
+
const altMarketCapChange24hPct = toFiniteNumberOrNull3(
|
|
4206
4403
|
globalRow?.altMarketCapChange24hPct
|
|
4207
4404
|
);
|
|
4208
|
-
const altVolumeChange24hPct =
|
|
4405
|
+
const altVolumeChange24hPct = toFiniteNumberOrNull3(
|
|
4209
4406
|
globalRow?.altVolumeChange24hPct
|
|
4210
4407
|
);
|
|
4211
4408
|
const altLiquidityRegime = globalRow ? toAltLiquidityRegime({
|
|
@@ -4216,19 +4413,19 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4216
4413
|
}) : "unknown";
|
|
4217
4414
|
const exchangeLiquidityRegime = exchangeLiquidityRow ? toExchangeLiquidityRegime({
|
|
4218
4415
|
stale: exchangeLiquidityRow.stale,
|
|
4219
|
-
totalVolumeChange24hPct:
|
|
4416
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4220
4417
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4221
4418
|
),
|
|
4222
4419
|
fallback: exchangeLiquidityRow.liquidityRegime ?? "unknown"
|
|
4223
4420
|
}) : "unknown";
|
|
4224
4421
|
const cmc100Row = indexRows.get("cmc100") ?? null;
|
|
4225
4422
|
const cmc20Row = indexRows.get("cmc20") ?? null;
|
|
4226
|
-
const cmc100Value =
|
|
4227
|
-
const cmc20Value =
|
|
4228
|
-
const cmc100Change24hPct =
|
|
4423
|
+
const cmc100Value = toFiniteNumberOrNull3(cmc100Row?.value);
|
|
4424
|
+
const cmc20Value = toFiniteNumberOrNull3(cmc20Row?.value);
|
|
4425
|
+
const cmc100Change24hPct = toFiniteNumberOrNull3(
|
|
4229
4426
|
cmc100Row?.valueChange24hPct
|
|
4230
4427
|
);
|
|
4231
|
-
const cmc20Change24hPct =
|
|
4428
|
+
const cmc20Change24hPct = toFiniteNumberOrNull3(cmc20Row?.valueChange24hPct);
|
|
4232
4429
|
const cmc20ToCmc100Ratio = safeDivide(cmc20Value, cmc100Value);
|
|
4233
4430
|
const cmc20ToCmc100RatioChange24hPct = cmc20Change24hPct != null && cmc100Change24hPct != null ? (1 + cmc20Change24hPct) / (1 + cmc100Change24hPct) - 1 : null;
|
|
4234
4431
|
const indexStale = cmc100Row?.stale === true || cmc20Row?.stale === true || !cmc100Row || !cmc20Row;
|
|
@@ -4252,41 +4449,41 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4252
4449
|
asOfTs: globalRow.ts.getTime(),
|
|
4253
4450
|
ageMs: globalRow.ageMs,
|
|
4254
4451
|
stale: globalRow.stale,
|
|
4255
|
-
totalMarketCapUsd:
|
|
4452
|
+
totalMarketCapUsd: toFiniteNumberOrNull3(
|
|
4256
4453
|
globalRow.totalMarketCapUsd
|
|
4257
4454
|
),
|
|
4258
|
-
totalVolumeUsd:
|
|
4455
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4259
4456
|
globalRow.totalVolumeUsd
|
|
4260
4457
|
),
|
|
4261
|
-
totalVolumeReportedUsd:
|
|
4458
|
+
totalVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4262
4459
|
globalRow.totalVolumeReportedUsd
|
|
4263
4460
|
),
|
|
4264
|
-
altMarketCapUsd:
|
|
4461
|
+
altMarketCapUsd: toFiniteNumberOrNull3(
|
|
4265
4462
|
globalRow.altMarketCapUsd
|
|
4266
4463
|
),
|
|
4267
|
-
altVolumeUsd:
|
|
4268
|
-
altVolumeReportedUsd:
|
|
4464
|
+
altVolumeUsd: toFiniteNumberOrNull3(globalRow.altVolumeUsd),
|
|
4465
|
+
altVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4269
4466
|
globalRow.altVolumeReportedUsd
|
|
4270
4467
|
),
|
|
4271
|
-
btcDominancePct:
|
|
4468
|
+
btcDominancePct: toFiniteNumberOrNull3(
|
|
4272
4469
|
globalRow.btcDominancePct
|
|
4273
4470
|
),
|
|
4274
|
-
ethDominancePct:
|
|
4471
|
+
ethDominancePct: toFiniteNumberOrNull3(
|
|
4275
4472
|
globalRow.ethDominancePct
|
|
4276
4473
|
),
|
|
4277
4474
|
btcDominanceChange24hPct,
|
|
4278
|
-
ethDominanceChange24hPct:
|
|
4475
|
+
ethDominanceChange24hPct: toFiniteNumberOrNull3(
|
|
4279
4476
|
globalRow.ethDominanceChange24hPct
|
|
4280
4477
|
),
|
|
4281
4478
|
altMarketCapChange24hPct,
|
|
4282
4479
|
altVolumeChange24hPct,
|
|
4283
|
-
activeCryptocurrencies:
|
|
4480
|
+
activeCryptocurrencies: toFiniteNumberOrNull3(
|
|
4284
4481
|
globalRow.activeCryptocurrencies
|
|
4285
4482
|
),
|
|
4286
|
-
activeExchanges:
|
|
4483
|
+
activeExchanges: toFiniteNumberOrNull3(
|
|
4287
4484
|
globalRow.activeExchanges
|
|
4288
4485
|
),
|
|
4289
|
-
activeMarketPairs:
|
|
4486
|
+
activeMarketPairs: toFiniteNumberOrNull3(
|
|
4290
4487
|
globalRow.activeMarketPairs
|
|
4291
4488
|
),
|
|
4292
4489
|
altLiquidityRegime
|
|
@@ -4331,22 +4528,22 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4331
4528
|
asOfTs: exchangeLiquidityRow.ts.getTime(),
|
|
4332
4529
|
ageMs: exchangeLiquidityRow.ageMs,
|
|
4333
4530
|
stale: exchangeLiquidityRow.stale,
|
|
4334
|
-
exchangesCount:
|
|
4531
|
+
exchangesCount: toFiniteNumberOrNull3(
|
|
4335
4532
|
exchangeLiquidityRow.exchangesCount
|
|
4336
4533
|
),
|
|
4337
|
-
totalVolumeUsd:
|
|
4534
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4338
4535
|
exchangeLiquidityRow.totalVolumeUsd
|
|
4339
4536
|
),
|
|
4340
|
-
totalVolumeChange24hPct:
|
|
4537
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4341
4538
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4342
4539
|
),
|
|
4343
|
-
binanceVolumeUsd:
|
|
4540
|
+
binanceVolumeUsd: toFiniteNumberOrNull3(
|
|
4344
4541
|
exchangeLiquidityRow.binanceVolumeUsd
|
|
4345
4542
|
),
|
|
4346
|
-
binanceVolumeShare:
|
|
4543
|
+
binanceVolumeShare: toFiniteNumberOrNull3(
|
|
4347
4544
|
exchangeLiquidityRow.binanceVolumeShare
|
|
4348
4545
|
),
|
|
4349
|
-
topExchangeVolumeShare:
|
|
4546
|
+
topExchangeVolumeShare: toFiniteNumberOrNull3(
|
|
4350
4547
|
exchangeLiquidityRow.topExchangeVolumeShare
|
|
4351
4548
|
),
|
|
4352
4549
|
liquidityRegime: exchangeLiquidityRegime
|
|
@@ -4359,11 +4556,11 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4359
4556
|
asOfTs: fearGreedRow.ts.getTime(),
|
|
4360
4557
|
ageMs: fearGreedRow.ageMs,
|
|
4361
4558
|
stale: fearGreedRow.stale,
|
|
4362
|
-
value:
|
|
4363
|
-
valueChange24h:
|
|
4559
|
+
value: toFiniteNumberOrNull3(fearGreedRow.value),
|
|
4560
|
+
valueChange24h: toFiniteNumberOrNull3(
|
|
4364
4561
|
fearGreedRow.valueChange24h
|
|
4365
4562
|
),
|
|
4366
|
-
valueChange7d:
|
|
4563
|
+
valueChange7d: toFiniteNumberOrNull3(
|
|
4367
4564
|
fearGreedRow.valueChange7d
|
|
4368
4565
|
),
|
|
4369
4566
|
classification: fearGreedRow.classification ?? "Unknown",
|
|
@@ -4383,13 +4580,13 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4383
4580
|
cmc100Value,
|
|
4384
4581
|
cmc100Change24hPct,
|
|
4385
4582
|
cmc100TopConstituentSymbol: cmc100Row?.topConstituentSymbol ?? null,
|
|
4386
|
-
cmc100TopConstituentWeightPct:
|
|
4583
|
+
cmc100TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4387
4584
|
cmc100Row?.topConstituentWeightPct
|
|
4388
4585
|
),
|
|
4389
4586
|
cmc20Value,
|
|
4390
4587
|
cmc20Change24hPct,
|
|
4391
4588
|
cmc20TopConstituentSymbol: cmc20Row?.topConstituentSymbol ?? null,
|
|
4392
|
-
cmc20TopConstituentWeightPct:
|
|
4589
|
+
cmc20TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4393
4590
|
cmc20Row?.topConstituentWeightPct
|
|
4394
4591
|
),
|
|
4395
4592
|
cmc20ToCmc100Ratio,
|
|
@@ -4407,7 +4604,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4407
4604
|
throw error;
|
|
4408
4605
|
}
|
|
4409
4606
|
coinMarketCapContextUnavailable = true;
|
|
4410
|
-
|
|
4607
|
+
import_logger5.logger.warn(
|
|
4411
4608
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
4412
4609
|
String(error)
|
|
4413
4610
|
);
|
|
@@ -4421,7 +4618,7 @@ var import_data2 = require("@tradejs/core/data");
|
|
|
4421
4618
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
4422
4619
|
var import_constants2 = require("@tradejs/core/constants");
|
|
4423
4620
|
var import_derivatives = require("@tradejs/infra/timescale/derivatives");
|
|
4424
|
-
var
|
|
4621
|
+
var import_logger6 = require("@tradejs/infra/logger");
|
|
4425
4622
|
var STORED_INTERVALS = ["15m", "1h"];
|
|
4426
4623
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
4427
4624
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
@@ -4476,7 +4673,7 @@ var resolvePrimaryReferenceSymbol2 = () => PRIMARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
|
4476
4673
|
var resolveSecondaryReferenceSymbol = () => SECONDARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
4477
4674
|
var getPrimaryIntervalContext = (context) => context?.intervals["15m"] ?? context?.intervals["1h"] ?? null;
|
|
4478
4675
|
var hasDerivativesSymbolData = (context) => Object.keys(context.intervals).length > 0 && !context.summary.riskFlags.includes("missing_derivatives");
|
|
4479
|
-
var
|
|
4676
|
+
var toFiniteNumberOrNull4 = (value) => {
|
|
4480
4677
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4481
4678
|
if (typeof value === "string" && value.trim()) {
|
|
4482
4679
|
const parsed = Number(value);
|
|
@@ -4490,8 +4687,8 @@ var roundNullable = (value, digits = 4) => {
|
|
|
4490
4687
|
return Math.round(value * multiplier) / multiplier;
|
|
4491
4688
|
};
|
|
4492
4689
|
var deltaNullable = (targetValue, referenceValue) => {
|
|
4493
|
-
const target =
|
|
4494
|
-
const reference =
|
|
4690
|
+
const target = toFiniteNumberOrNull4(targetValue);
|
|
4691
|
+
const reference = toFiniteNumberOrNull4(referenceValue);
|
|
4495
4692
|
return target == null || reference == null ? null : roundNullable(target - reference);
|
|
4496
4693
|
};
|
|
4497
4694
|
var buildTargetDerivedContext = (params) => {
|
|
@@ -4653,7 +4850,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4653
4850
|
throw error;
|
|
4654
4851
|
}
|
|
4655
4852
|
derivativesContextUnavailable = true;
|
|
4656
|
-
|
|
4853
|
+
import_logger6.logger.warn(
|
|
4657
4854
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
4658
4855
|
String(error)
|
|
4659
4856
|
);
|
|
@@ -4665,7 +4862,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4665
4862
|
var import_data3 = require("@tradejs/core/data");
|
|
4666
4863
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
4667
4864
|
var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
|
|
4668
|
-
var
|
|
4865
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
4669
4866
|
|
|
4670
4867
|
// src/hyperliquidWhaleUniverse.ts
|
|
4671
4868
|
var import_node_crypto3 = require("crypto");
|
|
@@ -5185,7 +5382,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
5185
5382
|
throw error;
|
|
5186
5383
|
}
|
|
5187
5384
|
hyperliquidWhaleContextUnavailable = true;
|
|
5188
|
-
|
|
5385
|
+
import_logger7.logger.warn(
|
|
5189
5386
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
5190
5387
|
String(error)
|
|
5191
5388
|
);
|
|
@@ -5268,7 +5465,7 @@ var runMarketContextStage = async ({
|
|
|
5268
5465
|
elapsedMs: Date.now() - startedAt
|
|
5269
5466
|
};
|
|
5270
5467
|
if (status === "timed_out") {
|
|
5271
|
-
|
|
5468
|
+
import_logger8.logger.warn(
|
|
5272
5469
|
"Market context stage timed out: %s after %sms",
|
|
5273
5470
|
stage,
|
|
5274
5471
|
result.elapsedMs
|
|
@@ -5458,79 +5655,10 @@ var enrichSignalWithAi = async ({
|
|
|
5458
5655
|
signal.aiAnalysis = analysis;
|
|
5459
5656
|
return resolveAiQuality(analysis, direction);
|
|
5460
5657
|
} catch (err) {
|
|
5461
|
-
|
|
5658
|
+
import_logger9.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
|
|
5462
5659
|
}
|
|
5463
5660
|
return void 0;
|
|
5464
5661
|
};
|
|
5465
|
-
var toFiniteNumberOrNull4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5466
|
-
var getOrderArrivalSnapshot = async ({
|
|
5467
|
-
connector,
|
|
5468
|
-
symbol
|
|
5469
|
-
}) => {
|
|
5470
|
-
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
5471
|
-
return {
|
|
5472
|
-
arrivalSnapshotTime: Date.now(),
|
|
5473
|
-
arrivalSource: "unavailable",
|
|
5474
|
-
bid: null,
|
|
5475
|
-
ask: null,
|
|
5476
|
-
arrivalMid: null,
|
|
5477
|
-
spreadBps: null
|
|
5478
|
-
};
|
|
5479
|
-
}
|
|
5480
|
-
try {
|
|
5481
|
-
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
5482
|
-
const arrivalSnapshotTime = toFiniteNumberOrNull4(ticker?.timestamp);
|
|
5483
|
-
const bid = toFiniteNumberOrNull4(ticker?.bidPrice);
|
|
5484
|
-
const ask = toFiniteNumberOrNull4(ticker?.askPrice);
|
|
5485
|
-
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
5486
|
-
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
5487
|
-
return {
|
|
5488
|
-
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
5489
|
-
arrivalSource: "top_of_book",
|
|
5490
|
-
bid,
|
|
5491
|
-
ask,
|
|
5492
|
-
arrivalMid,
|
|
5493
|
-
spreadBps
|
|
5494
|
-
};
|
|
5495
|
-
} catch (error) {
|
|
5496
|
-
import_logger8.logger.warn(
|
|
5497
|
-
"runtime order arrival snapshot failed: %s %s",
|
|
5498
|
-
symbol,
|
|
5499
|
-
error?.message || String(error)
|
|
5500
|
-
);
|
|
5501
|
-
return {
|
|
5502
|
-
arrivalSnapshotTime: Date.now(),
|
|
5503
|
-
arrivalSource: "top_of_book_error",
|
|
5504
|
-
bid: null,
|
|
5505
|
-
ask: null,
|
|
5506
|
-
arrivalMid: null,
|
|
5507
|
-
spreadBps: null
|
|
5508
|
-
};
|
|
5509
|
-
}
|
|
5510
|
-
};
|
|
5511
|
-
var validateEntryProtectionAtArrival = ({
|
|
5512
|
-
direction,
|
|
5513
|
-
signalPrice,
|
|
5514
|
-
bid,
|
|
5515
|
-
ask,
|
|
5516
|
-
arrivalMid,
|
|
5517
|
-
takeProfits,
|
|
5518
|
-
stopLossPrice
|
|
5519
|
-
}) => {
|
|
5520
|
-
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
5521
|
-
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
5522
|
-
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
5523
|
-
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
5524
|
-
}
|
|
5525
|
-
for (const takeProfit of takeProfits) {
|
|
5526
|
-
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
5527
|
-
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
5528
|
-
}
|
|
5529
|
-
}
|
|
5530
|
-
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
5531
|
-
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
5532
|
-
}
|
|
5533
|
-
};
|
|
5534
5662
|
var resolveRuntimeTelemetryQuality = ({
|
|
5535
5663
|
signalClosePrice,
|
|
5536
5664
|
arrivalMid,
|
|
@@ -5607,7 +5735,8 @@ var executeEntryOrder = async ({
|
|
|
5607
5735
|
signal,
|
|
5608
5736
|
beforePlaceOrder,
|
|
5609
5737
|
recordRuntimeTrade = true,
|
|
5610
|
-
leverage
|
|
5738
|
+
leverage,
|
|
5739
|
+
executionLimits
|
|
5611
5740
|
}) => {
|
|
5612
5741
|
await beforePlaceOrder?.();
|
|
5613
5742
|
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
@@ -5618,23 +5747,57 @@ var executeEntryOrder = async ({
|
|
|
5618
5747
|
signal.orderQty = qty;
|
|
5619
5748
|
signal.orderValue = qty * currentPrice;
|
|
5620
5749
|
signal.orderFailureReason = void 0;
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5750
|
+
let arrivalSnapshot = {
|
|
5751
|
+
arrivalSnapshotTime: Date.now(),
|
|
5752
|
+
arrivalSource: "unavailable",
|
|
5753
|
+
bid: null,
|
|
5754
|
+
ask: null,
|
|
5755
|
+
arrivalMid: null,
|
|
5756
|
+
spreadBps: null
|
|
5757
|
+
};
|
|
5758
|
+
let orderSubmitTime = Date.now();
|
|
5759
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
5760
|
+
connector,
|
|
5761
|
+
symbol,
|
|
5762
|
+
direction,
|
|
5763
|
+
takeProfits,
|
|
5764
|
+
stopLossPrice,
|
|
5765
|
+
limits: executionLimits,
|
|
5766
|
+
onValidated: (snapshot2, economics2) => {
|
|
5767
|
+
arrivalSnapshot = snapshot2;
|
|
5768
|
+
orderSubmitTime = Date.now();
|
|
5769
|
+
if (executionLimits?.maxLossValue != null) {
|
|
5770
|
+
signal.riskDecision = {
|
|
5771
|
+
stage: "order_plan",
|
|
5772
|
+
status: economics2.riskExceeded ? "warning" : "approved",
|
|
5773
|
+
reason: economics2.riskExceeded ? "ENTRY_RISK_EXCEEDS_MAX_LOSS_AT_SUBMISSION" : "PLANNED_LOSS_WITHIN_MAX_LOSS_VALUE",
|
|
5774
|
+
plannedLossValue: economics2.plannedLossValue,
|
|
5775
|
+
maxLossValue: executionLimits.maxLossValue,
|
|
5776
|
+
limitUtilization: economics2.plannedLossValue / executionLimits.maxLossValue,
|
|
5777
|
+
enforced: false
|
|
5778
|
+
};
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
});
|
|
5782
|
+
if (!beforeSubmit) {
|
|
5783
|
+
arrivalSnapshot = await getOrderArrivalSnapshot({ connector, symbol });
|
|
5784
|
+
try {
|
|
5785
|
+
validateEntryProtectionAtArrival({
|
|
5786
|
+
direction,
|
|
5787
|
+
signalPrice: currentPrice,
|
|
5788
|
+
bid: arrivalSnapshot.bid,
|
|
5789
|
+
ask: arrivalSnapshot.ask,
|
|
5790
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
5791
|
+
takeProfits,
|
|
5792
|
+
stopLossPrice
|
|
5793
|
+
});
|
|
5794
|
+
} catch (error) {
|
|
5795
|
+
signal.orderStatus = "failed";
|
|
5796
|
+
signal.orderFailureReason = error.message;
|
|
5797
|
+
throw error;
|
|
5798
|
+
}
|
|
5799
|
+
orderSubmitTime = Date.now();
|
|
5636
5800
|
}
|
|
5637
|
-
const orderSubmitTime = Date.now();
|
|
5638
5801
|
const orderPlaced = await connector.placeOrder({
|
|
5639
5802
|
symbol,
|
|
5640
5803
|
qty,
|
|
@@ -5645,7 +5808,8 @@ var executeEntryOrder = async ({
|
|
|
5645
5808
|
direction,
|
|
5646
5809
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
5647
5810
|
orderId,
|
|
5648
|
-
signal
|
|
5811
|
+
signal,
|
|
5812
|
+
...beforeSubmit ? { beforeSubmit } : {}
|
|
5649
5813
|
});
|
|
5650
5814
|
const orderAckTime = Date.now();
|
|
5651
5815
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
@@ -6474,7 +6638,7 @@ var canUseSharedReplayState = ({
|
|
|
6474
6638
|
}) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
|
|
6475
6639
|
|
|
6476
6640
|
// src/strategy/runtimeExecution.ts
|
|
6477
|
-
var
|
|
6641
|
+
var import_logger10 = require("@tradejs/infra/logger");
|
|
6478
6642
|
var import_types = require("@tradejs/types");
|
|
6479
6643
|
var buildExitOrderSignal = ({
|
|
6480
6644
|
strategyName,
|
|
@@ -6526,7 +6690,7 @@ var handleExitDecision = async ({
|
|
|
6526
6690
|
deploymentId: connector.deploymentId
|
|
6527
6691
|
});
|
|
6528
6692
|
if (!activeTrade) {
|
|
6529
|
-
|
|
6693
|
+
import_logger10.logger.warn(
|
|
6530
6694
|
"[%s] blocked closePosition for untracked runtime position: %s",
|
|
6531
6695
|
strategyName ?? "unknown",
|
|
6532
6696
|
symbol
|
|
@@ -6534,7 +6698,7 @@ var handleExitDecision = async ({
|
|
|
6534
6698
|
return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
|
|
6535
6699
|
}
|
|
6536
6700
|
if (!strategyName || activeTrade.strategy !== strategyName) {
|
|
6537
|
-
|
|
6701
|
+
import_logger10.logger.warn(
|
|
6538
6702
|
"[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
|
|
6539
6703
|
strategyName ?? "unknown",
|
|
6540
6704
|
symbol,
|
|
@@ -6587,7 +6751,7 @@ var handleExitDecision = async ({
|
|
|
6587
6751
|
exitType: closedTrade?.exitType ?? "exit"
|
|
6588
6752
|
});
|
|
6589
6753
|
} catch (notificationError) {
|
|
6590
|
-
|
|
6754
|
+
import_logger10.logger.error(
|
|
6591
6755
|
"runtime close notification error: %s %s",
|
|
6592
6756
|
symbol,
|
|
6593
6757
|
notificationError
|
|
@@ -6601,7 +6765,7 @@ var handleExitDecision = async ({
|
|
|
6601
6765
|
decision,
|
|
6602
6766
|
market
|
|
6603
6767
|
});
|
|
6604
|
-
|
|
6768
|
+
import_logger10.logger.error("close order error: %s %s", symbol, err);
|
|
6605
6769
|
return "ORDER_ERROR";
|
|
6606
6770
|
}
|
|
6607
6771
|
return decision.code;
|
|
@@ -6628,7 +6792,7 @@ var handleProtectDecision = async ({
|
|
|
6628
6792
|
decision,
|
|
6629
6793
|
market
|
|
6630
6794
|
});
|
|
6631
|
-
|
|
6795
|
+
import_logger10.logger.error("protect position error: %s %s", symbol, err);
|
|
6632
6796
|
return "ORDER_ERROR";
|
|
6633
6797
|
}
|
|
6634
6798
|
return decision.code;
|
|
@@ -6694,7 +6858,11 @@ var executeEntryDecision = async ({
|
|
|
6694
6858
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
6695
6859
|
signal,
|
|
6696
6860
|
beforePlaceOrder,
|
|
6697
|
-
recordRuntimeTrade: recordRuntimeJournal
|
|
6861
|
+
recordRuntimeTrade: recordRuntimeJournal,
|
|
6862
|
+
executionLimits: resolveEntryExecutionLimits(
|
|
6863
|
+
hookCtx.strategyConfig,
|
|
6864
|
+
decision.entryContext.direction
|
|
6865
|
+
)
|
|
6698
6866
|
});
|
|
6699
6867
|
await invokeStageHooks(
|
|
6700
6868
|
"afterPlaceOrder",
|
|
@@ -6716,19 +6884,32 @@ var executeEntryDecision = async ({
|
|
|
6716
6884
|
return signal;
|
|
6717
6885
|
}
|
|
6718
6886
|
await beforePlaceOrder();
|
|
6719
|
-
const
|
|
6887
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
6720
6888
|
connector,
|
|
6721
|
-
symbol
|
|
6722
|
-
});
|
|
6723
|
-
validateEntryProtectionAtArrival({
|
|
6889
|
+
symbol,
|
|
6724
6890
|
direction: decision.entryContext.direction,
|
|
6725
|
-
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6726
|
-
bid: arrivalSnapshot.bid,
|
|
6727
|
-
ask: arrivalSnapshot.ask,
|
|
6728
|
-
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6729
6891
|
takeProfits: decision.orderPlan.takeProfits,
|
|
6730
|
-
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6892
|
+
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
6893
|
+
limits: resolveEntryExecutionLimits(
|
|
6894
|
+
hookCtx.strategyConfig,
|
|
6895
|
+
decision.entryContext.direction
|
|
6896
|
+
)
|
|
6731
6897
|
});
|
|
6898
|
+
if (!beforeSubmit) {
|
|
6899
|
+
const arrivalSnapshot = await getOrderArrivalSnapshot({
|
|
6900
|
+
connector,
|
|
6901
|
+
symbol
|
|
6902
|
+
});
|
|
6903
|
+
validateEntryProtectionAtArrival({
|
|
6904
|
+
direction: decision.entryContext.direction,
|
|
6905
|
+
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6906
|
+
bid: arrivalSnapshot.bid,
|
|
6907
|
+
ask: arrivalSnapshot.ask,
|
|
6908
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6909
|
+
takeProfits: decision.orderPlan.takeProfits,
|
|
6910
|
+
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6911
|
+
});
|
|
6912
|
+
}
|
|
6732
6913
|
const orderPlaced = await connector.placeOrder({
|
|
6733
6914
|
symbol,
|
|
6734
6915
|
qty: decision.orderPlan.qty,
|
|
@@ -6736,6 +6917,7 @@ var executeEntryDecision = async ({
|
|
|
6736
6917
|
timestamp: decision.entryContext.timestamp,
|
|
6737
6918
|
direction: decision.entryContext.direction,
|
|
6738
6919
|
positionIntent: decision.orderPlan.positionIntent,
|
|
6920
|
+
...beforeSubmit ? { beforeSubmit } : {},
|
|
6739
6921
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
6740
6922
|
});
|
|
6741
6923
|
if (!orderPlaced) {
|
|
@@ -6777,6 +6959,23 @@ var executeEntryDecision = async ({
|
|
|
6777
6959
|
{ decision, entry, market }
|
|
6778
6960
|
);
|
|
6779
6961
|
} catch (err) {
|
|
6962
|
+
if (err instanceof EntrySubmissionValidationError) {
|
|
6963
|
+
if (signal) {
|
|
6964
|
+
signal.orderStatus = "skipped";
|
|
6965
|
+
signal.orderSkipReason = err.message;
|
|
6966
|
+
signal.allocatorDecision = {
|
|
6967
|
+
stage: "runtime_admission",
|
|
6968
|
+
status: "rejected",
|
|
6969
|
+
reason: err.message
|
|
6970
|
+
};
|
|
6971
|
+
}
|
|
6972
|
+
import_logger10.logger.warn(
|
|
6973
|
+
"entry rejected before submission: %s %s",
|
|
6974
|
+
symbol,
|
|
6975
|
+
err.message
|
|
6976
|
+
);
|
|
6977
|
+
return signal ?? err.message;
|
|
6978
|
+
}
|
|
6780
6979
|
if (signal) {
|
|
6781
6980
|
signal.orderStatus = "failed";
|
|
6782
6981
|
if (typeof signal.orderFailureReason !== "string" || !signal.orderFailureReason.trim()) {
|
|
@@ -6791,9 +6990,9 @@ var executeEntryDecision = async ({
|
|
|
6791
6990
|
market
|
|
6792
6991
|
});
|
|
6793
6992
|
if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
|
|
6794
|
-
|
|
6993
|
+
import_logger10.logger.warn("order warning: %s %s", symbol, err);
|
|
6795
6994
|
} else {
|
|
6796
|
-
|
|
6995
|
+
import_logger10.logger.error("order error: %s %s", symbol, err);
|
|
6797
6996
|
}
|
|
6798
6997
|
return signal ?? "ORDER_ERROR";
|
|
6799
6998
|
}
|
|
@@ -6901,6 +7100,9 @@ var createStrategyRuntime = ({
|
|
|
6901
7100
|
});
|
|
6902
7101
|
const strategyPolicyProfile = getPolicyProfile();
|
|
6903
7102
|
const indicatorPeriods = (0, import_strategies6.buildDefaultIndicatorPeriods)(config);
|
|
7103
|
+
const strategyConfig = { ...config };
|
|
7104
|
+
delete strategyConfig.RECORD_RUNTIME_TRADES;
|
|
7105
|
+
delete strategyConfig.SIMULATE_ORDERS;
|
|
6904
7106
|
const hookBase = {
|
|
6905
7107
|
connector,
|
|
6906
7108
|
strategyName,
|
|
@@ -6911,7 +7113,7 @@ var createStrategyRuntime = ({
|
|
|
6911
7113
|
accountId,
|
|
6912
7114
|
deploymentId,
|
|
6913
7115
|
policyProfileId: strategyPolicyProfile?.id ?? requestedPolicyProfileId,
|
|
6914
|
-
strategyConfig
|
|
7116
|
+
strategyConfig,
|
|
6915
7117
|
env,
|
|
6916
7118
|
isConfigFromBacktest
|
|
6917
7119
|
};
|
|
@@ -6958,7 +7160,7 @@ var createStrategyRuntime = ({
|
|
|
6958
7160
|
try {
|
|
6959
7161
|
await projectHook(errorParams);
|
|
6960
7162
|
} catch (hookError) {
|
|
6961
|
-
|
|
7163
|
+
import_logger11.logger.error(
|
|
6962
7164
|
"project hook onRuntimeError failed: %s %s",
|
|
6963
7165
|
strategyName,
|
|
6964
7166
|
hookError
|
|
@@ -6972,21 +7174,21 @@ var createStrategyRuntime = ({
|
|
|
6972
7174
|
try {
|
|
6973
7175
|
await onRuntimeError(errorParams);
|
|
6974
7176
|
} catch (hookError) {
|
|
6975
|
-
|
|
7177
|
+
import_logger11.logger.error(
|
|
6976
7178
|
"runtime hook onRuntimeError failed: %s %s",
|
|
6977
7179
|
strategyName,
|
|
6978
7180
|
hookError
|
|
6979
7181
|
);
|
|
6980
7182
|
}
|
|
6981
7183
|
};
|
|
6982
|
-
const invokeHook = async (stage, hook, params, errorContext = {}) => {
|
|
7184
|
+
const invokeHook = async (stage, hook, params, errorContext = {}, failureResult) => {
|
|
6983
7185
|
if (!hook) {
|
|
6984
7186
|
return void 0;
|
|
6985
7187
|
}
|
|
6986
7188
|
try {
|
|
6987
7189
|
return await hook(params);
|
|
6988
7190
|
} catch (error) {
|
|
6989
|
-
|
|
7191
|
+
import_logger11.logger.error(
|
|
6990
7192
|
'strategy hook "%s" failed for %s: %s',
|
|
6991
7193
|
stage,
|
|
6992
7194
|
strategyName,
|
|
@@ -6999,17 +7201,18 @@ var createStrategyRuntime = ({
|
|
|
6999
7201
|
entry: errorContext.entry,
|
|
7000
7202
|
market: errorContext.market
|
|
7001
7203
|
});
|
|
7002
|
-
return
|
|
7204
|
+
return failureResult;
|
|
7003
7205
|
}
|
|
7004
7206
|
};
|
|
7005
|
-
const invokeProjectHooks = async (stage, params, errorContext = {}) => {
|
|
7207
|
+
const invokeProjectHooks = async (stage, params, errorContext = {}, failureResult) => {
|
|
7006
7208
|
const results = [];
|
|
7007
7209
|
for (const hook of getProjectHookList(stage)) {
|
|
7008
7210
|
const result = await invokeHook(
|
|
7009
7211
|
stage,
|
|
7010
7212
|
hook,
|
|
7011
7213
|
params,
|
|
7012
|
-
errorContext
|
|
7214
|
+
errorContext,
|
|
7215
|
+
failureResult
|
|
7013
7216
|
);
|
|
7014
7217
|
if (result !== void 0) {
|
|
7015
7218
|
results.push(result);
|
|
@@ -7024,10 +7227,12 @@ var createStrategyRuntime = ({
|
|
|
7024
7227
|
return invokeHook(stage, hook, params, errorContext);
|
|
7025
7228
|
};
|
|
7026
7229
|
const invokeGateHooks = async (stage, hook, params, errorContext = {}) => {
|
|
7230
|
+
const failureResult = stage === "beforeEntryGate" ? { allow: false, reason: "ERROR" } : void 0;
|
|
7027
7231
|
const projectResults = await invokeProjectHooks(
|
|
7028
7232
|
stage,
|
|
7029
7233
|
params,
|
|
7030
|
-
errorContext
|
|
7234
|
+
errorContext,
|
|
7235
|
+
failureResult
|
|
7031
7236
|
);
|
|
7032
7237
|
const projectBlock = projectResults.find(
|
|
7033
7238
|
(result) => result?.allow === false
|
|
@@ -7039,7 +7244,8 @@ var createStrategyRuntime = ({
|
|
|
7039
7244
|
stage,
|
|
7040
7245
|
hook,
|
|
7041
7246
|
params,
|
|
7042
|
-
errorContext
|
|
7247
|
+
errorContext,
|
|
7248
|
+
failureResult
|
|
7043
7249
|
);
|
|
7044
7250
|
};
|
|
7045
7251
|
const applyProjectAfterCoreDecisionHooks = async ({
|
|
@@ -7185,11 +7391,8 @@ var createStrategyRuntime = ({
|
|
|
7185
7391
|
return enrichedBaseContext;
|
|
7186
7392
|
}
|
|
7187
7393
|
});
|
|
7188
|
-
const coreConfig = { ...config };
|
|
7189
|
-
delete coreConfig.RECORD_RUNTIME_TRADES;
|
|
7190
|
-
delete coreConfig.SIMULATE_ORDERS;
|
|
7191
7394
|
const core = await createCore({
|
|
7192
|
-
config:
|
|
7395
|
+
config: strategyConfig,
|
|
7193
7396
|
data,
|
|
7194
7397
|
strategyApi,
|
|
7195
7398
|
indicatorsState
|