@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/registry.js
CHANGED
|
@@ -1045,13 +1045,210 @@ var assessSignalWithJev = async ({
|
|
|
1045
1045
|
// src/strategyRuntime.ts
|
|
1046
1046
|
var import_constants5 = require("@tradejs/core/constants");
|
|
1047
1047
|
var import_strategies6 = require("@tradejs/core/strategies");
|
|
1048
|
-
var
|
|
1048
|
+
var import_logger11 = require("@tradejs/infra/logger");
|
|
1049
1049
|
|
|
1050
1050
|
// src/strategyHelpers/runtime.ts
|
|
1051
|
-
var
|
|
1051
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
1052
1052
|
var import_constants3 = require("@tradejs/core/constants");
|
|
1053
1053
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
1054
1054
|
|
|
1055
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1056
|
+
var import_logger = require("@tradejs/infra/logger");
|
|
1057
|
+
|
|
1058
|
+
// src/strategy/entryExecutionValidation.ts
|
|
1059
|
+
var EntrySubmissionValidationError = class extends Error {
|
|
1060
|
+
constructor() {
|
|
1061
|
+
super(...arguments);
|
|
1062
|
+
this.name = "EntrySubmissionValidationError";
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
var resolveEntryExecutionLimits = (config, direction) => {
|
|
1066
|
+
const side = config[direction];
|
|
1067
|
+
const minimum = side && typeof side === "object" && "minRiskRatio" in side ? side.minRiskRatio : void 0;
|
|
1068
|
+
const maximum = config.MAX_LOSS_VALUE;
|
|
1069
|
+
if (minimum == null && maximum == null) return void 0;
|
|
1070
|
+
const minimumNetRiskRatio = minimum == null ? void 0 : Number(minimum);
|
|
1071
|
+
const maxLossValue = maximum == null ? void 0 : Number(maximum);
|
|
1072
|
+
const feeRate = Number(config.RISK_FEE_RATE ?? 0);
|
|
1073
|
+
const slippage = Number(config.RISK_SLIPPAGE_BPS ?? 0);
|
|
1074
|
+
const impact = Number(config.RISK_MARKET_IMPACT_BPS ?? 0);
|
|
1075
|
+
const slippageBps = slippage + impact;
|
|
1076
|
+
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)
|
|
1077
|
+
throw new Error("INVALID_ENTRY_EXECUTION_LIMITS");
|
|
1078
|
+
return { minimumNetRiskRatio, maxLossValue, feeRate, slippageBps };
|
|
1079
|
+
};
|
|
1080
|
+
var validateEntryExecution = ({
|
|
1081
|
+
direction,
|
|
1082
|
+
price,
|
|
1083
|
+
qty,
|
|
1084
|
+
stopLossPrice,
|
|
1085
|
+
takeProfitPrice,
|
|
1086
|
+
limits
|
|
1087
|
+
}) => {
|
|
1088
|
+
if (!Number.isFinite(price) || price <= 0 || !Number.isFinite(qty) || qty <= 0 || stopLossPrice == null || !Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || !Number.isFinite(takeProfitPrice) || takeProfitPrice <= 0)
|
|
1089
|
+
throw new EntrySubmissionValidationError(
|
|
1090
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1091
|
+
);
|
|
1092
|
+
const side = direction === "LONG" ? 1 : -1;
|
|
1093
|
+
if (side * (price - stopLossPrice) <= 0 || side * (takeProfitPrice - price) <= 0)
|
|
1094
|
+
throw new EntrySubmissionValidationError(
|
|
1095
|
+
"INVALID_ENTRY_PROTECTION_AT_SUBMISSION"
|
|
1096
|
+
);
|
|
1097
|
+
const slippage = limits.slippageBps / 1e4;
|
|
1098
|
+
const cost = (value, sign) => value * slippage + value * (1 + sign * slippage) * limits.feeRate;
|
|
1099
|
+
const entryCost = cost(price, side);
|
|
1100
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + entryCost + cost(stopLossPrice, -side);
|
|
1101
|
+
const rewardPerUnit = Math.max(
|
|
1102
|
+
0,
|
|
1103
|
+
Math.abs(takeProfitPrice - price) - entryCost - cost(takeProfitPrice, -side)
|
|
1104
|
+
);
|
|
1105
|
+
const netRiskRatio = rewardPerUnit / lossPerUnit;
|
|
1106
|
+
const plannedLossValue = qty * lossPerUnit;
|
|
1107
|
+
if (!Number.isFinite(netRiskRatio) || !Number.isFinite(plannedLossValue))
|
|
1108
|
+
throw new EntrySubmissionValidationError(
|
|
1109
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
1110
|
+
);
|
|
1111
|
+
if (limits.minimumNetRiskRatio != null && netRiskRatio <= limits.minimumNetRiskRatio)
|
|
1112
|
+
throw new EntrySubmissionValidationError(
|
|
1113
|
+
"ENTRY_RR_BELOW_MIN_AT_SUBMISSION"
|
|
1114
|
+
);
|
|
1115
|
+
const riskExceeded = limits.maxLossValue != null && plannedLossValue > limits.maxLossValue * (1 + 1e-9);
|
|
1116
|
+
return { netRiskRatio, plannedLossValue, riskExceeded };
|
|
1117
|
+
};
|
|
1118
|
+
|
|
1119
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
1120
|
+
var MAX_ENTRY_QUOTE_AGE_MS = 5e3;
|
|
1121
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
1122
|
+
var getOrderArrivalSnapshot = async ({
|
|
1123
|
+
connector,
|
|
1124
|
+
symbol,
|
|
1125
|
+
requireTimestamp = false
|
|
1126
|
+
}) => {
|
|
1127
|
+
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
1128
|
+
return {
|
|
1129
|
+
arrivalSnapshotTime: Date.now(),
|
|
1130
|
+
arrivalSource: "unavailable",
|
|
1131
|
+
bid: null,
|
|
1132
|
+
ask: null,
|
|
1133
|
+
arrivalMid: null,
|
|
1134
|
+
spreadBps: null
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
try {
|
|
1138
|
+
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
1139
|
+
const arrivalSnapshotTime = toFiniteNumberOrNull(ticker?.timestamp);
|
|
1140
|
+
const timestampUnavailable = requireTimestamp && arrivalSnapshotTime == null;
|
|
1141
|
+
const bid = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.bidPrice);
|
|
1142
|
+
const ask = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.askPrice);
|
|
1143
|
+
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
1144
|
+
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
1145
|
+
return {
|
|
1146
|
+
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
1147
|
+
arrivalSource: "top_of_book",
|
|
1148
|
+
bid,
|
|
1149
|
+
ask,
|
|
1150
|
+
arrivalMid,
|
|
1151
|
+
spreadBps
|
|
1152
|
+
};
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
import_logger.logger.warn(
|
|
1155
|
+
"runtime order arrival snapshot failed: %s %s",
|
|
1156
|
+
symbol,
|
|
1157
|
+
error?.message || String(error)
|
|
1158
|
+
);
|
|
1159
|
+
return {
|
|
1160
|
+
arrivalSnapshotTime: Date.now(),
|
|
1161
|
+
arrivalSource: "top_of_book_error",
|
|
1162
|
+
bid: null,
|
|
1163
|
+
ask: null,
|
|
1164
|
+
arrivalMid: null,
|
|
1165
|
+
spreadBps: null
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
var validateEntryProtectionAtArrival = ({
|
|
1170
|
+
direction,
|
|
1171
|
+
signalPrice,
|
|
1172
|
+
bid,
|
|
1173
|
+
ask,
|
|
1174
|
+
arrivalMid,
|
|
1175
|
+
takeProfits,
|
|
1176
|
+
stopLossPrice
|
|
1177
|
+
}) => {
|
|
1178
|
+
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
1179
|
+
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
1180
|
+
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
1181
|
+
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
1182
|
+
}
|
|
1183
|
+
for (const takeProfit of takeProfits) {
|
|
1184
|
+
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
1185
|
+
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
1189
|
+
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
var createEntrySubmissionValidation = ({
|
|
1193
|
+
connector,
|
|
1194
|
+
symbol,
|
|
1195
|
+
direction,
|
|
1196
|
+
takeProfits,
|
|
1197
|
+
stopLossPrice,
|
|
1198
|
+
limits,
|
|
1199
|
+
onValidated
|
|
1200
|
+
}) => {
|
|
1201
|
+
if (!limits) return void 0;
|
|
1202
|
+
if (!connector.capabilities?.orderSubmissionValidation)
|
|
1203
|
+
throw new EntrySubmissionValidationError(
|
|
1204
|
+
"ENTRY_SUBMISSION_VALIDATION_UNSUPPORTED"
|
|
1205
|
+
);
|
|
1206
|
+
return async ({ qty, executionPrice }) => {
|
|
1207
|
+
const simulated = Reflect.get(connector, "__tradejsTestConnector") === true;
|
|
1208
|
+
const snapshot2 = simulated && executionPrice != null ? {
|
|
1209
|
+
arrivalSnapshotTime: Date.now(),
|
|
1210
|
+
arrivalSource: "simulation",
|
|
1211
|
+
bid: executionPrice,
|
|
1212
|
+
ask: executionPrice,
|
|
1213
|
+
arrivalMid: executionPrice,
|
|
1214
|
+
spreadBps: 0
|
|
1215
|
+
} : await getOrderArrivalSnapshot({
|
|
1216
|
+
connector,
|
|
1217
|
+
symbol,
|
|
1218
|
+
requireTimestamp: true
|
|
1219
|
+
});
|
|
1220
|
+
const age = Date.now() - snapshot2.arrivalSnapshotTime;
|
|
1221
|
+
if (snapshot2.bid == null || snapshot2.ask == null || !Number.isFinite(snapshot2.bid) || !Number.isFinite(snapshot2.ask) || snapshot2.bid <= 0 || snapshot2.ask < snapshot2.bid)
|
|
1222
|
+
throw new EntrySubmissionValidationError(
|
|
1223
|
+
"ENTRY_QUOTE_UNAVAILABLE_AT_SUBMISSION"
|
|
1224
|
+
);
|
|
1225
|
+
if (!Number.isFinite(age) || age < -MAX_ENTRY_QUOTE_AGE_MS || age > MAX_ENTRY_QUOTE_AGE_MS)
|
|
1226
|
+
throw new EntrySubmissionValidationError(
|
|
1227
|
+
"ENTRY_QUOTE_STALE_AT_SUBMISSION"
|
|
1228
|
+
);
|
|
1229
|
+
const price = direction === "LONG" ? snapshot2.ask : snapshot2.bid;
|
|
1230
|
+
validateEntryProtectionAtArrival({
|
|
1231
|
+
direction,
|
|
1232
|
+
signalPrice: price,
|
|
1233
|
+
bid: snapshot2.bid,
|
|
1234
|
+
ask: snapshot2.ask,
|
|
1235
|
+
arrivalMid: snapshot2.arrivalMid,
|
|
1236
|
+
takeProfits,
|
|
1237
|
+
stopLossPrice
|
|
1238
|
+
});
|
|
1239
|
+
const prices = takeProfits.map((tp) => tp.price);
|
|
1240
|
+
const economics2 = validateEntryExecution({
|
|
1241
|
+
direction,
|
|
1242
|
+
price,
|
|
1243
|
+
qty,
|
|
1244
|
+
stopLossPrice,
|
|
1245
|
+
takeProfitPrice: direction === "LONG" ? Math.max(...prices) : Math.min(...prices),
|
|
1246
|
+
limits
|
|
1247
|
+
});
|
|
1248
|
+
onValidated?.(snapshot2, economics2);
|
|
1249
|
+
};
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1055
1252
|
// src/ai.ts
|
|
1056
1253
|
var import_aiLanguages2 = require("@tradejs/core/aiLanguages");
|
|
1057
1254
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -1636,7 +1833,7 @@ var import_fs = __toESM(require("fs"));
|
|
|
1636
1833
|
var import_path = __toESM(require("path"));
|
|
1637
1834
|
var import_url = require("url");
|
|
1638
1835
|
var import_config = require("@tradejs/core/config");
|
|
1639
|
-
var
|
|
1836
|
+
var import_logger2 = require("@tradejs/infra/logger");
|
|
1640
1837
|
var CONFIG_FILE_NAMES = [
|
|
1641
1838
|
"tradejs.config.ts",
|
|
1642
1839
|
"tradejs.config.mts",
|
|
@@ -1903,11 +2100,11 @@ var loadTradejsConfig = async (cwd = getTradejsProjectCwd()) => {
|
|
|
1903
2100
|
cachedByCwd.set(cwd, config);
|
|
1904
2101
|
if (!announcedConfigFile.has(configFilePath)) {
|
|
1905
2102
|
announcedConfigFile.add(configFilePath);
|
|
1906
|
-
|
|
2103
|
+
import_logger2.logger.log("debug", "Loaded TradeJS config: %s", configFilePath);
|
|
1907
2104
|
}
|
|
1908
2105
|
return config;
|
|
1909
2106
|
} catch (error) {
|
|
1910
|
-
|
|
2107
|
+
import_logger2.logger.log(
|
|
1911
2108
|
"warn",
|
|
1912
2109
|
"Failed to load TradeJS config from %s: %s",
|
|
1913
2110
|
configFilePath,
|
|
@@ -2897,7 +3094,7 @@ var import_node_crypto = require("crypto");
|
|
|
2897
3094
|
var import_constants = require("@tradejs/core/constants");
|
|
2898
3095
|
var import_time = require("@tradejs/core/time");
|
|
2899
3096
|
var import_trade = require("@tradejs/core/trade");
|
|
2900
|
-
var
|
|
3097
|
+
var import_logger3 = require("@tradejs/infra/logger");
|
|
2901
3098
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
2902
3099
|
var now = () => Date.now();
|
|
2903
3100
|
var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
|
|
@@ -2956,7 +3153,7 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
2956
3153
|
)
|
|
2957
3154
|
]);
|
|
2958
3155
|
} catch (error) {
|
|
2959
|
-
|
|
3156
|
+
import_logger3.logger.error(
|
|
2960
3157
|
"runtime trade open journal failed: %s %s",
|
|
2961
3158
|
record.symbol,
|
|
2962
3159
|
error?.message || String(error)
|
|
@@ -3024,7 +3221,7 @@ var recordRuntimeTradeIncrease = async (params) => {
|
|
|
3024
3221
|
)
|
|
3025
3222
|
]);
|
|
3026
3223
|
} catch (error) {
|
|
3027
|
-
|
|
3224
|
+
import_logger3.logger.error(
|
|
3028
3225
|
"runtime trade increase journal failed: %s %s",
|
|
3029
3226
|
symbol,
|
|
3030
3227
|
error?.message || String(error)
|
|
@@ -3131,7 +3328,7 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3131
3328
|
)
|
|
3132
3329
|
]);
|
|
3133
3330
|
} catch (error) {
|
|
3134
|
-
|
|
3331
|
+
import_logger3.logger.error(
|
|
3135
3332
|
"runtime trade close journal failed: %s %s",
|
|
3136
3333
|
symbol,
|
|
3137
3334
|
error?.message || String(error)
|
|
@@ -3141,11 +3338,11 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3141
3338
|
};
|
|
3142
3339
|
|
|
3143
3340
|
// src/strategyHelpers/marketContextStages.ts
|
|
3144
|
-
var
|
|
3341
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
3145
3342
|
|
|
3146
3343
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
3147
3344
|
var import_marketContext = require("@tradejs/infra/timescale/marketContext");
|
|
3148
|
-
var
|
|
3345
|
+
var import_logger4 = require("@tradejs/infra/logger");
|
|
3149
3346
|
var import_strategies = require("@tradejs/core/strategies");
|
|
3150
3347
|
|
|
3151
3348
|
// src/binanceBreadthUniverses.ts
|
|
@@ -3509,7 +3706,7 @@ var parseEnabledFlag = (value, env) => {
|
|
|
3509
3706
|
if (normalized === "live") return env !== "BACKTEST";
|
|
3510
3707
|
return false;
|
|
3511
3708
|
};
|
|
3512
|
-
var
|
|
3709
|
+
var toFiniteNumberOrNull2 = (value) => {
|
|
3513
3710
|
const numeric = typeof value === "number" ? value : Number(value);
|
|
3514
3711
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3515
3712
|
};
|
|
@@ -3634,14 +3831,14 @@ var toTradeFlowContext = (row, interval) => row ? {
|
|
|
3634
3831
|
asOfTs: row.ts.getTime(),
|
|
3635
3832
|
ageMs: row.ageMs,
|
|
3636
3833
|
stale: row.stale,
|
|
3637
|
-
trades:
|
|
3638
|
-
buyPressurePct:
|
|
3639
|
-
buyBaseVolume:
|
|
3640
|
-
sellBaseVolume:
|
|
3641
|
-
buyQuoteVolume:
|
|
3642
|
-
sellQuoteVolume:
|
|
3643
|
-
netBaseDelta:
|
|
3644
|
-
netQuoteDelta:
|
|
3834
|
+
trades: toFiniteNumberOrNull2(row.trades),
|
|
3835
|
+
buyPressurePct: toFiniteNumberOrNull2(row.buyPressurePct),
|
|
3836
|
+
buyBaseVolume: toFiniteNumberOrNull2(row.buyBaseVolume),
|
|
3837
|
+
sellBaseVolume: toFiniteNumberOrNull2(row.sellBaseVolume),
|
|
3838
|
+
buyQuoteVolume: toFiniteNumberOrNull2(row.buyQuoteVolume),
|
|
3839
|
+
sellQuoteVolume: toFiniteNumberOrNull2(row.sellQuoteVolume),
|
|
3840
|
+
netBaseDelta: toFiniteNumberOrNull2(row.netBaseDelta),
|
|
3841
|
+
netQuoteDelta: toFiniteNumberOrNull2(row.netQuoteDelta)
|
|
3645
3842
|
} : null;
|
|
3646
3843
|
var getCachedReferenceRows = ({
|
|
3647
3844
|
referenceSymbols,
|
|
@@ -3730,16 +3927,16 @@ var toMarketBreadthContext = (breadth, interval) => ({
|
|
|
3730
3927
|
asOfTs: breadth.ts.getTime(),
|
|
3731
3928
|
ageMs: breadth.ageMs,
|
|
3732
3929
|
stale: breadth.stale,
|
|
3733
|
-
symbolsCount:
|
|
3734
|
-
advancers:
|
|
3735
|
-
decliners:
|
|
3736
|
-
unchanged:
|
|
3737
|
-
advanceDeclineRatio:
|
|
3738
|
-
pctAboveMa20:
|
|
3739
|
-
pctAboveMa50:
|
|
3740
|
-
equalWeightedReturn:
|
|
3741
|
-
volumeWeightedReturn:
|
|
3742
|
-
dispersion:
|
|
3930
|
+
symbolsCount: toFiniteNumberOrNull2(breadth.symbolsCount),
|
|
3931
|
+
advancers: toFiniteNumberOrNull2(breadth.advancers),
|
|
3932
|
+
decliners: toFiniteNumberOrNull2(breadth.decliners),
|
|
3933
|
+
unchanged: toFiniteNumberOrNull2(breadth.unchanged),
|
|
3934
|
+
advanceDeclineRatio: toFiniteNumberOrNull2(breadth.advanceDeclineRatio),
|
|
3935
|
+
pctAboveMa20: toFiniteNumberOrNull2(breadth.pctAboveMa20),
|
|
3936
|
+
pctAboveMa50: toFiniteNumberOrNull2(breadth.pctAboveMa50),
|
|
3937
|
+
equalWeightedReturn: toFiniteNumberOrNull2(breadth.equalWeightedReturn),
|
|
3938
|
+
volumeWeightedReturn: toFiniteNumberOrNull2(breadth.volumeWeightedReturn),
|
|
3939
|
+
dispersion: toFiniteNumberOrNull2(breadth.dispersion)
|
|
3743
3940
|
});
|
|
3744
3941
|
var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
3745
3942
|
const {
|
|
@@ -3840,46 +4037,46 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3840
4037
|
asOfTs: primaryBreadth.ts.getTime(),
|
|
3841
4038
|
ageMs: primaryBreadth.ageMs,
|
|
3842
4039
|
stale: primaryBreadth.stale,
|
|
3843
|
-
btcReturn1h:
|
|
4040
|
+
btcReturn1h: toFiniteNumberOrNull2(
|
|
3844
4041
|
primaryBreadth.btcReturn1h
|
|
3845
4042
|
),
|
|
3846
|
-
btcReturn4h:
|
|
4043
|
+
btcReturn4h: toFiniteNumberOrNull2(
|
|
3847
4044
|
primaryBreadth.btcReturn4h
|
|
3848
4045
|
),
|
|
3849
|
-
btcReturn24h:
|
|
4046
|
+
btcReturn24h: toFiniteNumberOrNull2(
|
|
3850
4047
|
primaryBreadth.btcReturn24h
|
|
3851
4048
|
),
|
|
3852
|
-
altBasketReturn1h:
|
|
4049
|
+
altBasketReturn1h: toFiniteNumberOrNull2(
|
|
3853
4050
|
primaryBreadth.altBasketReturn1h
|
|
3854
4051
|
),
|
|
3855
|
-
altBasketReturn4h:
|
|
4052
|
+
altBasketReturn4h: toFiniteNumberOrNull2(
|
|
3856
4053
|
primaryBreadth.altBasketReturn4h
|
|
3857
4054
|
),
|
|
3858
|
-
altBasketReturn24h:
|
|
4055
|
+
altBasketReturn24h: toFiniteNumberOrNull2(
|
|
3859
4056
|
primaryBreadth.altBasketReturn24h
|
|
3860
4057
|
),
|
|
3861
|
-
btcVsAltReturn1h:
|
|
4058
|
+
btcVsAltReturn1h: toFiniteNumberOrNull2(
|
|
3862
4059
|
primaryBreadth.btcVsAltReturn1h
|
|
3863
4060
|
),
|
|
3864
|
-
btcVsAltReturn4h:
|
|
4061
|
+
btcVsAltReturn4h: toFiniteNumberOrNull2(
|
|
3865
4062
|
primaryBreadth.btcVsAltReturn4h
|
|
3866
4063
|
),
|
|
3867
|
-
btcVsAltReturn24h:
|
|
4064
|
+
btcVsAltReturn24h: toFiniteNumberOrNull2(
|
|
3868
4065
|
primaryBreadth.btcVsAltReturn24h
|
|
3869
4066
|
),
|
|
3870
|
-
btcTurnoverShare1h:
|
|
4067
|
+
btcTurnoverShare1h: toFiniteNumberOrNull2(
|
|
3871
4068
|
primaryBreadth.btcTurnoverShare1h
|
|
3872
4069
|
),
|
|
3873
|
-
btcTurnoverShare24h:
|
|
4070
|
+
btcTurnoverShare24h: toFiniteNumberOrNull2(
|
|
3874
4071
|
primaryBreadth.btcTurnoverShare24h
|
|
3875
4072
|
),
|
|
3876
|
-
btcTurnoverShareChange24h:
|
|
4073
|
+
btcTurnoverShareChange24h: toFiniteNumberOrNull2(
|
|
3877
4074
|
primaryBreadth.btcTurnoverShareChange24h
|
|
3878
4075
|
),
|
|
3879
|
-
altVolToBtcVol24h:
|
|
4076
|
+
altVolToBtcVol24h: toFiniteNumberOrNull2(
|
|
3880
4077
|
primaryBreadth.altVolToBtcVol24h
|
|
3881
4078
|
),
|
|
3882
|
-
altDispersion24h:
|
|
4079
|
+
altDispersion24h: toFiniteNumberOrNull2(
|
|
3883
4080
|
primaryBreadth.altDispersion24h
|
|
3884
4081
|
),
|
|
3885
4082
|
regime: primaryBreadth.btcAltRegime ?? "unknown"
|
|
@@ -3896,7 +4093,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3896
4093
|
throw error;
|
|
3897
4094
|
}
|
|
3898
4095
|
binanceMarketContextUnavailable = true;
|
|
3899
|
-
|
|
4096
|
+
import_logger4.logger.warn(
|
|
3900
4097
|
"Binance market context disabled after Timescale read failure: %s",
|
|
3901
4098
|
String(error)
|
|
3902
4099
|
);
|
|
@@ -3906,7 +4103,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
3906
4103
|
|
|
3907
4104
|
// src/strategyHelpers/coinMarketCapContext.ts
|
|
3908
4105
|
var import_strategies2 = require("@tradejs/core/strategies");
|
|
3909
|
-
var
|
|
4106
|
+
var import_logger5 = require("@tradejs/infra/logger");
|
|
3910
4107
|
var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
|
|
3911
4108
|
var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
|
|
3912
4109
|
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
@@ -3944,7 +4141,7 @@ var asInt = (value, fallback) => {
|
|
|
3944
4141
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
3945
4142
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
3946
4143
|
};
|
|
3947
|
-
var
|
|
4144
|
+
var toFiniteNumberOrNull3 = (value) => {
|
|
3948
4145
|
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
3949
4146
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3950
4147
|
};
|
|
@@ -4178,12 +4375,12 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4178
4375
|
const ethRow = references.get("ETHUSDT") ?? null;
|
|
4179
4376
|
const previousBtcRow = previousReferences.get("BTCUSDT") ?? null;
|
|
4180
4377
|
const previousEthRow = previousReferences.get("ETHUSDT") ?? null;
|
|
4181
|
-
const btcMarketCapUsd =
|
|
4182
|
-
const ethMarketCapUsd =
|
|
4183
|
-
const previousBtcMarketCapUsd =
|
|
4378
|
+
const btcMarketCapUsd = toFiniteNumberOrNull3(btcRow?.marketCapUsd);
|
|
4379
|
+
const ethMarketCapUsd = toFiniteNumberOrNull3(ethRow?.marketCapUsd);
|
|
4380
|
+
const previousBtcMarketCapUsd = toFiniteNumberOrNull3(
|
|
4184
4381
|
previousBtcRow?.marketCapUsd
|
|
4185
4382
|
);
|
|
4186
|
-
const previousEthMarketCapUsd =
|
|
4383
|
+
const previousEthMarketCapUsd = toFiniteNumberOrNull3(
|
|
4187
4384
|
previousEthRow?.marketCapUsd
|
|
4188
4385
|
);
|
|
4189
4386
|
const ethBtcMarketCapRatio = safeDivide(ethMarketCapUsd, btcMarketCapUsd);
|
|
@@ -4192,16 +4389,16 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4192
4389
|
previousBtcMarketCapUsd
|
|
4193
4390
|
);
|
|
4194
4391
|
const ethBtcMarketCapRatioChange24hPct = ethBtcMarketCapRatio != null && previousEthBtcMarketCapRatio != null && previousEthBtcMarketCapRatio > 0 ? (ethBtcMarketCapRatio - previousEthBtcMarketCapRatio) / previousEthBtcMarketCapRatio : null;
|
|
4195
|
-
const btcVolumeUsd =
|
|
4196
|
-
const ethVolumeUsd =
|
|
4392
|
+
const btcVolumeUsd = toFiniteNumberOrNull3(btcRow?.volumeUsd);
|
|
4393
|
+
const ethVolumeUsd = toFiniteNumberOrNull3(ethRow?.volumeUsd);
|
|
4197
4394
|
const referenceStale = btcRow?.stale === true || ethRow?.stale === true || !btcRow || !ethRow;
|
|
4198
|
-
const btcDominanceChange24hPct =
|
|
4395
|
+
const btcDominanceChange24hPct = toFiniteNumberOrNull3(
|
|
4199
4396
|
globalRow?.btcDominanceChange24hPct
|
|
4200
4397
|
);
|
|
4201
|
-
const altMarketCapChange24hPct =
|
|
4398
|
+
const altMarketCapChange24hPct = toFiniteNumberOrNull3(
|
|
4202
4399
|
globalRow?.altMarketCapChange24hPct
|
|
4203
4400
|
);
|
|
4204
|
-
const altVolumeChange24hPct =
|
|
4401
|
+
const altVolumeChange24hPct = toFiniteNumberOrNull3(
|
|
4205
4402
|
globalRow?.altVolumeChange24hPct
|
|
4206
4403
|
);
|
|
4207
4404
|
const altLiquidityRegime = globalRow ? toAltLiquidityRegime({
|
|
@@ -4212,19 +4409,19 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4212
4409
|
}) : "unknown";
|
|
4213
4410
|
const exchangeLiquidityRegime = exchangeLiquidityRow ? toExchangeLiquidityRegime({
|
|
4214
4411
|
stale: exchangeLiquidityRow.stale,
|
|
4215
|
-
totalVolumeChange24hPct:
|
|
4412
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4216
4413
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4217
4414
|
),
|
|
4218
4415
|
fallback: exchangeLiquidityRow.liquidityRegime ?? "unknown"
|
|
4219
4416
|
}) : "unknown";
|
|
4220
4417
|
const cmc100Row = indexRows.get("cmc100") ?? null;
|
|
4221
4418
|
const cmc20Row = indexRows.get("cmc20") ?? null;
|
|
4222
|
-
const cmc100Value =
|
|
4223
|
-
const cmc20Value =
|
|
4224
|
-
const cmc100Change24hPct =
|
|
4419
|
+
const cmc100Value = toFiniteNumberOrNull3(cmc100Row?.value);
|
|
4420
|
+
const cmc20Value = toFiniteNumberOrNull3(cmc20Row?.value);
|
|
4421
|
+
const cmc100Change24hPct = toFiniteNumberOrNull3(
|
|
4225
4422
|
cmc100Row?.valueChange24hPct
|
|
4226
4423
|
);
|
|
4227
|
-
const cmc20Change24hPct =
|
|
4424
|
+
const cmc20Change24hPct = toFiniteNumberOrNull3(cmc20Row?.valueChange24hPct);
|
|
4228
4425
|
const cmc20ToCmc100Ratio = safeDivide(cmc20Value, cmc100Value);
|
|
4229
4426
|
const cmc20ToCmc100RatioChange24hPct = cmc20Change24hPct != null && cmc100Change24hPct != null ? (1 + cmc20Change24hPct) / (1 + cmc100Change24hPct) - 1 : null;
|
|
4230
4427
|
const indexStale = cmc100Row?.stale === true || cmc20Row?.stale === true || !cmc100Row || !cmc20Row;
|
|
@@ -4248,41 +4445,41 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4248
4445
|
asOfTs: globalRow.ts.getTime(),
|
|
4249
4446
|
ageMs: globalRow.ageMs,
|
|
4250
4447
|
stale: globalRow.stale,
|
|
4251
|
-
totalMarketCapUsd:
|
|
4448
|
+
totalMarketCapUsd: toFiniteNumberOrNull3(
|
|
4252
4449
|
globalRow.totalMarketCapUsd
|
|
4253
4450
|
),
|
|
4254
|
-
totalVolumeUsd:
|
|
4451
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4255
4452
|
globalRow.totalVolumeUsd
|
|
4256
4453
|
),
|
|
4257
|
-
totalVolumeReportedUsd:
|
|
4454
|
+
totalVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4258
4455
|
globalRow.totalVolumeReportedUsd
|
|
4259
4456
|
),
|
|
4260
|
-
altMarketCapUsd:
|
|
4457
|
+
altMarketCapUsd: toFiniteNumberOrNull3(
|
|
4261
4458
|
globalRow.altMarketCapUsd
|
|
4262
4459
|
),
|
|
4263
|
-
altVolumeUsd:
|
|
4264
|
-
altVolumeReportedUsd:
|
|
4460
|
+
altVolumeUsd: toFiniteNumberOrNull3(globalRow.altVolumeUsd),
|
|
4461
|
+
altVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4265
4462
|
globalRow.altVolumeReportedUsd
|
|
4266
4463
|
),
|
|
4267
|
-
btcDominancePct:
|
|
4464
|
+
btcDominancePct: toFiniteNumberOrNull3(
|
|
4268
4465
|
globalRow.btcDominancePct
|
|
4269
4466
|
),
|
|
4270
|
-
ethDominancePct:
|
|
4467
|
+
ethDominancePct: toFiniteNumberOrNull3(
|
|
4271
4468
|
globalRow.ethDominancePct
|
|
4272
4469
|
),
|
|
4273
4470
|
btcDominanceChange24hPct,
|
|
4274
|
-
ethDominanceChange24hPct:
|
|
4471
|
+
ethDominanceChange24hPct: toFiniteNumberOrNull3(
|
|
4275
4472
|
globalRow.ethDominanceChange24hPct
|
|
4276
4473
|
),
|
|
4277
4474
|
altMarketCapChange24hPct,
|
|
4278
4475
|
altVolumeChange24hPct,
|
|
4279
|
-
activeCryptocurrencies:
|
|
4476
|
+
activeCryptocurrencies: toFiniteNumberOrNull3(
|
|
4280
4477
|
globalRow.activeCryptocurrencies
|
|
4281
4478
|
),
|
|
4282
|
-
activeExchanges:
|
|
4479
|
+
activeExchanges: toFiniteNumberOrNull3(
|
|
4283
4480
|
globalRow.activeExchanges
|
|
4284
4481
|
),
|
|
4285
|
-
activeMarketPairs:
|
|
4482
|
+
activeMarketPairs: toFiniteNumberOrNull3(
|
|
4286
4483
|
globalRow.activeMarketPairs
|
|
4287
4484
|
),
|
|
4288
4485
|
altLiquidityRegime
|
|
@@ -4327,22 +4524,22 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4327
4524
|
asOfTs: exchangeLiquidityRow.ts.getTime(),
|
|
4328
4525
|
ageMs: exchangeLiquidityRow.ageMs,
|
|
4329
4526
|
stale: exchangeLiquidityRow.stale,
|
|
4330
|
-
exchangesCount:
|
|
4527
|
+
exchangesCount: toFiniteNumberOrNull3(
|
|
4331
4528
|
exchangeLiquidityRow.exchangesCount
|
|
4332
4529
|
),
|
|
4333
|
-
totalVolumeUsd:
|
|
4530
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4334
4531
|
exchangeLiquidityRow.totalVolumeUsd
|
|
4335
4532
|
),
|
|
4336
|
-
totalVolumeChange24hPct:
|
|
4533
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4337
4534
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4338
4535
|
),
|
|
4339
|
-
binanceVolumeUsd:
|
|
4536
|
+
binanceVolumeUsd: toFiniteNumberOrNull3(
|
|
4340
4537
|
exchangeLiquidityRow.binanceVolumeUsd
|
|
4341
4538
|
),
|
|
4342
|
-
binanceVolumeShare:
|
|
4539
|
+
binanceVolumeShare: toFiniteNumberOrNull3(
|
|
4343
4540
|
exchangeLiquidityRow.binanceVolumeShare
|
|
4344
4541
|
),
|
|
4345
|
-
topExchangeVolumeShare:
|
|
4542
|
+
topExchangeVolumeShare: toFiniteNumberOrNull3(
|
|
4346
4543
|
exchangeLiquidityRow.topExchangeVolumeShare
|
|
4347
4544
|
),
|
|
4348
4545
|
liquidityRegime: exchangeLiquidityRegime
|
|
@@ -4355,11 +4552,11 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4355
4552
|
asOfTs: fearGreedRow.ts.getTime(),
|
|
4356
4553
|
ageMs: fearGreedRow.ageMs,
|
|
4357
4554
|
stale: fearGreedRow.stale,
|
|
4358
|
-
value:
|
|
4359
|
-
valueChange24h:
|
|
4555
|
+
value: toFiniteNumberOrNull3(fearGreedRow.value),
|
|
4556
|
+
valueChange24h: toFiniteNumberOrNull3(
|
|
4360
4557
|
fearGreedRow.valueChange24h
|
|
4361
4558
|
),
|
|
4362
|
-
valueChange7d:
|
|
4559
|
+
valueChange7d: toFiniteNumberOrNull3(
|
|
4363
4560
|
fearGreedRow.valueChange7d
|
|
4364
4561
|
),
|
|
4365
4562
|
classification: fearGreedRow.classification ?? "Unknown",
|
|
@@ -4379,13 +4576,13 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4379
4576
|
cmc100Value,
|
|
4380
4577
|
cmc100Change24hPct,
|
|
4381
4578
|
cmc100TopConstituentSymbol: cmc100Row?.topConstituentSymbol ?? null,
|
|
4382
|
-
cmc100TopConstituentWeightPct:
|
|
4579
|
+
cmc100TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4383
4580
|
cmc100Row?.topConstituentWeightPct
|
|
4384
4581
|
),
|
|
4385
4582
|
cmc20Value,
|
|
4386
4583
|
cmc20Change24hPct,
|
|
4387
4584
|
cmc20TopConstituentSymbol: cmc20Row?.topConstituentSymbol ?? null,
|
|
4388
|
-
cmc20TopConstituentWeightPct:
|
|
4585
|
+
cmc20TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4389
4586
|
cmc20Row?.topConstituentWeightPct
|
|
4390
4587
|
),
|
|
4391
4588
|
cmc20ToCmc100Ratio,
|
|
@@ -4403,7 +4600,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4403
4600
|
throw error;
|
|
4404
4601
|
}
|
|
4405
4602
|
coinMarketCapContextUnavailable = true;
|
|
4406
|
-
|
|
4603
|
+
import_logger5.logger.warn(
|
|
4407
4604
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
4408
4605
|
String(error)
|
|
4409
4606
|
);
|
|
@@ -4417,7 +4614,7 @@ var import_data2 = require("@tradejs/core/data");
|
|
|
4417
4614
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
4418
4615
|
var import_constants2 = require("@tradejs/core/constants");
|
|
4419
4616
|
var import_derivatives = require("@tradejs/infra/timescale/derivatives");
|
|
4420
|
-
var
|
|
4617
|
+
var import_logger6 = require("@tradejs/infra/logger");
|
|
4421
4618
|
var STORED_INTERVALS = ["15m", "1h"];
|
|
4422
4619
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
4423
4620
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
@@ -4472,7 +4669,7 @@ var resolvePrimaryReferenceSymbol2 = () => PRIMARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
|
4472
4669
|
var resolveSecondaryReferenceSymbol = () => SECONDARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
4473
4670
|
var getPrimaryIntervalContext = (context) => context?.intervals["15m"] ?? context?.intervals["1h"] ?? null;
|
|
4474
4671
|
var hasDerivativesSymbolData = (context) => Object.keys(context.intervals).length > 0 && !context.summary.riskFlags.includes("missing_derivatives");
|
|
4475
|
-
var
|
|
4672
|
+
var toFiniteNumberOrNull4 = (value) => {
|
|
4476
4673
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4477
4674
|
if (typeof value === "string" && value.trim()) {
|
|
4478
4675
|
const parsed = Number(value);
|
|
@@ -4486,8 +4683,8 @@ var roundNullable = (value, digits = 4) => {
|
|
|
4486
4683
|
return Math.round(value * multiplier) / multiplier;
|
|
4487
4684
|
};
|
|
4488
4685
|
var deltaNullable = (targetValue, referenceValue) => {
|
|
4489
|
-
const target =
|
|
4490
|
-
const reference =
|
|
4686
|
+
const target = toFiniteNumberOrNull4(targetValue);
|
|
4687
|
+
const reference = toFiniteNumberOrNull4(referenceValue);
|
|
4491
4688
|
return target == null || reference == null ? null : roundNullable(target - reference);
|
|
4492
4689
|
};
|
|
4493
4690
|
var buildTargetDerivedContext = (params) => {
|
|
@@ -4649,7 +4846,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4649
4846
|
throw error;
|
|
4650
4847
|
}
|
|
4651
4848
|
derivativesContextUnavailable = true;
|
|
4652
|
-
|
|
4849
|
+
import_logger6.logger.warn(
|
|
4653
4850
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
4654
4851
|
String(error)
|
|
4655
4852
|
);
|
|
@@ -4661,7 +4858,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4661
4858
|
var import_data3 = require("@tradejs/core/data");
|
|
4662
4859
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
4663
4860
|
var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
|
|
4664
|
-
var
|
|
4861
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
4665
4862
|
|
|
4666
4863
|
// src/hyperliquidWhaleUniverse.ts
|
|
4667
4864
|
var import_node_crypto3 = require("crypto");
|
|
@@ -5181,7 +5378,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
5181
5378
|
throw error;
|
|
5182
5379
|
}
|
|
5183
5380
|
hyperliquidWhaleContextUnavailable = true;
|
|
5184
|
-
|
|
5381
|
+
import_logger7.logger.warn(
|
|
5185
5382
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
5186
5383
|
String(error)
|
|
5187
5384
|
);
|
|
@@ -5264,7 +5461,7 @@ var runMarketContextStage = async ({
|
|
|
5264
5461
|
elapsedMs: Date.now() - startedAt
|
|
5265
5462
|
};
|
|
5266
5463
|
if (status === "timed_out") {
|
|
5267
|
-
|
|
5464
|
+
import_logger8.logger.warn(
|
|
5268
5465
|
"Market context stage timed out: %s after %sms",
|
|
5269
5466
|
stage,
|
|
5270
5467
|
result.elapsedMs
|
|
@@ -5454,79 +5651,10 @@ var enrichSignalWithAi = async ({
|
|
|
5454
5651
|
signal.aiAnalysis = analysis;
|
|
5455
5652
|
return resolveAiQuality(analysis, direction);
|
|
5456
5653
|
} catch (err) {
|
|
5457
|
-
|
|
5654
|
+
import_logger9.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
|
|
5458
5655
|
}
|
|
5459
5656
|
return void 0;
|
|
5460
5657
|
};
|
|
5461
|
-
var toFiniteNumberOrNull4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5462
|
-
var getOrderArrivalSnapshot = async ({
|
|
5463
|
-
connector,
|
|
5464
|
-
symbol
|
|
5465
|
-
}) => {
|
|
5466
|
-
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
5467
|
-
return {
|
|
5468
|
-
arrivalSnapshotTime: Date.now(),
|
|
5469
|
-
arrivalSource: "unavailable",
|
|
5470
|
-
bid: null,
|
|
5471
|
-
ask: null,
|
|
5472
|
-
arrivalMid: null,
|
|
5473
|
-
spreadBps: null
|
|
5474
|
-
};
|
|
5475
|
-
}
|
|
5476
|
-
try {
|
|
5477
|
-
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
5478
|
-
const arrivalSnapshotTime = toFiniteNumberOrNull4(ticker?.timestamp);
|
|
5479
|
-
const bid = toFiniteNumberOrNull4(ticker?.bidPrice);
|
|
5480
|
-
const ask = toFiniteNumberOrNull4(ticker?.askPrice);
|
|
5481
|
-
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
5482
|
-
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
5483
|
-
return {
|
|
5484
|
-
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
5485
|
-
arrivalSource: "top_of_book",
|
|
5486
|
-
bid,
|
|
5487
|
-
ask,
|
|
5488
|
-
arrivalMid,
|
|
5489
|
-
spreadBps
|
|
5490
|
-
};
|
|
5491
|
-
} catch (error) {
|
|
5492
|
-
import_logger8.logger.warn(
|
|
5493
|
-
"runtime order arrival snapshot failed: %s %s",
|
|
5494
|
-
symbol,
|
|
5495
|
-
error?.message || String(error)
|
|
5496
|
-
);
|
|
5497
|
-
return {
|
|
5498
|
-
arrivalSnapshotTime: Date.now(),
|
|
5499
|
-
arrivalSource: "top_of_book_error",
|
|
5500
|
-
bid: null,
|
|
5501
|
-
ask: null,
|
|
5502
|
-
arrivalMid: null,
|
|
5503
|
-
spreadBps: null
|
|
5504
|
-
};
|
|
5505
|
-
}
|
|
5506
|
-
};
|
|
5507
|
-
var validateEntryProtectionAtArrival = ({
|
|
5508
|
-
direction,
|
|
5509
|
-
signalPrice,
|
|
5510
|
-
bid,
|
|
5511
|
-
ask,
|
|
5512
|
-
arrivalMid,
|
|
5513
|
-
takeProfits,
|
|
5514
|
-
stopLossPrice
|
|
5515
|
-
}) => {
|
|
5516
|
-
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
5517
|
-
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
5518
|
-
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
5519
|
-
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
5520
|
-
}
|
|
5521
|
-
for (const takeProfit of takeProfits) {
|
|
5522
|
-
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
5523
|
-
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
5524
|
-
}
|
|
5525
|
-
}
|
|
5526
|
-
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
5527
|
-
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
5528
|
-
}
|
|
5529
|
-
};
|
|
5530
5658
|
var resolveRuntimeTelemetryQuality = ({
|
|
5531
5659
|
signalClosePrice,
|
|
5532
5660
|
arrivalMid,
|
|
@@ -5603,7 +5731,8 @@ var executeEntryOrder = async ({
|
|
|
5603
5731
|
signal,
|
|
5604
5732
|
beforePlaceOrder,
|
|
5605
5733
|
recordRuntimeTrade = true,
|
|
5606
|
-
leverage
|
|
5734
|
+
leverage,
|
|
5735
|
+
executionLimits
|
|
5607
5736
|
}) => {
|
|
5608
5737
|
await beforePlaceOrder?.();
|
|
5609
5738
|
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
@@ -5614,23 +5743,57 @@ var executeEntryOrder = async ({
|
|
|
5614
5743
|
signal.orderQty = qty;
|
|
5615
5744
|
signal.orderValue = qty * currentPrice;
|
|
5616
5745
|
signal.orderFailureReason = void 0;
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5746
|
+
let arrivalSnapshot = {
|
|
5747
|
+
arrivalSnapshotTime: Date.now(),
|
|
5748
|
+
arrivalSource: "unavailable",
|
|
5749
|
+
bid: null,
|
|
5750
|
+
ask: null,
|
|
5751
|
+
arrivalMid: null,
|
|
5752
|
+
spreadBps: null
|
|
5753
|
+
};
|
|
5754
|
+
let orderSubmitTime = Date.now();
|
|
5755
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
5756
|
+
connector,
|
|
5757
|
+
symbol,
|
|
5758
|
+
direction,
|
|
5759
|
+
takeProfits,
|
|
5760
|
+
stopLossPrice,
|
|
5761
|
+
limits: executionLimits,
|
|
5762
|
+
onValidated: (snapshot2, economics2) => {
|
|
5763
|
+
arrivalSnapshot = snapshot2;
|
|
5764
|
+
orderSubmitTime = Date.now();
|
|
5765
|
+
if (executionLimits?.maxLossValue != null) {
|
|
5766
|
+
signal.riskDecision = {
|
|
5767
|
+
stage: "order_plan",
|
|
5768
|
+
status: economics2.riskExceeded ? "warning" : "approved",
|
|
5769
|
+
reason: economics2.riskExceeded ? "ENTRY_RISK_EXCEEDS_MAX_LOSS_AT_SUBMISSION" : "PLANNED_LOSS_WITHIN_MAX_LOSS_VALUE",
|
|
5770
|
+
plannedLossValue: economics2.plannedLossValue,
|
|
5771
|
+
maxLossValue: executionLimits.maxLossValue,
|
|
5772
|
+
limitUtilization: economics2.plannedLossValue / executionLimits.maxLossValue,
|
|
5773
|
+
enforced: false
|
|
5774
|
+
};
|
|
5775
|
+
}
|
|
5776
|
+
}
|
|
5777
|
+
});
|
|
5778
|
+
if (!beforeSubmit) {
|
|
5779
|
+
arrivalSnapshot = await getOrderArrivalSnapshot({ connector, symbol });
|
|
5780
|
+
try {
|
|
5781
|
+
validateEntryProtectionAtArrival({
|
|
5782
|
+
direction,
|
|
5783
|
+
signalPrice: currentPrice,
|
|
5784
|
+
bid: arrivalSnapshot.bid,
|
|
5785
|
+
ask: arrivalSnapshot.ask,
|
|
5786
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
5787
|
+
takeProfits,
|
|
5788
|
+
stopLossPrice
|
|
5789
|
+
});
|
|
5790
|
+
} catch (error) {
|
|
5791
|
+
signal.orderStatus = "failed";
|
|
5792
|
+
signal.orderFailureReason = error.message;
|
|
5793
|
+
throw error;
|
|
5794
|
+
}
|
|
5795
|
+
orderSubmitTime = Date.now();
|
|
5632
5796
|
}
|
|
5633
|
-
const orderSubmitTime = Date.now();
|
|
5634
5797
|
const orderPlaced = await connector.placeOrder({
|
|
5635
5798
|
symbol,
|
|
5636
5799
|
qty,
|
|
@@ -5641,7 +5804,8 @@ var executeEntryOrder = async ({
|
|
|
5641
5804
|
direction,
|
|
5642
5805
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
5643
5806
|
orderId,
|
|
5644
|
-
signal
|
|
5807
|
+
signal,
|
|
5808
|
+
...beforeSubmit ? { beforeSubmit } : {}
|
|
5645
5809
|
});
|
|
5646
5810
|
const orderAckTime = Date.now();
|
|
5647
5811
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
@@ -6470,7 +6634,7 @@ var canUseSharedReplayState = ({
|
|
|
6470
6634
|
}) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
|
|
6471
6635
|
|
|
6472
6636
|
// src/strategy/runtimeExecution.ts
|
|
6473
|
-
var
|
|
6637
|
+
var import_logger10 = require("@tradejs/infra/logger");
|
|
6474
6638
|
var import_types = require("@tradejs/types");
|
|
6475
6639
|
var buildExitOrderSignal = ({
|
|
6476
6640
|
strategyName,
|
|
@@ -6522,7 +6686,7 @@ var handleExitDecision = async ({
|
|
|
6522
6686
|
deploymentId: connector.deploymentId
|
|
6523
6687
|
});
|
|
6524
6688
|
if (!activeTrade) {
|
|
6525
|
-
|
|
6689
|
+
import_logger10.logger.warn(
|
|
6526
6690
|
"[%s] blocked closePosition for untracked runtime position: %s",
|
|
6527
6691
|
strategyName ?? "unknown",
|
|
6528
6692
|
symbol
|
|
@@ -6530,7 +6694,7 @@ var handleExitDecision = async ({
|
|
|
6530
6694
|
return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
|
|
6531
6695
|
}
|
|
6532
6696
|
if (!strategyName || activeTrade.strategy !== strategyName) {
|
|
6533
|
-
|
|
6697
|
+
import_logger10.logger.warn(
|
|
6534
6698
|
"[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
|
|
6535
6699
|
strategyName ?? "unknown",
|
|
6536
6700
|
symbol,
|
|
@@ -6583,7 +6747,7 @@ var handleExitDecision = async ({
|
|
|
6583
6747
|
exitType: closedTrade?.exitType ?? "exit"
|
|
6584
6748
|
});
|
|
6585
6749
|
} catch (notificationError) {
|
|
6586
|
-
|
|
6750
|
+
import_logger10.logger.error(
|
|
6587
6751
|
"runtime close notification error: %s %s",
|
|
6588
6752
|
symbol,
|
|
6589
6753
|
notificationError
|
|
@@ -6597,7 +6761,7 @@ var handleExitDecision = async ({
|
|
|
6597
6761
|
decision,
|
|
6598
6762
|
market
|
|
6599
6763
|
});
|
|
6600
|
-
|
|
6764
|
+
import_logger10.logger.error("close order error: %s %s", symbol, err);
|
|
6601
6765
|
return "ORDER_ERROR";
|
|
6602
6766
|
}
|
|
6603
6767
|
return decision.code;
|
|
@@ -6624,7 +6788,7 @@ var handleProtectDecision = async ({
|
|
|
6624
6788
|
decision,
|
|
6625
6789
|
market
|
|
6626
6790
|
});
|
|
6627
|
-
|
|
6791
|
+
import_logger10.logger.error("protect position error: %s %s", symbol, err);
|
|
6628
6792
|
return "ORDER_ERROR";
|
|
6629
6793
|
}
|
|
6630
6794
|
return decision.code;
|
|
@@ -6690,7 +6854,11 @@ var executeEntryDecision = async ({
|
|
|
6690
6854
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
6691
6855
|
signal,
|
|
6692
6856
|
beforePlaceOrder,
|
|
6693
|
-
recordRuntimeTrade: recordRuntimeJournal
|
|
6857
|
+
recordRuntimeTrade: recordRuntimeJournal,
|
|
6858
|
+
executionLimits: resolveEntryExecutionLimits(
|
|
6859
|
+
hookCtx.strategyConfig,
|
|
6860
|
+
decision.entryContext.direction
|
|
6861
|
+
)
|
|
6694
6862
|
});
|
|
6695
6863
|
await invokeStageHooks(
|
|
6696
6864
|
"afterPlaceOrder",
|
|
@@ -6712,19 +6880,32 @@ var executeEntryDecision = async ({
|
|
|
6712
6880
|
return signal;
|
|
6713
6881
|
}
|
|
6714
6882
|
await beforePlaceOrder();
|
|
6715
|
-
const
|
|
6883
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
6716
6884
|
connector,
|
|
6717
|
-
symbol
|
|
6718
|
-
});
|
|
6719
|
-
validateEntryProtectionAtArrival({
|
|
6885
|
+
symbol,
|
|
6720
6886
|
direction: decision.entryContext.direction,
|
|
6721
|
-
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6722
|
-
bid: arrivalSnapshot.bid,
|
|
6723
|
-
ask: arrivalSnapshot.ask,
|
|
6724
|
-
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6725
6887
|
takeProfits: decision.orderPlan.takeProfits,
|
|
6726
|
-
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6888
|
+
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
6889
|
+
limits: resolveEntryExecutionLimits(
|
|
6890
|
+
hookCtx.strategyConfig,
|
|
6891
|
+
decision.entryContext.direction
|
|
6892
|
+
)
|
|
6727
6893
|
});
|
|
6894
|
+
if (!beforeSubmit) {
|
|
6895
|
+
const arrivalSnapshot = await getOrderArrivalSnapshot({
|
|
6896
|
+
connector,
|
|
6897
|
+
symbol
|
|
6898
|
+
});
|
|
6899
|
+
validateEntryProtectionAtArrival({
|
|
6900
|
+
direction: decision.entryContext.direction,
|
|
6901
|
+
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6902
|
+
bid: arrivalSnapshot.bid,
|
|
6903
|
+
ask: arrivalSnapshot.ask,
|
|
6904
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6905
|
+
takeProfits: decision.orderPlan.takeProfits,
|
|
6906
|
+
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
6907
|
+
});
|
|
6908
|
+
}
|
|
6728
6909
|
const orderPlaced = await connector.placeOrder({
|
|
6729
6910
|
symbol,
|
|
6730
6911
|
qty: decision.orderPlan.qty,
|
|
@@ -6732,6 +6913,7 @@ var executeEntryDecision = async ({
|
|
|
6732
6913
|
timestamp: decision.entryContext.timestamp,
|
|
6733
6914
|
direction: decision.entryContext.direction,
|
|
6734
6915
|
positionIntent: decision.orderPlan.positionIntent,
|
|
6916
|
+
...beforeSubmit ? { beforeSubmit } : {},
|
|
6735
6917
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
6736
6918
|
});
|
|
6737
6919
|
if (!orderPlaced) {
|
|
@@ -6773,6 +6955,23 @@ var executeEntryDecision = async ({
|
|
|
6773
6955
|
{ decision, entry, market }
|
|
6774
6956
|
);
|
|
6775
6957
|
} catch (err) {
|
|
6958
|
+
if (err instanceof EntrySubmissionValidationError) {
|
|
6959
|
+
if (signal) {
|
|
6960
|
+
signal.orderStatus = "skipped";
|
|
6961
|
+
signal.orderSkipReason = err.message;
|
|
6962
|
+
signal.allocatorDecision = {
|
|
6963
|
+
stage: "runtime_admission",
|
|
6964
|
+
status: "rejected",
|
|
6965
|
+
reason: err.message
|
|
6966
|
+
};
|
|
6967
|
+
}
|
|
6968
|
+
import_logger10.logger.warn(
|
|
6969
|
+
"entry rejected before submission: %s %s",
|
|
6970
|
+
symbol,
|
|
6971
|
+
err.message
|
|
6972
|
+
);
|
|
6973
|
+
return signal ?? err.message;
|
|
6974
|
+
}
|
|
6776
6975
|
if (signal) {
|
|
6777
6976
|
signal.orderStatus = "failed";
|
|
6778
6977
|
if (typeof signal.orderFailureReason !== "string" || !signal.orderFailureReason.trim()) {
|
|
@@ -6787,9 +6986,9 @@ var executeEntryDecision = async ({
|
|
|
6787
6986
|
market
|
|
6788
6987
|
});
|
|
6789
6988
|
if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
|
|
6790
|
-
|
|
6989
|
+
import_logger10.logger.warn("order warning: %s %s", symbol, err);
|
|
6791
6990
|
} else {
|
|
6792
|
-
|
|
6991
|
+
import_logger10.logger.error("order error: %s %s", symbol, err);
|
|
6793
6992
|
}
|
|
6794
6993
|
return signal ?? "ORDER_ERROR";
|
|
6795
6994
|
}
|
|
@@ -6897,6 +7096,9 @@ var createStrategyRuntime = ({
|
|
|
6897
7096
|
});
|
|
6898
7097
|
const strategyPolicyProfile = getPolicyProfile();
|
|
6899
7098
|
const indicatorPeriods = (0, import_strategies6.buildDefaultIndicatorPeriods)(config);
|
|
7099
|
+
const strategyConfig = { ...config };
|
|
7100
|
+
delete strategyConfig.RECORD_RUNTIME_TRADES;
|
|
7101
|
+
delete strategyConfig.SIMULATE_ORDERS;
|
|
6900
7102
|
const hookBase = {
|
|
6901
7103
|
connector,
|
|
6902
7104
|
strategyName,
|
|
@@ -6907,7 +7109,7 @@ var createStrategyRuntime = ({
|
|
|
6907
7109
|
accountId,
|
|
6908
7110
|
deploymentId,
|
|
6909
7111
|
policyProfileId: strategyPolicyProfile?.id ?? requestedPolicyProfileId,
|
|
6910
|
-
strategyConfig
|
|
7112
|
+
strategyConfig,
|
|
6911
7113
|
env,
|
|
6912
7114
|
isConfigFromBacktest
|
|
6913
7115
|
};
|
|
@@ -6954,7 +7156,7 @@ var createStrategyRuntime = ({
|
|
|
6954
7156
|
try {
|
|
6955
7157
|
await projectHook(errorParams);
|
|
6956
7158
|
} catch (hookError) {
|
|
6957
|
-
|
|
7159
|
+
import_logger11.logger.error(
|
|
6958
7160
|
"project hook onRuntimeError failed: %s %s",
|
|
6959
7161
|
strategyName,
|
|
6960
7162
|
hookError
|
|
@@ -6968,21 +7170,21 @@ var createStrategyRuntime = ({
|
|
|
6968
7170
|
try {
|
|
6969
7171
|
await onRuntimeError(errorParams);
|
|
6970
7172
|
} catch (hookError) {
|
|
6971
|
-
|
|
7173
|
+
import_logger11.logger.error(
|
|
6972
7174
|
"runtime hook onRuntimeError failed: %s %s",
|
|
6973
7175
|
strategyName,
|
|
6974
7176
|
hookError
|
|
6975
7177
|
);
|
|
6976
7178
|
}
|
|
6977
7179
|
};
|
|
6978
|
-
const invokeHook = async (stage, hook, params, errorContext = {}) => {
|
|
7180
|
+
const invokeHook = async (stage, hook, params, errorContext = {}, failureResult) => {
|
|
6979
7181
|
if (!hook) {
|
|
6980
7182
|
return void 0;
|
|
6981
7183
|
}
|
|
6982
7184
|
try {
|
|
6983
7185
|
return await hook(params);
|
|
6984
7186
|
} catch (error) {
|
|
6985
|
-
|
|
7187
|
+
import_logger11.logger.error(
|
|
6986
7188
|
'strategy hook "%s" failed for %s: %s',
|
|
6987
7189
|
stage,
|
|
6988
7190
|
strategyName,
|
|
@@ -6995,17 +7197,18 @@ var createStrategyRuntime = ({
|
|
|
6995
7197
|
entry: errorContext.entry,
|
|
6996
7198
|
market: errorContext.market
|
|
6997
7199
|
});
|
|
6998
|
-
return
|
|
7200
|
+
return failureResult;
|
|
6999
7201
|
}
|
|
7000
7202
|
};
|
|
7001
|
-
const invokeProjectHooks = async (stage, params, errorContext = {}) => {
|
|
7203
|
+
const invokeProjectHooks = async (stage, params, errorContext = {}, failureResult) => {
|
|
7002
7204
|
const results = [];
|
|
7003
7205
|
for (const hook of getProjectHookList(stage)) {
|
|
7004
7206
|
const result = await invokeHook(
|
|
7005
7207
|
stage,
|
|
7006
7208
|
hook,
|
|
7007
7209
|
params,
|
|
7008
|
-
errorContext
|
|
7210
|
+
errorContext,
|
|
7211
|
+
failureResult
|
|
7009
7212
|
);
|
|
7010
7213
|
if (result !== void 0) {
|
|
7011
7214
|
results.push(result);
|
|
@@ -7020,10 +7223,12 @@ var createStrategyRuntime = ({
|
|
|
7020
7223
|
return invokeHook(stage, hook, params, errorContext);
|
|
7021
7224
|
};
|
|
7022
7225
|
const invokeGateHooks = async (stage, hook, params, errorContext = {}) => {
|
|
7226
|
+
const failureResult = stage === "beforeEntryGate" ? { allow: false, reason: "ERROR" } : void 0;
|
|
7023
7227
|
const projectResults = await invokeProjectHooks(
|
|
7024
7228
|
stage,
|
|
7025
7229
|
params,
|
|
7026
|
-
errorContext
|
|
7230
|
+
errorContext,
|
|
7231
|
+
failureResult
|
|
7027
7232
|
);
|
|
7028
7233
|
const projectBlock = projectResults.find(
|
|
7029
7234
|
(result) => result?.allow === false
|
|
@@ -7035,7 +7240,8 @@ var createStrategyRuntime = ({
|
|
|
7035
7240
|
stage,
|
|
7036
7241
|
hook,
|
|
7037
7242
|
params,
|
|
7038
|
-
errorContext
|
|
7243
|
+
errorContext,
|
|
7244
|
+
failureResult
|
|
7039
7245
|
);
|
|
7040
7246
|
};
|
|
7041
7247
|
const applyProjectAfterCoreDecisionHooks = async ({
|
|
@@ -7181,11 +7387,8 @@ var createStrategyRuntime = ({
|
|
|
7181
7387
|
return enrichedBaseContext;
|
|
7182
7388
|
}
|
|
7183
7389
|
});
|
|
7184
|
-
const coreConfig = { ...config };
|
|
7185
|
-
delete coreConfig.RECORD_RUNTIME_TRADES;
|
|
7186
|
-
delete coreConfig.SIMULATE_ORDERS;
|
|
7187
7390
|
const core = await createCore({
|
|
7188
|
-
config:
|
|
7391
|
+
config: strategyConfig,
|
|
7189
7392
|
data,
|
|
7190
7393
|
strategyApi,
|
|
7191
7394
|
indicatorsState
|