@tradejs/node 3.1.29-beta.287 → 3.1.29-beta.289
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 +434 -224
- package/dist/backtest.mjs +10 -5
- package/dist/{chunk-KOV3U6ZZ.mjs → chunk-KYGJBMKE.mjs} +407 -202
- package/dist/diagnostics.js +408 -203
- package/dist/diagnostics.mjs +1 -1
- package/dist/mcp.d.mts +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +423 -218
- package/dist/mcp.mjs +1 -1
- package/dist/registry.js +408 -203
- package/dist/registry.mjs +1 -1
- package/dist/runtimeDashboard.js +410 -205
- package/dist/runtimeDashboard.mjs +1 -1
- package/dist/runtimeStrategies.js +408 -203
- package/dist/runtimeStrategies.mjs +1 -1
- package/dist/strategies.d.mts +32 -22
- package/dist/strategies.d.ts +32 -22
- package/dist/strategies.js +416 -211
- package/dist/strategies.mjs +1 -1
- package/package.json +5 -5
package/dist/strategies.js
CHANGED
|
@@ -2909,13 +2909,213 @@ var assessSignalWithJev = async ({
|
|
|
2909
2909
|
// src/strategyRuntime.ts
|
|
2910
2910
|
var import_constants5 = require("@tradejs/core/constants");
|
|
2911
2911
|
var import_strategies6 = require("@tradejs/core/strategies");
|
|
2912
|
-
var
|
|
2912
|
+
var import_logger11 = require("@tradejs/infra/logger");
|
|
2913
2913
|
|
|
2914
2914
|
// src/strategyHelpers/runtime.ts
|
|
2915
|
-
var
|
|
2915
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
2916
2916
|
var import_constants3 = require("@tradejs/core/constants");
|
|
2917
2917
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
2918
2918
|
|
|
2919
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
2920
|
+
var import_logger2 = require("@tradejs/infra/logger");
|
|
2921
|
+
|
|
2922
|
+
// src/strategy/entryExecutionValidation.ts
|
|
2923
|
+
var EntrySubmissionValidationError = class extends Error {
|
|
2924
|
+
constructor() {
|
|
2925
|
+
super(...arguments);
|
|
2926
|
+
this.name = "EntrySubmissionValidationError";
|
|
2927
|
+
}
|
|
2928
|
+
};
|
|
2929
|
+
var resolveEntryExecutionLimits = (config, direction) => {
|
|
2930
|
+
const side = config[direction];
|
|
2931
|
+
const minimum = side && typeof side === "object" && "minRiskRatio" in side ? side.minRiskRatio : void 0;
|
|
2932
|
+
const maximum = config.MAX_LOSS_VALUE;
|
|
2933
|
+
if (minimum == null && maximum == null) return void 0;
|
|
2934
|
+
const minimumNetRiskRatio = minimum == null ? void 0 : Number(minimum);
|
|
2935
|
+
const maxLossValue = maximum == null ? void 0 : Number(maximum);
|
|
2936
|
+
const feeRate = Number(config.RISK_FEE_RATE ?? 0);
|
|
2937
|
+
const slippage = Number(config.RISK_SLIPPAGE_BPS ?? 0);
|
|
2938
|
+
const impact = Number(config.RISK_MARKET_IMPACT_BPS ?? 0);
|
|
2939
|
+
const slippageBps = slippage + impact;
|
|
2940
|
+
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)
|
|
2941
|
+
throw new Error("INVALID_ENTRY_EXECUTION_LIMITS");
|
|
2942
|
+
return { minimumNetRiskRatio, maxLossValue, feeRate, slippageBps };
|
|
2943
|
+
};
|
|
2944
|
+
var validateEntryExecution = ({
|
|
2945
|
+
direction,
|
|
2946
|
+
price,
|
|
2947
|
+
qty,
|
|
2948
|
+
stopLossPrice,
|
|
2949
|
+
takeProfitPrice,
|
|
2950
|
+
limits
|
|
2951
|
+
}) => {
|
|
2952
|
+
if (!Number.isFinite(price) || price <= 0 || !Number.isFinite(qty) || qty <= 0 || stopLossPrice == null || !Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || !Number.isFinite(takeProfitPrice) || takeProfitPrice <= 0)
|
|
2953
|
+
throw new EntrySubmissionValidationError(
|
|
2954
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
2955
|
+
);
|
|
2956
|
+
const side = direction === "LONG" ? 1 : -1;
|
|
2957
|
+
if (side * (price - stopLossPrice) <= 0 || side * (takeProfitPrice - price) <= 0)
|
|
2958
|
+
throw new EntrySubmissionValidationError(
|
|
2959
|
+
"INVALID_ENTRY_PROTECTION_AT_SUBMISSION"
|
|
2960
|
+
);
|
|
2961
|
+
const slippage = limits.slippageBps / 1e4;
|
|
2962
|
+
const cost = (value, sign) => value * slippage + value * (1 + sign * slippage) * limits.feeRate;
|
|
2963
|
+
const entryCost = cost(price, side);
|
|
2964
|
+
const lossPerUnit = Math.abs(price - stopLossPrice) + entryCost + cost(stopLossPrice, -side);
|
|
2965
|
+
const rewardPerUnit = Math.max(
|
|
2966
|
+
0,
|
|
2967
|
+
Math.abs(takeProfitPrice - price) - entryCost - cost(takeProfitPrice, -side)
|
|
2968
|
+
);
|
|
2969
|
+
const netRiskRatio = rewardPerUnit / lossPerUnit;
|
|
2970
|
+
const plannedLossValue = qty * lossPerUnit;
|
|
2971
|
+
if (!Number.isFinite(netRiskRatio) || !Number.isFinite(plannedLossValue))
|
|
2972
|
+
throw new EntrySubmissionValidationError(
|
|
2973
|
+
"ENTRY_ECONOMICS_INPUTS_UNAVAILABLE"
|
|
2974
|
+
);
|
|
2975
|
+
if (limits.minimumNetRiskRatio != null && netRiskRatio <= limits.minimumNetRiskRatio)
|
|
2976
|
+
throw new EntrySubmissionValidationError(
|
|
2977
|
+
"ENTRY_RR_BELOW_MIN_AT_SUBMISSION"
|
|
2978
|
+
);
|
|
2979
|
+
if (limits.maxLossValue != null && plannedLossValue > limits.maxLossValue * (1 + 1e-9))
|
|
2980
|
+
throw new EntrySubmissionValidationError(
|
|
2981
|
+
"ENTRY_RISK_EXCEEDS_MAX_LOSS_AT_SUBMISSION"
|
|
2982
|
+
);
|
|
2983
|
+
return { netRiskRatio, plannedLossValue };
|
|
2984
|
+
};
|
|
2985
|
+
|
|
2986
|
+
// src/strategy/entrySubmissionValidation.ts
|
|
2987
|
+
var MAX_ENTRY_QUOTE_AGE_MS = 5e3;
|
|
2988
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
2989
|
+
var getOrderArrivalSnapshot = async ({
|
|
2990
|
+
connector,
|
|
2991
|
+
symbol,
|
|
2992
|
+
requireTimestamp = false
|
|
2993
|
+
}) => {
|
|
2994
|
+
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
2995
|
+
return {
|
|
2996
|
+
arrivalSnapshotTime: Date.now(),
|
|
2997
|
+
arrivalSource: "unavailable",
|
|
2998
|
+
bid: null,
|
|
2999
|
+
ask: null,
|
|
3000
|
+
arrivalMid: null,
|
|
3001
|
+
spreadBps: null
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
try {
|
|
3005
|
+
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
3006
|
+
const arrivalSnapshotTime = toFiniteNumberOrNull(ticker?.timestamp);
|
|
3007
|
+
const timestampUnavailable = requireTimestamp && arrivalSnapshotTime == null;
|
|
3008
|
+
const bid = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.bidPrice);
|
|
3009
|
+
const ask = timestampUnavailable ? null : toFiniteNumberOrNull(ticker?.askPrice);
|
|
3010
|
+
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
3011
|
+
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
3012
|
+
return {
|
|
3013
|
+
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
3014
|
+
arrivalSource: "top_of_book",
|
|
3015
|
+
bid,
|
|
3016
|
+
ask,
|
|
3017
|
+
arrivalMid,
|
|
3018
|
+
spreadBps
|
|
3019
|
+
};
|
|
3020
|
+
} catch (error) {
|
|
3021
|
+
import_logger2.logger.warn(
|
|
3022
|
+
"runtime order arrival snapshot failed: %s %s",
|
|
3023
|
+
symbol,
|
|
3024
|
+
error?.message || String(error)
|
|
3025
|
+
);
|
|
3026
|
+
return {
|
|
3027
|
+
arrivalSnapshotTime: Date.now(),
|
|
3028
|
+
arrivalSource: "top_of_book_error",
|
|
3029
|
+
bid: null,
|
|
3030
|
+
ask: null,
|
|
3031
|
+
arrivalMid: null,
|
|
3032
|
+
spreadBps: null
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
};
|
|
3036
|
+
var validateEntryProtectionAtArrival = ({
|
|
3037
|
+
direction,
|
|
3038
|
+
signalPrice,
|
|
3039
|
+
bid,
|
|
3040
|
+
ask,
|
|
3041
|
+
arrivalMid,
|
|
3042
|
+
takeProfits,
|
|
3043
|
+
stopLossPrice
|
|
3044
|
+
}) => {
|
|
3045
|
+
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
3046
|
+
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
3047
|
+
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
3048
|
+
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
3049
|
+
}
|
|
3050
|
+
for (const takeProfit of takeProfits) {
|
|
3051
|
+
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
3052
|
+
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
3056
|
+
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
3057
|
+
}
|
|
3058
|
+
};
|
|
3059
|
+
var createEntrySubmissionValidation = ({
|
|
3060
|
+
connector,
|
|
3061
|
+
symbol,
|
|
3062
|
+
direction,
|
|
3063
|
+
takeProfits,
|
|
3064
|
+
stopLossPrice,
|
|
3065
|
+
limits,
|
|
3066
|
+
onValidated
|
|
3067
|
+
}) => {
|
|
3068
|
+
if (!limits) return void 0;
|
|
3069
|
+
if (!connector.capabilities?.orderSubmissionValidation)
|
|
3070
|
+
throw new EntrySubmissionValidationError(
|
|
3071
|
+
"ENTRY_SUBMISSION_VALIDATION_UNSUPPORTED"
|
|
3072
|
+
);
|
|
3073
|
+
return async ({ qty, executionPrice }) => {
|
|
3074
|
+
const simulated = Reflect.get(connector, "__tradejsTestConnector") === true;
|
|
3075
|
+
const snapshot2 = simulated && executionPrice != null ? {
|
|
3076
|
+
arrivalSnapshotTime: Date.now(),
|
|
3077
|
+
arrivalSource: "simulation",
|
|
3078
|
+
bid: executionPrice,
|
|
3079
|
+
ask: executionPrice,
|
|
3080
|
+
arrivalMid: executionPrice,
|
|
3081
|
+
spreadBps: 0
|
|
3082
|
+
} : await getOrderArrivalSnapshot({
|
|
3083
|
+
connector,
|
|
3084
|
+
symbol,
|
|
3085
|
+
requireTimestamp: true
|
|
3086
|
+
});
|
|
3087
|
+
const age = Date.now() - snapshot2.arrivalSnapshotTime;
|
|
3088
|
+
if (snapshot2.bid == null || snapshot2.ask == null || !Number.isFinite(snapshot2.bid) || !Number.isFinite(snapshot2.ask) || snapshot2.bid <= 0 || snapshot2.ask < snapshot2.bid)
|
|
3089
|
+
throw new EntrySubmissionValidationError(
|
|
3090
|
+
"ENTRY_QUOTE_UNAVAILABLE_AT_SUBMISSION"
|
|
3091
|
+
);
|
|
3092
|
+
if (!Number.isFinite(age) || age < -MAX_ENTRY_QUOTE_AGE_MS || age > MAX_ENTRY_QUOTE_AGE_MS)
|
|
3093
|
+
throw new EntrySubmissionValidationError(
|
|
3094
|
+
"ENTRY_QUOTE_STALE_AT_SUBMISSION"
|
|
3095
|
+
);
|
|
3096
|
+
const price = direction === "LONG" ? snapshot2.ask : snapshot2.bid;
|
|
3097
|
+
validateEntryProtectionAtArrival({
|
|
3098
|
+
direction,
|
|
3099
|
+
signalPrice: price,
|
|
3100
|
+
bid: snapshot2.bid,
|
|
3101
|
+
ask: snapshot2.ask,
|
|
3102
|
+
arrivalMid: snapshot2.arrivalMid,
|
|
3103
|
+
takeProfits,
|
|
3104
|
+
stopLossPrice
|
|
3105
|
+
});
|
|
3106
|
+
const prices = takeProfits.map((tp) => tp.price);
|
|
3107
|
+
const economics2 = validateEntryExecution({
|
|
3108
|
+
direction,
|
|
3109
|
+
price,
|
|
3110
|
+
qty,
|
|
3111
|
+
stopLossPrice,
|
|
3112
|
+
takeProfitPrice: direction === "LONG" ? Math.max(...prices) : Math.min(...prices),
|
|
3113
|
+
limits
|
|
3114
|
+
});
|
|
3115
|
+
onValidated?.(snapshot2, economics2);
|
|
3116
|
+
};
|
|
3117
|
+
};
|
|
3118
|
+
|
|
2919
3119
|
// src/strategyAdapters/ml.ts
|
|
2920
3120
|
var defaultMlAdapter = {
|
|
2921
3121
|
normalizeStrategyConfig: (strategyConfig) => strategyConfig
|
|
@@ -2969,7 +3169,7 @@ var import_node_crypto = require("crypto");
|
|
|
2969
3169
|
var import_constants = require("@tradejs/core/constants");
|
|
2970
3170
|
var import_time = require("@tradejs/core/time");
|
|
2971
3171
|
var import_trade = require("@tradejs/core/trade");
|
|
2972
|
-
var
|
|
3172
|
+
var import_logger3 = require("@tradejs/infra/logger");
|
|
2973
3173
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
2974
3174
|
var now = () => Date.now();
|
|
2975
3175
|
var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
|
|
@@ -3028,7 +3228,7 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
3028
3228
|
)
|
|
3029
3229
|
]);
|
|
3030
3230
|
} catch (error) {
|
|
3031
|
-
|
|
3231
|
+
import_logger3.logger.error(
|
|
3032
3232
|
"runtime trade open journal failed: %s %s",
|
|
3033
3233
|
record.symbol,
|
|
3034
3234
|
error?.message || String(error)
|
|
@@ -3096,7 +3296,7 @@ var recordRuntimeTradeIncrease = async (params) => {
|
|
|
3096
3296
|
)
|
|
3097
3297
|
]);
|
|
3098
3298
|
} catch (error) {
|
|
3099
|
-
|
|
3299
|
+
import_logger3.logger.error(
|
|
3100
3300
|
"runtime trade increase journal failed: %s %s",
|
|
3101
3301
|
symbol,
|
|
3102
3302
|
error?.message || String(error)
|
|
@@ -3203,7 +3403,7 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3203
3403
|
)
|
|
3204
3404
|
]);
|
|
3205
3405
|
} catch (error) {
|
|
3206
|
-
|
|
3406
|
+
import_logger3.logger.error(
|
|
3207
3407
|
"runtime trade close journal failed: %s %s",
|
|
3208
3408
|
symbol,
|
|
3209
3409
|
error?.message || String(error)
|
|
@@ -3213,11 +3413,11 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
3213
3413
|
};
|
|
3214
3414
|
|
|
3215
3415
|
// src/strategyHelpers/marketContextStages.ts
|
|
3216
|
-
var
|
|
3416
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
3217
3417
|
|
|
3218
3418
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
3219
3419
|
var import_marketContext = require("@tradejs/infra/timescale/marketContext");
|
|
3220
|
-
var
|
|
3420
|
+
var import_logger4 = require("@tradejs/infra/logger");
|
|
3221
3421
|
var import_strategies = require("@tradejs/core/strategies");
|
|
3222
3422
|
|
|
3223
3423
|
// src/binanceBreadthUniverses.ts
|
|
@@ -3593,7 +3793,7 @@ var parseEnabledFlag = (value, env) => {
|
|
|
3593
3793
|
if (normalized === "live") return env !== "BACKTEST";
|
|
3594
3794
|
return false;
|
|
3595
3795
|
};
|
|
3596
|
-
var
|
|
3796
|
+
var toFiniteNumberOrNull2 = (value) => {
|
|
3597
3797
|
const numeric = typeof value === "number" ? value : Number(value);
|
|
3598
3798
|
return Number.isFinite(numeric) ? numeric : null;
|
|
3599
3799
|
};
|
|
@@ -3858,14 +4058,14 @@ var toTradeFlowContext = (row, interval) => row ? {
|
|
|
3858
4058
|
asOfTs: row.ts.getTime(),
|
|
3859
4059
|
ageMs: row.ageMs,
|
|
3860
4060
|
stale: row.stale,
|
|
3861
|
-
trades:
|
|
3862
|
-
buyPressurePct:
|
|
3863
|
-
buyBaseVolume:
|
|
3864
|
-
sellBaseVolume:
|
|
3865
|
-
buyQuoteVolume:
|
|
3866
|
-
sellQuoteVolume:
|
|
3867
|
-
netBaseDelta:
|
|
3868
|
-
netQuoteDelta:
|
|
4061
|
+
trades: toFiniteNumberOrNull2(row.trades),
|
|
4062
|
+
buyPressurePct: toFiniteNumberOrNull2(row.buyPressurePct),
|
|
4063
|
+
buyBaseVolume: toFiniteNumberOrNull2(row.buyBaseVolume),
|
|
4064
|
+
sellBaseVolume: toFiniteNumberOrNull2(row.sellBaseVolume),
|
|
4065
|
+
buyQuoteVolume: toFiniteNumberOrNull2(row.buyQuoteVolume),
|
|
4066
|
+
sellQuoteVolume: toFiniteNumberOrNull2(row.sellQuoteVolume),
|
|
4067
|
+
netBaseDelta: toFiniteNumberOrNull2(row.netBaseDelta),
|
|
4068
|
+
netQuoteDelta: toFiniteNumberOrNull2(row.netQuoteDelta)
|
|
3869
4069
|
} : null;
|
|
3870
4070
|
var getCachedReferenceRows = ({
|
|
3871
4071
|
referenceSymbols,
|
|
@@ -3954,16 +4154,16 @@ var toMarketBreadthContext = (breadth, interval) => ({
|
|
|
3954
4154
|
asOfTs: breadth.ts.getTime(),
|
|
3955
4155
|
ageMs: breadth.ageMs,
|
|
3956
4156
|
stale: breadth.stale,
|
|
3957
|
-
symbolsCount:
|
|
3958
|
-
advancers:
|
|
3959
|
-
decliners:
|
|
3960
|
-
unchanged:
|
|
3961
|
-
advanceDeclineRatio:
|
|
3962
|
-
pctAboveMa20:
|
|
3963
|
-
pctAboveMa50:
|
|
3964
|
-
equalWeightedReturn:
|
|
3965
|
-
volumeWeightedReturn:
|
|
3966
|
-
dispersion:
|
|
4157
|
+
symbolsCount: toFiniteNumberOrNull2(breadth.symbolsCount),
|
|
4158
|
+
advancers: toFiniteNumberOrNull2(breadth.advancers),
|
|
4159
|
+
decliners: toFiniteNumberOrNull2(breadth.decliners),
|
|
4160
|
+
unchanged: toFiniteNumberOrNull2(breadth.unchanged),
|
|
4161
|
+
advanceDeclineRatio: toFiniteNumberOrNull2(breadth.advanceDeclineRatio),
|
|
4162
|
+
pctAboveMa20: toFiniteNumberOrNull2(breadth.pctAboveMa20),
|
|
4163
|
+
pctAboveMa50: toFiniteNumberOrNull2(breadth.pctAboveMa50),
|
|
4164
|
+
equalWeightedReturn: toFiniteNumberOrNull2(breadth.equalWeightedReturn),
|
|
4165
|
+
volumeWeightedReturn: toFiniteNumberOrNull2(breadth.volumeWeightedReturn),
|
|
4166
|
+
dispersion: toFiniteNumberOrNull2(breadth.dispersion)
|
|
3967
4167
|
});
|
|
3968
4168
|
var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
3969
4169
|
const {
|
|
@@ -4064,46 +4264,46 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
4064
4264
|
asOfTs: primaryBreadth.ts.getTime(),
|
|
4065
4265
|
ageMs: primaryBreadth.ageMs,
|
|
4066
4266
|
stale: primaryBreadth.stale,
|
|
4067
|
-
btcReturn1h:
|
|
4267
|
+
btcReturn1h: toFiniteNumberOrNull2(
|
|
4068
4268
|
primaryBreadth.btcReturn1h
|
|
4069
4269
|
),
|
|
4070
|
-
btcReturn4h:
|
|
4270
|
+
btcReturn4h: toFiniteNumberOrNull2(
|
|
4071
4271
|
primaryBreadth.btcReturn4h
|
|
4072
4272
|
),
|
|
4073
|
-
btcReturn24h:
|
|
4273
|
+
btcReturn24h: toFiniteNumberOrNull2(
|
|
4074
4274
|
primaryBreadth.btcReturn24h
|
|
4075
4275
|
),
|
|
4076
|
-
altBasketReturn1h:
|
|
4276
|
+
altBasketReturn1h: toFiniteNumberOrNull2(
|
|
4077
4277
|
primaryBreadth.altBasketReturn1h
|
|
4078
4278
|
),
|
|
4079
|
-
altBasketReturn4h:
|
|
4279
|
+
altBasketReturn4h: toFiniteNumberOrNull2(
|
|
4080
4280
|
primaryBreadth.altBasketReturn4h
|
|
4081
4281
|
),
|
|
4082
|
-
altBasketReturn24h:
|
|
4282
|
+
altBasketReturn24h: toFiniteNumberOrNull2(
|
|
4083
4283
|
primaryBreadth.altBasketReturn24h
|
|
4084
4284
|
),
|
|
4085
|
-
btcVsAltReturn1h:
|
|
4285
|
+
btcVsAltReturn1h: toFiniteNumberOrNull2(
|
|
4086
4286
|
primaryBreadth.btcVsAltReturn1h
|
|
4087
4287
|
),
|
|
4088
|
-
btcVsAltReturn4h:
|
|
4288
|
+
btcVsAltReturn4h: toFiniteNumberOrNull2(
|
|
4089
4289
|
primaryBreadth.btcVsAltReturn4h
|
|
4090
4290
|
),
|
|
4091
|
-
btcVsAltReturn24h:
|
|
4291
|
+
btcVsAltReturn24h: toFiniteNumberOrNull2(
|
|
4092
4292
|
primaryBreadth.btcVsAltReturn24h
|
|
4093
4293
|
),
|
|
4094
|
-
btcTurnoverShare1h:
|
|
4294
|
+
btcTurnoverShare1h: toFiniteNumberOrNull2(
|
|
4095
4295
|
primaryBreadth.btcTurnoverShare1h
|
|
4096
4296
|
),
|
|
4097
|
-
btcTurnoverShare24h:
|
|
4297
|
+
btcTurnoverShare24h: toFiniteNumberOrNull2(
|
|
4098
4298
|
primaryBreadth.btcTurnoverShare24h
|
|
4099
4299
|
),
|
|
4100
|
-
btcTurnoverShareChange24h:
|
|
4300
|
+
btcTurnoverShareChange24h: toFiniteNumberOrNull2(
|
|
4101
4301
|
primaryBreadth.btcTurnoverShareChange24h
|
|
4102
4302
|
),
|
|
4103
|
-
altVolToBtcVol24h:
|
|
4303
|
+
altVolToBtcVol24h: toFiniteNumberOrNull2(
|
|
4104
4304
|
primaryBreadth.altVolToBtcVol24h
|
|
4105
4305
|
),
|
|
4106
|
-
altDispersion24h:
|
|
4306
|
+
altDispersion24h: toFiniteNumberOrNull2(
|
|
4107
4307
|
primaryBreadth.altDispersion24h
|
|
4108
4308
|
),
|
|
4109
4309
|
regime: primaryBreadth.btcAltRegime ?? "unknown"
|
|
@@ -4120,7 +4320,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
4120
4320
|
throw error;
|
|
4121
4321
|
}
|
|
4122
4322
|
binanceMarketContextUnavailable = true;
|
|
4123
|
-
|
|
4323
|
+
import_logger4.logger.warn(
|
|
4124
4324
|
"Binance market context disabled after Timescale read failure: %s",
|
|
4125
4325
|
String(error)
|
|
4126
4326
|
);
|
|
@@ -4130,7 +4330,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
4130
4330
|
|
|
4131
4331
|
// src/strategyHelpers/coinMarketCapContext.ts
|
|
4132
4332
|
var import_strategies2 = require("@tradejs/core/strategies");
|
|
4133
|
-
var
|
|
4333
|
+
var import_logger5 = require("@tradejs/infra/logger");
|
|
4134
4334
|
var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
|
|
4135
4335
|
var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
|
|
4136
4336
|
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
@@ -4168,7 +4368,7 @@ var asInt = (value, fallback) => {
|
|
|
4168
4368
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
4169
4369
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
4170
4370
|
};
|
|
4171
|
-
var
|
|
4371
|
+
var toFiniteNumberOrNull3 = (value) => {
|
|
4172
4372
|
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
4173
4373
|
return Number.isFinite(numeric) ? numeric : null;
|
|
4174
4374
|
};
|
|
@@ -4402,12 +4602,12 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4402
4602
|
const ethRow = references.get("ETHUSDT") ?? null;
|
|
4403
4603
|
const previousBtcRow = previousReferences.get("BTCUSDT") ?? null;
|
|
4404
4604
|
const previousEthRow = previousReferences.get("ETHUSDT") ?? null;
|
|
4405
|
-
const btcMarketCapUsd =
|
|
4406
|
-
const ethMarketCapUsd =
|
|
4407
|
-
const previousBtcMarketCapUsd =
|
|
4605
|
+
const btcMarketCapUsd = toFiniteNumberOrNull3(btcRow?.marketCapUsd);
|
|
4606
|
+
const ethMarketCapUsd = toFiniteNumberOrNull3(ethRow?.marketCapUsd);
|
|
4607
|
+
const previousBtcMarketCapUsd = toFiniteNumberOrNull3(
|
|
4408
4608
|
previousBtcRow?.marketCapUsd
|
|
4409
4609
|
);
|
|
4410
|
-
const previousEthMarketCapUsd =
|
|
4610
|
+
const previousEthMarketCapUsd = toFiniteNumberOrNull3(
|
|
4411
4611
|
previousEthRow?.marketCapUsd
|
|
4412
4612
|
);
|
|
4413
4613
|
const ethBtcMarketCapRatio = safeDivide(ethMarketCapUsd, btcMarketCapUsd);
|
|
@@ -4416,16 +4616,16 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4416
4616
|
previousBtcMarketCapUsd
|
|
4417
4617
|
);
|
|
4418
4618
|
const ethBtcMarketCapRatioChange24hPct = ethBtcMarketCapRatio != null && previousEthBtcMarketCapRatio != null && previousEthBtcMarketCapRatio > 0 ? (ethBtcMarketCapRatio - previousEthBtcMarketCapRatio) / previousEthBtcMarketCapRatio : null;
|
|
4419
|
-
const btcVolumeUsd =
|
|
4420
|
-
const ethVolumeUsd =
|
|
4619
|
+
const btcVolumeUsd = toFiniteNumberOrNull3(btcRow?.volumeUsd);
|
|
4620
|
+
const ethVolumeUsd = toFiniteNumberOrNull3(ethRow?.volumeUsd);
|
|
4421
4621
|
const referenceStale = btcRow?.stale === true || ethRow?.stale === true || !btcRow || !ethRow;
|
|
4422
|
-
const btcDominanceChange24hPct =
|
|
4622
|
+
const btcDominanceChange24hPct = toFiniteNumberOrNull3(
|
|
4423
4623
|
globalRow?.btcDominanceChange24hPct
|
|
4424
4624
|
);
|
|
4425
|
-
const altMarketCapChange24hPct =
|
|
4625
|
+
const altMarketCapChange24hPct = toFiniteNumberOrNull3(
|
|
4426
4626
|
globalRow?.altMarketCapChange24hPct
|
|
4427
4627
|
);
|
|
4428
|
-
const altVolumeChange24hPct =
|
|
4628
|
+
const altVolumeChange24hPct = toFiniteNumberOrNull3(
|
|
4429
4629
|
globalRow?.altVolumeChange24hPct
|
|
4430
4630
|
);
|
|
4431
4631
|
const altLiquidityRegime = globalRow ? toAltLiquidityRegime({
|
|
@@ -4436,19 +4636,19 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4436
4636
|
}) : "unknown";
|
|
4437
4637
|
const exchangeLiquidityRegime = exchangeLiquidityRow ? toExchangeLiquidityRegime({
|
|
4438
4638
|
stale: exchangeLiquidityRow.stale,
|
|
4439
|
-
totalVolumeChange24hPct:
|
|
4639
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4440
4640
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4441
4641
|
),
|
|
4442
4642
|
fallback: exchangeLiquidityRow.liquidityRegime ?? "unknown"
|
|
4443
4643
|
}) : "unknown";
|
|
4444
4644
|
const cmc100Row = indexRows.get("cmc100") ?? null;
|
|
4445
4645
|
const cmc20Row = indexRows.get("cmc20") ?? null;
|
|
4446
|
-
const cmc100Value =
|
|
4447
|
-
const cmc20Value =
|
|
4448
|
-
const cmc100Change24hPct =
|
|
4646
|
+
const cmc100Value = toFiniteNumberOrNull3(cmc100Row?.value);
|
|
4647
|
+
const cmc20Value = toFiniteNumberOrNull3(cmc20Row?.value);
|
|
4648
|
+
const cmc100Change24hPct = toFiniteNumberOrNull3(
|
|
4449
4649
|
cmc100Row?.valueChange24hPct
|
|
4450
4650
|
);
|
|
4451
|
-
const cmc20Change24hPct =
|
|
4651
|
+
const cmc20Change24hPct = toFiniteNumberOrNull3(cmc20Row?.valueChange24hPct);
|
|
4452
4652
|
const cmc20ToCmc100Ratio = safeDivide(cmc20Value, cmc100Value);
|
|
4453
4653
|
const cmc20ToCmc100RatioChange24hPct = cmc20Change24hPct != null && cmc100Change24hPct != null ? (1 + cmc20Change24hPct) / (1 + cmc100Change24hPct) - 1 : null;
|
|
4454
4654
|
const indexStale = cmc100Row?.stale === true || cmc20Row?.stale === true || !cmc100Row || !cmc20Row;
|
|
@@ -4472,41 +4672,41 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4472
4672
|
asOfTs: globalRow.ts.getTime(),
|
|
4473
4673
|
ageMs: globalRow.ageMs,
|
|
4474
4674
|
stale: globalRow.stale,
|
|
4475
|
-
totalMarketCapUsd:
|
|
4675
|
+
totalMarketCapUsd: toFiniteNumberOrNull3(
|
|
4476
4676
|
globalRow.totalMarketCapUsd
|
|
4477
4677
|
),
|
|
4478
|
-
totalVolumeUsd:
|
|
4678
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4479
4679
|
globalRow.totalVolumeUsd
|
|
4480
4680
|
),
|
|
4481
|
-
totalVolumeReportedUsd:
|
|
4681
|
+
totalVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4482
4682
|
globalRow.totalVolumeReportedUsd
|
|
4483
4683
|
),
|
|
4484
|
-
altMarketCapUsd:
|
|
4684
|
+
altMarketCapUsd: toFiniteNumberOrNull3(
|
|
4485
4685
|
globalRow.altMarketCapUsd
|
|
4486
4686
|
),
|
|
4487
|
-
altVolumeUsd:
|
|
4488
|
-
altVolumeReportedUsd:
|
|
4687
|
+
altVolumeUsd: toFiniteNumberOrNull3(globalRow.altVolumeUsd),
|
|
4688
|
+
altVolumeReportedUsd: toFiniteNumberOrNull3(
|
|
4489
4689
|
globalRow.altVolumeReportedUsd
|
|
4490
4690
|
),
|
|
4491
|
-
btcDominancePct:
|
|
4691
|
+
btcDominancePct: toFiniteNumberOrNull3(
|
|
4492
4692
|
globalRow.btcDominancePct
|
|
4493
4693
|
),
|
|
4494
|
-
ethDominancePct:
|
|
4694
|
+
ethDominancePct: toFiniteNumberOrNull3(
|
|
4495
4695
|
globalRow.ethDominancePct
|
|
4496
4696
|
),
|
|
4497
4697
|
btcDominanceChange24hPct,
|
|
4498
|
-
ethDominanceChange24hPct:
|
|
4698
|
+
ethDominanceChange24hPct: toFiniteNumberOrNull3(
|
|
4499
4699
|
globalRow.ethDominanceChange24hPct
|
|
4500
4700
|
),
|
|
4501
4701
|
altMarketCapChange24hPct,
|
|
4502
4702
|
altVolumeChange24hPct,
|
|
4503
|
-
activeCryptocurrencies:
|
|
4703
|
+
activeCryptocurrencies: toFiniteNumberOrNull3(
|
|
4504
4704
|
globalRow.activeCryptocurrencies
|
|
4505
4705
|
),
|
|
4506
|
-
activeExchanges:
|
|
4706
|
+
activeExchanges: toFiniteNumberOrNull3(
|
|
4507
4707
|
globalRow.activeExchanges
|
|
4508
4708
|
),
|
|
4509
|
-
activeMarketPairs:
|
|
4709
|
+
activeMarketPairs: toFiniteNumberOrNull3(
|
|
4510
4710
|
globalRow.activeMarketPairs
|
|
4511
4711
|
),
|
|
4512
4712
|
altLiquidityRegime
|
|
@@ -4551,22 +4751,22 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4551
4751
|
asOfTs: exchangeLiquidityRow.ts.getTime(),
|
|
4552
4752
|
ageMs: exchangeLiquidityRow.ageMs,
|
|
4553
4753
|
stale: exchangeLiquidityRow.stale,
|
|
4554
|
-
exchangesCount:
|
|
4754
|
+
exchangesCount: toFiniteNumberOrNull3(
|
|
4555
4755
|
exchangeLiquidityRow.exchangesCount
|
|
4556
4756
|
),
|
|
4557
|
-
totalVolumeUsd:
|
|
4757
|
+
totalVolumeUsd: toFiniteNumberOrNull3(
|
|
4558
4758
|
exchangeLiquidityRow.totalVolumeUsd
|
|
4559
4759
|
),
|
|
4560
|
-
totalVolumeChange24hPct:
|
|
4760
|
+
totalVolumeChange24hPct: toFiniteNumberOrNull3(
|
|
4561
4761
|
exchangeLiquidityRow.totalVolumeChange24hPct
|
|
4562
4762
|
),
|
|
4563
|
-
binanceVolumeUsd:
|
|
4763
|
+
binanceVolumeUsd: toFiniteNumberOrNull3(
|
|
4564
4764
|
exchangeLiquidityRow.binanceVolumeUsd
|
|
4565
4765
|
),
|
|
4566
|
-
binanceVolumeShare:
|
|
4766
|
+
binanceVolumeShare: toFiniteNumberOrNull3(
|
|
4567
4767
|
exchangeLiquidityRow.binanceVolumeShare
|
|
4568
4768
|
),
|
|
4569
|
-
topExchangeVolumeShare:
|
|
4769
|
+
topExchangeVolumeShare: toFiniteNumberOrNull3(
|
|
4570
4770
|
exchangeLiquidityRow.topExchangeVolumeShare
|
|
4571
4771
|
),
|
|
4572
4772
|
liquidityRegime: exchangeLiquidityRegime
|
|
@@ -4579,11 +4779,11 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4579
4779
|
asOfTs: fearGreedRow.ts.getTime(),
|
|
4580
4780
|
ageMs: fearGreedRow.ageMs,
|
|
4581
4781
|
stale: fearGreedRow.stale,
|
|
4582
|
-
value:
|
|
4583
|
-
valueChange24h:
|
|
4782
|
+
value: toFiniteNumberOrNull3(fearGreedRow.value),
|
|
4783
|
+
valueChange24h: toFiniteNumberOrNull3(
|
|
4584
4784
|
fearGreedRow.valueChange24h
|
|
4585
4785
|
),
|
|
4586
|
-
valueChange7d:
|
|
4786
|
+
valueChange7d: toFiniteNumberOrNull3(
|
|
4587
4787
|
fearGreedRow.valueChange7d
|
|
4588
4788
|
),
|
|
4589
4789
|
classification: fearGreedRow.classification ?? "Unknown",
|
|
@@ -4603,13 +4803,13 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4603
4803
|
cmc100Value,
|
|
4604
4804
|
cmc100Change24hPct,
|
|
4605
4805
|
cmc100TopConstituentSymbol: cmc100Row?.topConstituentSymbol ?? null,
|
|
4606
|
-
cmc100TopConstituentWeightPct:
|
|
4806
|
+
cmc100TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4607
4807
|
cmc100Row?.topConstituentWeightPct
|
|
4608
4808
|
),
|
|
4609
4809
|
cmc20Value,
|
|
4610
4810
|
cmc20Change24hPct,
|
|
4611
4811
|
cmc20TopConstituentSymbol: cmc20Row?.topConstituentSymbol ?? null,
|
|
4612
|
-
cmc20TopConstituentWeightPct:
|
|
4812
|
+
cmc20TopConstituentWeightPct: toFiniteNumberOrNull3(
|
|
4613
4813
|
cmc20Row?.topConstituentWeightPct
|
|
4614
4814
|
),
|
|
4615
4815
|
cmc20ToCmc100Ratio,
|
|
@@ -4627,7 +4827,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
4627
4827
|
throw error;
|
|
4628
4828
|
}
|
|
4629
4829
|
coinMarketCapContextUnavailable = true;
|
|
4630
|
-
|
|
4830
|
+
import_logger5.logger.warn(
|
|
4631
4831
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
4632
4832
|
String(error)
|
|
4633
4833
|
);
|
|
@@ -4641,7 +4841,7 @@ var import_data2 = require("@tradejs/core/data");
|
|
|
4641
4841
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
4642
4842
|
var import_constants2 = require("@tradejs/core/constants");
|
|
4643
4843
|
var import_derivatives = require("@tradejs/infra/timescale/derivatives");
|
|
4644
|
-
var
|
|
4844
|
+
var import_logger6 = require("@tradejs/infra/logger");
|
|
4645
4845
|
var STORED_INTERVALS = ["15m", "1h"];
|
|
4646
4846
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
4647
4847
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
@@ -4696,7 +4896,7 @@ var resolvePrimaryReferenceSymbol2 = () => PRIMARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
|
4696
4896
|
var resolveSecondaryReferenceSymbol = () => SECONDARY_DERIVATIVES_REFERENCE_SYMBOL;
|
|
4697
4897
|
var getPrimaryIntervalContext = (context) => context?.intervals["15m"] ?? context?.intervals["1h"] ?? null;
|
|
4698
4898
|
var hasDerivativesSymbolData = (context) => Object.keys(context.intervals).length > 0 && !context.summary.riskFlags.includes("missing_derivatives");
|
|
4699
|
-
var
|
|
4899
|
+
var toFiniteNumberOrNull4 = (value) => {
|
|
4700
4900
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4701
4901
|
if (typeof value === "string" && value.trim()) {
|
|
4702
4902
|
const parsed = Number(value);
|
|
@@ -4710,8 +4910,8 @@ var roundNullable = (value, digits = 4) => {
|
|
|
4710
4910
|
return Math.round(value * multiplier) / multiplier;
|
|
4711
4911
|
};
|
|
4712
4912
|
var deltaNullable = (targetValue, referenceValue) => {
|
|
4713
|
-
const target =
|
|
4714
|
-
const reference =
|
|
4913
|
+
const target = toFiniteNumberOrNull4(targetValue);
|
|
4914
|
+
const reference = toFiniteNumberOrNull4(referenceValue);
|
|
4715
4915
|
return target == null || reference == null ? null : roundNullable(target - reference);
|
|
4716
4916
|
};
|
|
4717
4917
|
var buildTargetDerivedContext = (params) => {
|
|
@@ -4873,7 +5073,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4873
5073
|
throw error;
|
|
4874
5074
|
}
|
|
4875
5075
|
derivativesContextUnavailable = true;
|
|
4876
|
-
|
|
5076
|
+
import_logger6.logger.warn(
|
|
4877
5077
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
4878
5078
|
String(error)
|
|
4879
5079
|
);
|
|
@@ -4885,7 +5085,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
4885
5085
|
var import_data3 = require("@tradejs/core/data");
|
|
4886
5086
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
4887
5087
|
var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
|
|
4888
|
-
var
|
|
5088
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
4889
5089
|
|
|
4890
5090
|
// src/hyperliquidWhaleUniverse.ts
|
|
4891
5091
|
var import_node_crypto3 = require("crypto");
|
|
@@ -5409,7 +5609,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
5409
5609
|
throw error;
|
|
5410
5610
|
}
|
|
5411
5611
|
hyperliquidWhaleContextUnavailable = true;
|
|
5412
|
-
|
|
5612
|
+
import_logger7.logger.warn(
|
|
5413
5613
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
5414
5614
|
String(error)
|
|
5415
5615
|
);
|
|
@@ -5492,7 +5692,7 @@ var runMarketContextStage = async ({
|
|
|
5492
5692
|
elapsedMs: Date.now() - startedAt
|
|
5493
5693
|
};
|
|
5494
5694
|
if (status === "timed_out") {
|
|
5495
|
-
|
|
5695
|
+
import_logger8.logger.warn(
|
|
5496
5696
|
"Market context stage timed out: %s after %sms",
|
|
5497
5697
|
stage,
|
|
5498
5698
|
result.elapsedMs
|
|
@@ -5682,7 +5882,7 @@ var enrichSignalWithAi = async ({
|
|
|
5682
5882
|
signal.aiAnalysis = analysis;
|
|
5683
5883
|
return resolveAiQuality(analysis, direction);
|
|
5684
5884
|
} catch (err) {
|
|
5685
|
-
|
|
5885
|
+
import_logger9.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
|
|
5686
5886
|
}
|
|
5687
5887
|
return void 0;
|
|
5688
5888
|
};
|
|
@@ -5699,75 +5899,6 @@ var enrichSignalWithMlAi = async ({
|
|
|
5699
5899
|
await enrichSignalWithMl({ signal, env, ml });
|
|
5700
5900
|
return enrichSignalWithAi({ signal, userName, symbol, direction, env, ai });
|
|
5701
5901
|
};
|
|
5702
|
-
var toFiniteNumberOrNull4 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
5703
|
-
var getOrderArrivalSnapshot = async ({
|
|
5704
|
-
connector,
|
|
5705
|
-
symbol
|
|
5706
|
-
}) => {
|
|
5707
|
-
if (typeof connector.getTopOfBookTicker !== "function") {
|
|
5708
|
-
return {
|
|
5709
|
-
arrivalSnapshotTime: Date.now(),
|
|
5710
|
-
arrivalSource: "unavailable",
|
|
5711
|
-
bid: null,
|
|
5712
|
-
ask: null,
|
|
5713
|
-
arrivalMid: null,
|
|
5714
|
-
spreadBps: null
|
|
5715
|
-
};
|
|
5716
|
-
}
|
|
5717
|
-
try {
|
|
5718
|
-
const ticker = await connector.getTopOfBookTicker(symbol);
|
|
5719
|
-
const arrivalSnapshotTime = toFiniteNumberOrNull4(ticker?.timestamp);
|
|
5720
|
-
const bid = toFiniteNumberOrNull4(ticker?.bidPrice);
|
|
5721
|
-
const ask = toFiniteNumberOrNull4(ticker?.askPrice);
|
|
5722
|
-
const arrivalMid = bid != null && ask != null ? (bid + ask) / 2 : null;
|
|
5723
|
-
const spreadBps = bid != null && ask != null && arrivalMid != null && arrivalMid > 0 ? (ask - bid) / arrivalMid * 1e4 : null;
|
|
5724
|
-
return {
|
|
5725
|
-
arrivalSnapshotTime: arrivalSnapshotTime ?? Date.now(),
|
|
5726
|
-
arrivalSource: "top_of_book",
|
|
5727
|
-
bid,
|
|
5728
|
-
ask,
|
|
5729
|
-
arrivalMid,
|
|
5730
|
-
spreadBps
|
|
5731
|
-
};
|
|
5732
|
-
} catch (error) {
|
|
5733
|
-
import_logger8.logger.warn(
|
|
5734
|
-
"runtime order arrival snapshot failed: %s %s",
|
|
5735
|
-
symbol,
|
|
5736
|
-
error?.message || String(error)
|
|
5737
|
-
);
|
|
5738
|
-
return {
|
|
5739
|
-
arrivalSnapshotTime: Date.now(),
|
|
5740
|
-
arrivalSource: "top_of_book_error",
|
|
5741
|
-
bid: null,
|
|
5742
|
-
ask: null,
|
|
5743
|
-
arrivalMid: null,
|
|
5744
|
-
spreadBps: null
|
|
5745
|
-
};
|
|
5746
|
-
}
|
|
5747
|
-
};
|
|
5748
|
-
var validateEntryProtectionAtArrival = ({
|
|
5749
|
-
direction,
|
|
5750
|
-
signalPrice,
|
|
5751
|
-
bid,
|
|
5752
|
-
ask,
|
|
5753
|
-
arrivalMid,
|
|
5754
|
-
takeProfits,
|
|
5755
|
-
stopLossPrice
|
|
5756
|
-
}) => {
|
|
5757
|
-
const entryReference = direction === "LONG" ? ask ?? arrivalMid ?? signalPrice : bid ?? arrivalMid ?? signalPrice;
|
|
5758
|
-
const stopReference = direction === "LONG" ? bid ?? arrivalMid ?? signalPrice : ask ?? arrivalMid ?? signalPrice;
|
|
5759
|
-
if (!Number.isFinite(entryReference) || entryReference <= 0 || !Number.isFinite(stopReference) || stopReference <= 0) {
|
|
5760
|
-
throw new Error("INVALID_ENTRY_REFERENCE_AT_ARRIVAL");
|
|
5761
|
-
}
|
|
5762
|
-
for (const takeProfit of takeProfits) {
|
|
5763
|
-
if (!Number.isFinite(takeProfit.price) || takeProfit.price <= 0 || (direction === "LONG" ? takeProfit.price <= entryReference : takeProfit.price >= entryReference)) {
|
|
5764
|
-
throw new Error("TAKE_PROFIT_CROSSED_BEFORE_ENTRY");
|
|
5765
|
-
}
|
|
5766
|
-
}
|
|
5767
|
-
if (stopLossPrice != null && (!Number.isFinite(stopLossPrice) || stopLossPrice <= 0 || (direction === "LONG" ? stopLossPrice >= stopReference : stopLossPrice <= stopReference))) {
|
|
5768
|
-
throw new Error("STOP_LOSS_CROSSED_BEFORE_ENTRY");
|
|
5769
|
-
}
|
|
5770
|
-
};
|
|
5771
5902
|
var resolveRuntimeTelemetryQuality = ({
|
|
5772
5903
|
signalClosePrice,
|
|
5773
5904
|
arrivalMid,
|
|
@@ -5844,7 +5975,8 @@ var executeEntryOrder = async ({
|
|
|
5844
5975
|
signal,
|
|
5845
5976
|
beforePlaceOrder,
|
|
5846
5977
|
recordRuntimeTrade = true,
|
|
5847
|
-
leverage
|
|
5978
|
+
leverage,
|
|
5979
|
+
executionLimits
|
|
5848
5980
|
}) => {
|
|
5849
5981
|
await beforePlaceOrder?.();
|
|
5850
5982
|
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
@@ -5855,23 +5987,57 @@ var executeEntryOrder = async ({
|
|
|
5855
5987
|
signal.orderQty = qty;
|
|
5856
5988
|
signal.orderValue = qty * currentPrice;
|
|
5857
5989
|
signal.orderFailureReason = void 0;
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5990
|
+
let arrivalSnapshot = {
|
|
5991
|
+
arrivalSnapshotTime: Date.now(),
|
|
5992
|
+
arrivalSource: "unavailable",
|
|
5993
|
+
bid: null,
|
|
5994
|
+
ask: null,
|
|
5995
|
+
arrivalMid: null,
|
|
5996
|
+
spreadBps: null
|
|
5997
|
+
};
|
|
5998
|
+
let orderSubmitTime = Date.now();
|
|
5999
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
6000
|
+
connector,
|
|
6001
|
+
symbol,
|
|
6002
|
+
direction,
|
|
6003
|
+
takeProfits,
|
|
6004
|
+
stopLossPrice,
|
|
6005
|
+
limits: executionLimits,
|
|
6006
|
+
onValidated: (snapshot2, economics2) => {
|
|
6007
|
+
arrivalSnapshot = snapshot2;
|
|
6008
|
+
orderSubmitTime = Date.now();
|
|
6009
|
+
if (executionLimits?.maxLossValue != null) {
|
|
6010
|
+
signal.riskDecision = {
|
|
6011
|
+
stage: "order_plan",
|
|
6012
|
+
status: "approved",
|
|
6013
|
+
reason: "PLANNED_LOSS_WITHIN_MAX_LOSS_VALUE",
|
|
6014
|
+
plannedLossValue: economics2.plannedLossValue,
|
|
6015
|
+
maxLossValue: executionLimits.maxLossValue,
|
|
6016
|
+
limitUtilization: economics2.plannedLossValue / executionLimits.maxLossValue,
|
|
6017
|
+
enforced: true
|
|
6018
|
+
};
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
6021
|
+
});
|
|
6022
|
+
if (!beforeSubmit) {
|
|
6023
|
+
arrivalSnapshot = await getOrderArrivalSnapshot({ connector, symbol });
|
|
6024
|
+
try {
|
|
6025
|
+
validateEntryProtectionAtArrival({
|
|
6026
|
+
direction,
|
|
6027
|
+
signalPrice: currentPrice,
|
|
6028
|
+
bid: arrivalSnapshot.bid,
|
|
6029
|
+
ask: arrivalSnapshot.ask,
|
|
6030
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6031
|
+
takeProfits,
|
|
6032
|
+
stopLossPrice
|
|
6033
|
+
});
|
|
6034
|
+
} catch (error) {
|
|
6035
|
+
signal.orderStatus = "failed";
|
|
6036
|
+
signal.orderFailureReason = error.message;
|
|
6037
|
+
throw error;
|
|
6038
|
+
}
|
|
6039
|
+
orderSubmitTime = Date.now();
|
|
5873
6040
|
}
|
|
5874
|
-
const orderSubmitTime = Date.now();
|
|
5875
6041
|
const orderPlaced = await connector.placeOrder({
|
|
5876
6042
|
symbol,
|
|
5877
6043
|
qty,
|
|
@@ -5882,7 +6048,8 @@ var executeEntryOrder = async ({
|
|
|
5882
6048
|
direction,
|
|
5883
6049
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
5884
6050
|
orderId,
|
|
5885
|
-
signal
|
|
6051
|
+
signal,
|
|
6052
|
+
...beforeSubmit ? { beforeSubmit } : {}
|
|
5886
6053
|
});
|
|
5887
6054
|
const orderAckTime = Date.now();
|
|
5888
6055
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
@@ -6711,7 +6878,7 @@ var canUseSharedReplayState = ({
|
|
|
6711
6878
|
}) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
|
|
6712
6879
|
|
|
6713
6880
|
// src/strategy/runtimeExecution.ts
|
|
6714
|
-
var
|
|
6881
|
+
var import_logger10 = require("@tradejs/infra/logger");
|
|
6715
6882
|
var import_types = require("@tradejs/types");
|
|
6716
6883
|
var buildExitOrderSignal = ({
|
|
6717
6884
|
strategyName,
|
|
@@ -6763,7 +6930,7 @@ var handleExitDecision = async ({
|
|
|
6763
6930
|
deploymentId: connector.deploymentId
|
|
6764
6931
|
});
|
|
6765
6932
|
if (!activeTrade) {
|
|
6766
|
-
|
|
6933
|
+
import_logger10.logger.warn(
|
|
6767
6934
|
"[%s] blocked closePosition for untracked runtime position: %s",
|
|
6768
6935
|
strategyName ?? "unknown",
|
|
6769
6936
|
symbol
|
|
@@ -6771,7 +6938,7 @@ var handleExitDecision = async ({
|
|
|
6771
6938
|
return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
|
|
6772
6939
|
}
|
|
6773
6940
|
if (!strategyName || activeTrade.strategy !== strategyName) {
|
|
6774
|
-
|
|
6941
|
+
import_logger10.logger.warn(
|
|
6775
6942
|
"[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
|
|
6776
6943
|
strategyName ?? "unknown",
|
|
6777
6944
|
symbol,
|
|
@@ -6824,7 +6991,7 @@ var handleExitDecision = async ({
|
|
|
6824
6991
|
exitType: closedTrade?.exitType ?? "exit"
|
|
6825
6992
|
});
|
|
6826
6993
|
} catch (notificationError) {
|
|
6827
|
-
|
|
6994
|
+
import_logger10.logger.error(
|
|
6828
6995
|
"runtime close notification error: %s %s",
|
|
6829
6996
|
symbol,
|
|
6830
6997
|
notificationError
|
|
@@ -6838,7 +7005,7 @@ var handleExitDecision = async ({
|
|
|
6838
7005
|
decision,
|
|
6839
7006
|
market
|
|
6840
7007
|
});
|
|
6841
|
-
|
|
7008
|
+
import_logger10.logger.error("close order error: %s %s", symbol, err);
|
|
6842
7009
|
return "ORDER_ERROR";
|
|
6843
7010
|
}
|
|
6844
7011
|
return decision.code;
|
|
@@ -6865,7 +7032,7 @@ var handleProtectDecision = async ({
|
|
|
6865
7032
|
decision,
|
|
6866
7033
|
market
|
|
6867
7034
|
});
|
|
6868
|
-
|
|
7035
|
+
import_logger10.logger.error("protect position error: %s %s", symbol, err);
|
|
6869
7036
|
return "ORDER_ERROR";
|
|
6870
7037
|
}
|
|
6871
7038
|
return decision.code;
|
|
@@ -6931,7 +7098,11 @@ var executeEntryDecision = async ({
|
|
|
6931
7098
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
6932
7099
|
signal,
|
|
6933
7100
|
beforePlaceOrder,
|
|
6934
|
-
recordRuntimeTrade: recordRuntimeJournal
|
|
7101
|
+
recordRuntimeTrade: recordRuntimeJournal,
|
|
7102
|
+
executionLimits: resolveEntryExecutionLimits(
|
|
7103
|
+
hookCtx.strategyConfig,
|
|
7104
|
+
decision.entryContext.direction
|
|
7105
|
+
)
|
|
6935
7106
|
});
|
|
6936
7107
|
await invokeStageHooks(
|
|
6937
7108
|
"afterPlaceOrder",
|
|
@@ -6953,19 +7124,32 @@ var executeEntryDecision = async ({
|
|
|
6953
7124
|
return signal;
|
|
6954
7125
|
}
|
|
6955
7126
|
await beforePlaceOrder();
|
|
6956
|
-
const
|
|
7127
|
+
const beforeSubmit = createEntrySubmissionValidation({
|
|
6957
7128
|
connector,
|
|
6958
|
-
symbol
|
|
6959
|
-
});
|
|
6960
|
-
validateEntryProtectionAtArrival({
|
|
7129
|
+
symbol,
|
|
6961
7130
|
direction: decision.entryContext.direction,
|
|
6962
|
-
signalPrice: decision.entryContext.prices.currentPrice,
|
|
6963
|
-
bid: arrivalSnapshot.bid,
|
|
6964
|
-
ask: arrivalSnapshot.ask,
|
|
6965
|
-
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
6966
7131
|
takeProfits: decision.orderPlan.takeProfits,
|
|
6967
|
-
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
7132
|
+
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
7133
|
+
limits: resolveEntryExecutionLimits(
|
|
7134
|
+
hookCtx.strategyConfig,
|
|
7135
|
+
decision.entryContext.direction
|
|
7136
|
+
)
|
|
6968
7137
|
});
|
|
7138
|
+
if (!beforeSubmit) {
|
|
7139
|
+
const arrivalSnapshot = await getOrderArrivalSnapshot({
|
|
7140
|
+
connector,
|
|
7141
|
+
symbol
|
|
7142
|
+
});
|
|
7143
|
+
validateEntryProtectionAtArrival({
|
|
7144
|
+
direction: decision.entryContext.direction,
|
|
7145
|
+
signalPrice: decision.entryContext.prices.currentPrice,
|
|
7146
|
+
bid: arrivalSnapshot.bid,
|
|
7147
|
+
ask: arrivalSnapshot.ask,
|
|
7148
|
+
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
7149
|
+
takeProfits: decision.orderPlan.takeProfits,
|
|
7150
|
+
stopLossPrice: decision.orderPlan.stopLossPrice
|
|
7151
|
+
});
|
|
7152
|
+
}
|
|
6969
7153
|
const orderPlaced = await connector.placeOrder({
|
|
6970
7154
|
symbol,
|
|
6971
7155
|
qty: decision.orderPlan.qty,
|
|
@@ -6973,6 +7157,7 @@ var executeEntryDecision = async ({
|
|
|
6973
7157
|
timestamp: decision.entryContext.timestamp,
|
|
6974
7158
|
direction: decision.entryContext.direction,
|
|
6975
7159
|
positionIntent: decision.orderPlan.positionIntent,
|
|
7160
|
+
...beforeSubmit ? { beforeSubmit } : {},
|
|
6976
7161
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
6977
7162
|
});
|
|
6978
7163
|
if (!orderPlaced) {
|
|
@@ -7014,6 +7199,23 @@ var executeEntryDecision = async ({
|
|
|
7014
7199
|
{ decision, entry, market }
|
|
7015
7200
|
);
|
|
7016
7201
|
} catch (err) {
|
|
7202
|
+
if (err instanceof EntrySubmissionValidationError) {
|
|
7203
|
+
if (signal) {
|
|
7204
|
+
signal.orderStatus = "skipped";
|
|
7205
|
+
signal.orderSkipReason = err.message;
|
|
7206
|
+
signal.allocatorDecision = {
|
|
7207
|
+
stage: "runtime_admission",
|
|
7208
|
+
status: "rejected",
|
|
7209
|
+
reason: err.message
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
7212
|
+
import_logger10.logger.warn(
|
|
7213
|
+
"entry rejected before submission: %s %s",
|
|
7214
|
+
symbol,
|
|
7215
|
+
err.message
|
|
7216
|
+
);
|
|
7217
|
+
return signal ?? err.message;
|
|
7218
|
+
}
|
|
7017
7219
|
if (signal) {
|
|
7018
7220
|
signal.orderStatus = "failed";
|
|
7019
7221
|
if (typeof signal.orderFailureReason !== "string" || !signal.orderFailureReason.trim()) {
|
|
@@ -7028,9 +7230,9 @@ var executeEntryDecision = async ({
|
|
|
7028
7230
|
market
|
|
7029
7231
|
});
|
|
7030
7232
|
if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
|
|
7031
|
-
|
|
7233
|
+
import_logger10.logger.warn("order warning: %s %s", symbol, err);
|
|
7032
7234
|
} else {
|
|
7033
|
-
|
|
7235
|
+
import_logger10.logger.error("order error: %s %s", symbol, err);
|
|
7034
7236
|
}
|
|
7035
7237
|
return signal ?? "ORDER_ERROR";
|
|
7036
7238
|
}
|
|
@@ -7195,7 +7397,7 @@ var createStrategyRuntime = ({
|
|
|
7195
7397
|
try {
|
|
7196
7398
|
await projectHook(errorParams);
|
|
7197
7399
|
} catch (hookError) {
|
|
7198
|
-
|
|
7400
|
+
import_logger11.logger.error(
|
|
7199
7401
|
"project hook onRuntimeError failed: %s %s",
|
|
7200
7402
|
strategyName,
|
|
7201
7403
|
hookError
|
|
@@ -7209,7 +7411,7 @@ var createStrategyRuntime = ({
|
|
|
7209
7411
|
try {
|
|
7210
7412
|
await onRuntimeError(errorParams);
|
|
7211
7413
|
} catch (hookError) {
|
|
7212
|
-
|
|
7414
|
+
import_logger11.logger.error(
|
|
7213
7415
|
"runtime hook onRuntimeError failed: %s %s",
|
|
7214
7416
|
strategyName,
|
|
7215
7417
|
hookError
|
|
@@ -7223,7 +7425,7 @@ var createStrategyRuntime = ({
|
|
|
7223
7425
|
try {
|
|
7224
7426
|
return await hook(params);
|
|
7225
7427
|
} catch (error) {
|
|
7226
|
-
|
|
7428
|
+
import_logger11.logger.error(
|
|
7227
7429
|
'strategy hook "%s" failed for %s: %s',
|
|
7228
7430
|
stage,
|
|
7229
7431
|
strategyName,
|
|
@@ -7422,8 +7624,11 @@ var createStrategyRuntime = ({
|
|
|
7422
7624
|
return enrichedBaseContext;
|
|
7423
7625
|
}
|
|
7424
7626
|
});
|
|
7627
|
+
const coreConfig = { ...config };
|
|
7628
|
+
delete coreConfig.RECORD_RUNTIME_TRADES;
|
|
7629
|
+
delete coreConfig.SIMULATE_ORDERS;
|
|
7425
7630
|
const core = await createCore({
|
|
7426
|
-
config,
|
|
7631
|
+
config: coreConfig,
|
|
7427
7632
|
data,
|
|
7428
7633
|
strategyApi,
|
|
7429
7634
|
indicatorsState
|
|
@@ -8043,7 +8248,7 @@ setStrategyRuntimeFactory(createStrategyRuntime);
|
|
|
8043
8248
|
|
|
8044
8249
|
// src/strategyHooks/closeOppositePositionsBeforeOpen.ts
|
|
8045
8250
|
var import_lodash2 = __toESM(require("lodash"));
|
|
8046
|
-
var
|
|
8251
|
+
var import_logger12 = require("@tradejs/infra/logger");
|
|
8047
8252
|
var closeOppositePositionsBeforeOpen = async ({
|
|
8048
8253
|
connector,
|
|
8049
8254
|
entryContext
|
|
@@ -8057,7 +8262,7 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8057
8262
|
} = entryContext;
|
|
8058
8263
|
const price = prices.currentPrice;
|
|
8059
8264
|
try {
|
|
8060
|
-
|
|
8265
|
+
import_logger12.logger.log(
|
|
8061
8266
|
"info",
|
|
8062
8267
|
"[%s] checking open positions before open: %s %s",
|
|
8063
8268
|
strategyName,
|
|
@@ -8068,7 +8273,7 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8068
8273
|
const openPositions = (positions || []).filter(
|
|
8069
8274
|
(item) => item && Number(item.qty) > 0
|
|
8070
8275
|
);
|
|
8071
|
-
|
|
8276
|
+
import_logger12.logger.log(
|
|
8072
8277
|
"info",
|
|
8073
8278
|
"[%s] open positions found: %s",
|
|
8074
8279
|
strategyName,
|
|
@@ -8078,7 +8283,7 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8078
8283
|
(item) => item.symbol !== currentSymbol && item.direction !== currentDirection
|
|
8079
8284
|
);
|
|
8080
8285
|
if (import_lodash2.default.isEmpty(oppositePositions)) {
|
|
8081
|
-
|
|
8286
|
+
import_logger12.logger.log(
|
|
8082
8287
|
"info",
|
|
8083
8288
|
"[%s] no opposite positions to close before open: %s",
|
|
8084
8289
|
strategyName,
|
|
@@ -8087,7 +8292,7 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8087
8292
|
return;
|
|
8088
8293
|
}
|
|
8089
8294
|
for (const position of oppositePositions) {
|
|
8090
|
-
|
|
8295
|
+
import_logger12.logger.log(
|
|
8091
8296
|
"info",
|
|
8092
8297
|
"[%s] closing opposite position: %s %s qty=%s",
|
|
8093
8298
|
strategyName,
|
|
@@ -8102,14 +8307,14 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8102
8307
|
timestamp,
|
|
8103
8308
|
direction: position.direction
|
|
8104
8309
|
});
|
|
8105
|
-
|
|
8310
|
+
import_logger12.logger.log(
|
|
8106
8311
|
"info",
|
|
8107
8312
|
"[%s] opposite position closed: %s",
|
|
8108
8313
|
strategyName,
|
|
8109
8314
|
position.symbol
|
|
8110
8315
|
);
|
|
8111
8316
|
} catch (err) {
|
|
8112
|
-
|
|
8317
|
+
import_logger12.logger.log(
|
|
8113
8318
|
"error",
|
|
8114
8319
|
"[%s] failed to close opposite position: %s %s",
|
|
8115
8320
|
strategyName,
|
|
@@ -8119,7 +8324,7 @@ var closeOppositePositionsBeforeOpen = async ({
|
|
|
8119
8324
|
}
|
|
8120
8325
|
}
|
|
8121
8326
|
} catch (err) {
|
|
8122
|
-
|
|
8327
|
+
import_logger12.logger.log(
|
|
8123
8328
|
"error",
|
|
8124
8329
|
"[%s] failed to load open positions before open: %s %s",
|
|
8125
8330
|
strategyName,
|
|
@@ -8331,7 +8536,7 @@ var createMoveStopToBreakEvenOnBarHook = ({
|
|
|
8331
8536
|
var createMoveStopToBreakEvenAfterCoreDecisionHook = createMoveStopToBreakEvenOnBarHook;
|
|
8332
8537
|
|
|
8333
8538
|
// src/signalsHooks/closeAllPositionsOnGlobalProfitBeforeSignals.ts
|
|
8334
|
-
var
|
|
8539
|
+
var import_logger13 = require("@tradejs/infra/logger");
|
|
8335
8540
|
var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
|
|
8336
8541
|
getStrategyDefaultConfig = () => void 0,
|
|
8337
8542
|
profitRiskMultiplier = DEFAULT_GLOBAL_UNREALIZED_PNL_TRIGGER_RISK_MULTIPLIER
|
|
@@ -8370,7 +8575,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
|
|
|
8370
8575
|
if (!Number.isFinite(unrealizedPnlThreshold) || unrealizedPnlThreshold <= 0 || totalUnrealizedPnl < unrealizedPnlThreshold) {
|
|
8371
8576
|
return;
|
|
8372
8577
|
}
|
|
8373
|
-
|
|
8578
|
+
import_logger13.logger.info(
|
|
8374
8579
|
"closing all positions before signals by global unrealized pnl threshold: totalPnl=%s threshold=%s positions=%s",
|
|
8375
8580
|
totalUnrealizedPnl,
|
|
8376
8581
|
unrealizedPnlThreshold,
|
|
@@ -8396,7 +8601,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
|
|
|
8396
8601
|
];
|
|
8397
8602
|
});
|
|
8398
8603
|
if (failedClosures.length) {
|
|
8399
|
-
|
|
8604
|
+
import_logger13.logger.warn(
|
|
8400
8605
|
"close-all before signals hook could not confirm closures for %s",
|
|
8401
8606
|
failedClosures.join(", ")
|
|
8402
8607
|
);
|