@tradejs/cli 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +29497 -13537
- package/dist/lib/aiPocketSearch.js +1316 -0
- package/dist/lib/aiTrainCharts.js +711 -0
- package/dist/lib/aiTrainDataset.js +40 -0
- package/dist/lib/aiTrainEvaluationDump.js +76 -0
- package/dist/lib/aiTrainMetrics.js +148 -8
- package/dist/lib/aiTrainOptions.js +130 -0
- package/dist/lib/aiTrainQuarantine.js +199 -0
- package/dist/lib/aiTrainResearch.js +467 -0
- package/dist/lib/binanceMarketContextBackfill.js +841 -0
- package/dist/lib/binanceMarketData.js +392 -0
- package/dist/lib/coinMarketCapContextBackfill.js +1088 -0
- package/dist/lib/continuity.js +60 -0
- package/dist/lib/derivativesContextBackfill.js +490 -77
- package/dist/lib/executionCalibration.js +705 -0
- package/dist/lib/marketContextPrepare.js +4403 -0
- package/dist/lib/paritySummary.js +101 -0
- package/dist/lib/runBot.js +1 -0
- package/dist/lib/runEnvironment.js +2254 -0
- package/dist/lib/runFormatting.js +1657 -0
- package/dist/lib/runtimeDebugEvidence.js +526 -0
- package/dist/lib/runtimeModeConfig.js +53 -0
- package/dist/lib/runtimeParity.js +88 -11
- package/dist/lib/runtimeParityDetails.js +751 -0
- package/dist/lib/runtimeRedis.js +157 -0
- package/dist/lib/runtimeSignalsLoader.js +40 -6
- package/dist/lib/runtimeSignalsStorage.js +45 -22
- package/dist/lib/runtimeStrategyBacktest.js +134 -0
- package/dist/lib/runtimeTradeSync.js +263 -0
- package/dist/lib/telegramReports.js +9 -0
- package/dist/lib/tickerUniverseCache.js +116 -0
- package/dist/lib/timeWindow.js +3 -3
- package/dist/scripts/agentRun.js +14 -8
- package/dist/scripts/aiExport.js +1721 -7
- package/dist/scripts/aiExportSelect.js +16 -4
- package/dist/scripts/aiPocketSearch.js +4190 -0
- package/dist/scripts/aiTrain.js +1866 -87
- package/dist/scripts/backtest.js +4509 -818
- package/dist/scripts/binanceMarketIngest.js +565 -0
- package/dist/scripts/bot.js +16 -2
- package/dist/scripts/candlesMigrateProvider.js +32 -22
- package/dist/scripts/cleanDir.js +15 -2
- package/dist/scripts/cleanRedis.js +15 -2
- package/dist/scripts/cleanTests.js +38 -2
- package/dist/scripts/cleanupMarketContext.js +69 -0
- package/dist/scripts/continuity.js +148 -67
- package/dist/scripts/derivativesIngest.js +14 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +14 -4
- package/dist/scripts/doctor.js +14 -4
- package/dist/scripts/executionCalibration.js +792 -0
- package/dist/scripts/infraCommon.js +10 -0
- package/dist/scripts/infraDown.js +14 -4
- package/dist/scripts/infraInit.js +24 -4
- package/dist/scripts/infraUp.js +14 -4
- package/dist/scripts/marketWs.js +222 -0
- package/dist/scripts/migration.js +15 -2
- package/dist/scripts/mlExport.js +1698 -10
- package/dist/scripts/mlExportSelect.js +16 -4
- package/dist/scripts/mlInspect.js +13 -3
- package/dist/scripts/mlTrainLatestSelect.js +14 -4
- package/dist/scripts/replay.js +8824 -0
- package/dist/scripts/replayRunner.js +8827 -0
- package/dist/scripts/replayRuntimeEvidence.js +868 -0
- package/dist/scripts/researchAuto.js +286 -59
- package/dist/scripts/results.js +3 -3
- package/dist/scripts/runtimeEvidence.js +605 -0
- package/dist/scripts/runtimeParity.js +6362 -1043
- package/dist/scripts/serverHealth.js +588 -0
- package/dist/scripts/signals.js +5590 -511
- package/dist/scripts/signalsDaemon.js +6167 -0
- package/dist/scripts/signalsSummary.js +833 -248
- package/dist/scripts/test-ml.js +25 -3
- package/dist/scripts/test.js +26 -1
- package/dist/scripts/user-add.js +15 -2
- package/dist/workers/testerWorker.js +130 -21
- package/package.json +18 -12
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/binanceMarketData.ts
|
|
21
|
+
var binanceMarketData_exports = {};
|
|
22
|
+
__export(binanceMarketData_exports, {
|
|
23
|
+
MARKET_FEATURE_INTERVAL_MS: () => MARKET_FEATURE_INTERVAL_MS,
|
|
24
|
+
aggregateAggTradesToRows: () => aggregateAggTradesToRows,
|
|
25
|
+
buildKlineTradeFlowRows: () => buildKlineTradeFlowRows,
|
|
26
|
+
buildMarketBreadthRows: () => buildMarketBreadthRows,
|
|
27
|
+
classifyBtcAltRegime: () => classifyBtcAltRegime,
|
|
28
|
+
estimateBinanceMarketDataVolume: () => estimateBinanceMarketDataVolume,
|
|
29
|
+
normalizeBinanceSymbols: () => normalizeBinanceSymbols,
|
|
30
|
+
normalizeMarketFeatureInterval: () => normalizeMarketFeatureInterval,
|
|
31
|
+
selectBreadthUniverseFromTickers: () => selectBreadthUniverseFromTickers
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(binanceMarketData_exports);
|
|
34
|
+
var MARKET_FEATURE_INTERVAL_MS = {
|
|
35
|
+
"1m": 6e4,
|
|
36
|
+
"5m": 3e5,
|
|
37
|
+
"15m": 9e5,
|
|
38
|
+
"1h": 36e5
|
|
39
|
+
};
|
|
40
|
+
var STABLE_QUOTE_SYMBOLS = /* @__PURE__ */ new Set([
|
|
41
|
+
"USDCUSDT",
|
|
42
|
+
"FDUSDUSDT",
|
|
43
|
+
"TUSDUSDT",
|
|
44
|
+
"BUSDUSDT",
|
|
45
|
+
"USDPUSDT",
|
|
46
|
+
"DAIUSDT"
|
|
47
|
+
]);
|
|
48
|
+
var safeDivide = (num, den) => Number.isFinite(num) && Number.isFinite(den) && den !== 0 ? num / den : null;
|
|
49
|
+
var mean = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
|
|
50
|
+
var standardDeviation = (values) => {
|
|
51
|
+
const avg = mean(values);
|
|
52
|
+
if (avg == null || values.length < 2) return null;
|
|
53
|
+
const variance = values.reduce((sum, value) => sum + (value - avg) ** 2, 0) / values.length;
|
|
54
|
+
return Math.sqrt(variance);
|
|
55
|
+
};
|
|
56
|
+
var buildPrefixSum = (values) => {
|
|
57
|
+
const prefix = [0];
|
|
58
|
+
for (const value of values) prefix.push(prefix[prefix.length - 1] + value);
|
|
59
|
+
return prefix;
|
|
60
|
+
};
|
|
61
|
+
var sumPrefixRange = (prefix, startIndex, endIndexInclusive) => {
|
|
62
|
+
if (endIndexInclusive < startIndex) return 0;
|
|
63
|
+
const start = Math.max(0, startIndex);
|
|
64
|
+
const end = Math.min(prefix.length - 2, endIndexInclusive);
|
|
65
|
+
if (end < start) return 0;
|
|
66
|
+
return prefix[end + 1] - prefix[start];
|
|
67
|
+
};
|
|
68
|
+
var windowReturn = (candles, index, lookbackBars) => {
|
|
69
|
+
const previous = candles[index - lookbackBars];
|
|
70
|
+
const current = candles[index];
|
|
71
|
+
return previous && previous.close > 0 ? (current.close - previous.close) / previous.close : null;
|
|
72
|
+
};
|
|
73
|
+
var classifyBtcAltRegime = ({
|
|
74
|
+
btcReturn24h,
|
|
75
|
+
altBasketReturn24h,
|
|
76
|
+
btcVsAltReturn24h
|
|
77
|
+
}) => {
|
|
78
|
+
if (btcReturn24h == null || altBasketReturn24h == null || btcVsAltReturn24h == null) {
|
|
79
|
+
return "unknown";
|
|
80
|
+
}
|
|
81
|
+
if (btcReturn24h < -0.015 && altBasketReturn24h < -0.025) {
|
|
82
|
+
return "risk_off";
|
|
83
|
+
}
|
|
84
|
+
if (btcReturn24h > 5e-3 && altBasketReturn24h > 5e-3 && altBasketReturn24h > btcReturn24h) {
|
|
85
|
+
return "risk_on";
|
|
86
|
+
}
|
|
87
|
+
if (btcVsAltReturn24h > 5e-3) return "btc_lead";
|
|
88
|
+
if (btcVsAltReturn24h < -5e-3) return "alt_lead";
|
|
89
|
+
return "neutral";
|
|
90
|
+
};
|
|
91
|
+
var normalizeMarketFeatureInterval = (value) => {
|
|
92
|
+
const normalized = String(value || "15m").trim().toLowerCase();
|
|
93
|
+
if (normalized === "1" || normalized === "1m") return "1m";
|
|
94
|
+
if (normalized === "5" || normalized === "5m") return "5m";
|
|
95
|
+
if (normalized === "15" || normalized === "15m") return "15m";
|
|
96
|
+
if (normalized === "60" || normalized === "1h") return "1h";
|
|
97
|
+
return "15m";
|
|
98
|
+
};
|
|
99
|
+
var normalizeBinanceSymbols = (value) => String(value || "").split(",").map((item) => item.trim().toUpperCase()).filter(Boolean);
|
|
100
|
+
var selectBreadthUniverseFromTickers = (tickers, limit) => tickers.filter(
|
|
101
|
+
(ticker) => ticker.symbol.endsWith("USDT") && ticker.symbol !== "BTCUSDT" && !STABLE_QUOTE_SYMBOLS.has(ticker.symbol) && Number.isFinite(ticker.turnover24h) && ticker.turnover24h > 0
|
|
102
|
+
).sort((a, b) => b.turnover24h - a.turnover24h).slice(0, Math.max(0, limit)).map((ticker) => ticker.symbol);
|
|
103
|
+
var estimateBinanceMarketDataVolume = ({
|
|
104
|
+
symbols,
|
|
105
|
+
days,
|
|
106
|
+
interval,
|
|
107
|
+
includeAggTrades,
|
|
108
|
+
includeBreadth,
|
|
109
|
+
breadthLimit
|
|
110
|
+
}) => {
|
|
111
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
112
|
+
const bucketRowsPerSymbol = Math.ceil(days * 864e5 / intervalMs);
|
|
113
|
+
const aggTradeBucketRows = includeAggTrades ? symbols.length * bucketRowsPerSymbol : 0;
|
|
114
|
+
const breadthSymbols = includeBreadth ? Math.max(0, breadthLimit) : 0;
|
|
115
|
+
const breadthCandleRows = breadthSymbols * bucketRowsPerSymbol;
|
|
116
|
+
const breadthRows = includeBreadth ? bucketRowsPerSymbol : 0;
|
|
117
|
+
return {
|
|
118
|
+
interval,
|
|
119
|
+
days,
|
|
120
|
+
symbols: symbols.length,
|
|
121
|
+
bucketRowsPerSymbol,
|
|
122
|
+
aggTradeBucketRows,
|
|
123
|
+
breadthSymbols,
|
|
124
|
+
breadthCandleRows,
|
|
125
|
+
breadthRows,
|
|
126
|
+
estimatedStoredRows: aggTradeBucketRows + breadthRows
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
var aggregateAggTradesToRows = ({
|
|
130
|
+
symbol,
|
|
131
|
+
interval,
|
|
132
|
+
trades,
|
|
133
|
+
source = "binance_agg_trades"
|
|
134
|
+
}) => {
|
|
135
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
136
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
137
|
+
for (const trade of trades) {
|
|
138
|
+
const bucketTs = Math.floor(trade.timestamp / intervalMs) * intervalMs;
|
|
139
|
+
const row = buckets.get(bucketTs) ?? {
|
|
140
|
+
symbol,
|
|
141
|
+
interval,
|
|
142
|
+
ts: new Date(bucketTs),
|
|
143
|
+
trades: 0,
|
|
144
|
+
buyBaseVolume: 0,
|
|
145
|
+
sellBaseVolume: 0,
|
|
146
|
+
buyQuoteVolume: 0,
|
|
147
|
+
sellQuoteVolume: 0,
|
|
148
|
+
netBaseDelta: 0,
|
|
149
|
+
netQuoteDelta: 0,
|
|
150
|
+
buyPressurePct: null,
|
|
151
|
+
source
|
|
152
|
+
};
|
|
153
|
+
const quote = trade.price * trade.quantity;
|
|
154
|
+
const isAggressiveSell = trade.isBuyerMaker;
|
|
155
|
+
row.trades += 1;
|
|
156
|
+
if (isAggressiveSell) {
|
|
157
|
+
row.sellBaseVolume = (row.sellBaseVolume ?? 0) + trade.quantity;
|
|
158
|
+
row.sellQuoteVolume = (row.sellQuoteVolume ?? 0) + quote;
|
|
159
|
+
} else {
|
|
160
|
+
row.buyBaseVolume = (row.buyBaseVolume ?? 0) + trade.quantity;
|
|
161
|
+
row.buyQuoteVolume = (row.buyQuoteVolume ?? 0) + quote;
|
|
162
|
+
}
|
|
163
|
+
row.netBaseDelta = (row.buyBaseVolume ?? 0) - (row.sellBaseVolume ?? 0);
|
|
164
|
+
row.netQuoteDelta = (row.buyQuoteVolume ?? 0) - (row.sellQuoteVolume ?? 0);
|
|
165
|
+
row.buyPressurePct = safeDivide(
|
|
166
|
+
row.buyBaseVolume ?? 0,
|
|
167
|
+
(row.buyBaseVolume ?? 0) + (row.sellBaseVolume ?? 0)
|
|
168
|
+
);
|
|
169
|
+
buckets.set(bucketTs, row);
|
|
170
|
+
}
|
|
171
|
+
return [...buckets.values()].sort((a, b) => a.ts.getTime() - b.ts.getTime());
|
|
172
|
+
};
|
|
173
|
+
var buildKlineTradeFlowRows = ({
|
|
174
|
+
symbol,
|
|
175
|
+
interval,
|
|
176
|
+
candles,
|
|
177
|
+
source = "binance_klines"
|
|
178
|
+
}) => candles.map((candle) => {
|
|
179
|
+
const buyBaseVolume = candle.takerBuyBaseVolume;
|
|
180
|
+
const buyQuoteVolume = candle.takerBuyQuoteVolume;
|
|
181
|
+
if (buyBaseVolume == null || buyQuoteVolume == null || !Number.isFinite(buyBaseVolume) || !Number.isFinite(buyQuoteVolume)) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const sellBaseVolume = candle.takerSellBaseVolume != null && Number.isFinite(candle.takerSellBaseVolume) ? candle.takerSellBaseVolume : Math.max(0, candle.volume - buyBaseVolume);
|
|
185
|
+
const sellQuoteVolume = candle.takerSellQuoteVolume != null && Number.isFinite(candle.takerSellQuoteVolume) ? candle.takerSellQuoteVolume : Math.max(0, candle.turnover - buyQuoteVolume);
|
|
186
|
+
const trades = candle.trades != null && Number.isFinite(candle.trades) ? Math.max(0, Math.trunc(candle.trades)) : 0;
|
|
187
|
+
return {
|
|
188
|
+
symbol,
|
|
189
|
+
interval,
|
|
190
|
+
ts: new Date(candle.timestamp),
|
|
191
|
+
trades,
|
|
192
|
+
buyBaseVolume,
|
|
193
|
+
sellBaseVolume,
|
|
194
|
+
buyQuoteVolume,
|
|
195
|
+
sellQuoteVolume,
|
|
196
|
+
netBaseDelta: buyBaseVolume - sellBaseVolume,
|
|
197
|
+
netQuoteDelta: buyQuoteVolume - sellQuoteVolume,
|
|
198
|
+
buyPressurePct: safeDivide(
|
|
199
|
+
buyBaseVolume,
|
|
200
|
+
buyBaseVolume + sellBaseVolume
|
|
201
|
+
),
|
|
202
|
+
source
|
|
203
|
+
};
|
|
204
|
+
}).filter((row) => row != null);
|
|
205
|
+
var buildMarketBreadthRows = ({
|
|
206
|
+
universe,
|
|
207
|
+
interval,
|
|
208
|
+
candlesBySymbol,
|
|
209
|
+
btcCandles,
|
|
210
|
+
source = "binance_klines"
|
|
211
|
+
}) => {
|
|
212
|
+
const timestamps = /* @__PURE__ */ new Set();
|
|
213
|
+
const indexedSymbols = Object.values(candlesBySymbol).map((candles) => ({
|
|
214
|
+
candles,
|
|
215
|
+
byTimestamp: new Map(
|
|
216
|
+
candles.map((candle, index) => [candle.timestamp, index])
|
|
217
|
+
),
|
|
218
|
+
turnoverPrefix: buildPrefixSum(
|
|
219
|
+
candles.map((candle) => Math.max(0, candle.turnover ?? 0))
|
|
220
|
+
),
|
|
221
|
+
closePrefix: buildPrefixSum(candles.map((candle) => candle.close))
|
|
222
|
+
}));
|
|
223
|
+
const btcIndexed = btcCandles ? {
|
|
224
|
+
candles: btcCandles,
|
|
225
|
+
byTimestamp: new Map(
|
|
226
|
+
btcCandles.map((candle, index) => [candle.timestamp, index])
|
|
227
|
+
),
|
|
228
|
+
turnoverPrefix: buildPrefixSum(
|
|
229
|
+
btcCandles.map((candle) => Math.max(0, candle.turnover ?? 0))
|
|
230
|
+
)
|
|
231
|
+
} : null;
|
|
232
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
233
|
+
const bars1h = Math.max(1, Math.round(36e5 / intervalMs));
|
|
234
|
+
const bars4h = Math.max(1, Math.round(144e5 / intervalMs));
|
|
235
|
+
const bars24h = Math.max(1, Math.round(864e5 / intervalMs));
|
|
236
|
+
for (const candles of Object.values(candlesBySymbol)) {
|
|
237
|
+
for (const candle of candles) timestamps.add(candle.timestamp);
|
|
238
|
+
}
|
|
239
|
+
return [...timestamps].sort((a, b) => a - b).map((timestamp) => {
|
|
240
|
+
const returns = [];
|
|
241
|
+
const weightedReturns = [];
|
|
242
|
+
let advancers = 0;
|
|
243
|
+
let decliners = 0;
|
|
244
|
+
let unchanged = 0;
|
|
245
|
+
let aboveMa20 = 0;
|
|
246
|
+
let aboveMa20Eligible = 0;
|
|
247
|
+
let aboveMa50 = 0;
|
|
248
|
+
let aboveMa50Eligible = 0;
|
|
249
|
+
const altReturns1h = [];
|
|
250
|
+
const altReturns4h = [];
|
|
251
|
+
const altReturns24h = [];
|
|
252
|
+
let altTurnover1h = 0;
|
|
253
|
+
let altTurnover24h = 0;
|
|
254
|
+
let previousAltTurnover24h = 0;
|
|
255
|
+
for (const indexed of indexedSymbols) {
|
|
256
|
+
const { candles, byTimestamp, turnoverPrefix, closePrefix } = indexed;
|
|
257
|
+
const index = byTimestamp.get(timestamp);
|
|
258
|
+
if (index == null) continue;
|
|
259
|
+
const candle = candles[index];
|
|
260
|
+
const previous = candles[index - 1];
|
|
261
|
+
const ret = previous && previous.close > 0 ? (candle.close - previous.close) / previous.close : 0;
|
|
262
|
+
if (ret > 0) advancers += 1;
|
|
263
|
+
else if (ret < 0) decliners += 1;
|
|
264
|
+
else unchanged += 1;
|
|
265
|
+
returns.push(ret);
|
|
266
|
+
weightedReturns.push({
|
|
267
|
+
value: ret,
|
|
268
|
+
weight: Math.max(0, candle.turnover ?? 0)
|
|
269
|
+
});
|
|
270
|
+
const ma20Start = index - 19;
|
|
271
|
+
if (ma20Start >= 0) {
|
|
272
|
+
aboveMa20Eligible += 1;
|
|
273
|
+
const ma20 = sumPrefixRange(closePrefix, ma20Start, index) / 20;
|
|
274
|
+
if (candle.close > ma20) aboveMa20 += 1;
|
|
275
|
+
}
|
|
276
|
+
const ma50Start = index - 49;
|
|
277
|
+
if (ma50Start >= 0) {
|
|
278
|
+
aboveMa50Eligible += 1;
|
|
279
|
+
const ma50 = sumPrefixRange(closePrefix, ma50Start, index) / 50;
|
|
280
|
+
if (candle.close > ma50) aboveMa50 += 1;
|
|
281
|
+
}
|
|
282
|
+
const altReturn1h = windowReturn(candles, index, bars1h);
|
|
283
|
+
const altReturn4h = windowReturn(candles, index, bars4h);
|
|
284
|
+
const altReturn24h = windowReturn(candles, index, bars24h);
|
|
285
|
+
if (altReturn1h != null) altReturns1h.push(altReturn1h);
|
|
286
|
+
if (altReturn4h != null) altReturns4h.push(altReturn4h);
|
|
287
|
+
if (altReturn24h != null) altReturns24h.push(altReturn24h);
|
|
288
|
+
altTurnover1h += sumPrefixRange(
|
|
289
|
+
turnoverPrefix,
|
|
290
|
+
index - bars1h + 1,
|
|
291
|
+
index
|
|
292
|
+
);
|
|
293
|
+
altTurnover24h += sumPrefixRange(
|
|
294
|
+
turnoverPrefix,
|
|
295
|
+
index - bars24h + 1,
|
|
296
|
+
index
|
|
297
|
+
);
|
|
298
|
+
previousAltTurnover24h += sumPrefixRange(
|
|
299
|
+
turnoverPrefix,
|
|
300
|
+
index - bars24h * 2 + 1,
|
|
301
|
+
index - bars24h
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
const weightSum = weightedReturns.reduce(
|
|
305
|
+
(sum, item) => sum + item.weight,
|
|
306
|
+
0
|
|
307
|
+
);
|
|
308
|
+
const volumeWeightedReturn = weightSum > 0 ? weightedReturns.reduce(
|
|
309
|
+
(sum, item) => sum + item.value * item.weight,
|
|
310
|
+
0
|
|
311
|
+
) / weightSum : null;
|
|
312
|
+
const btcIndex = btcIndexed?.byTimestamp.get(timestamp);
|
|
313
|
+
const btcReturn1h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars1h) : null;
|
|
314
|
+
const btcReturn4h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars4h) : null;
|
|
315
|
+
const btcReturn24h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars24h) : null;
|
|
316
|
+
const btcTurnover1h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
317
|
+
btcIndexed.turnoverPrefix,
|
|
318
|
+
btcIndex - bars1h + 1,
|
|
319
|
+
btcIndex
|
|
320
|
+
) : null;
|
|
321
|
+
const btcTurnover24h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
322
|
+
btcIndexed.turnoverPrefix,
|
|
323
|
+
btcIndex - bars24h + 1,
|
|
324
|
+
btcIndex
|
|
325
|
+
) : null;
|
|
326
|
+
const previousBtcTurnover24h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
327
|
+
btcIndexed.turnoverPrefix,
|
|
328
|
+
btcIndex - bars24h * 2 + 1,
|
|
329
|
+
btcIndex - bars24h
|
|
330
|
+
) : null;
|
|
331
|
+
const altBasketReturn1h = mean(altReturns1h);
|
|
332
|
+
const altBasketReturn4h = mean(altReturns4h);
|
|
333
|
+
const altBasketReturn24h = mean(altReturns24h);
|
|
334
|
+
const btcVsAltReturn1h = btcReturn1h == null || altBasketReturn1h == null ? null : btcReturn1h - altBasketReturn1h;
|
|
335
|
+
const btcVsAltReturn4h = btcReturn4h == null || altBasketReturn4h == null ? null : btcReturn4h - altBasketReturn4h;
|
|
336
|
+
const btcVsAltReturn24h = btcReturn24h == null || altBasketReturn24h == null ? null : btcReturn24h - altBasketReturn24h;
|
|
337
|
+
const btcTurnoverShare1h = btcTurnover1h == null ? null : safeDivide(btcTurnover1h, btcTurnover1h + altTurnover1h);
|
|
338
|
+
const btcTurnoverShare24h = btcTurnover24h == null ? null : safeDivide(btcTurnover24h, btcTurnover24h + altTurnover24h);
|
|
339
|
+
const previousBtcTurnoverShare24h = previousBtcTurnover24h == null ? null : safeDivide(
|
|
340
|
+
previousBtcTurnover24h,
|
|
341
|
+
previousBtcTurnover24h + previousAltTurnover24h
|
|
342
|
+
);
|
|
343
|
+
const btcTurnoverShareChange24h = btcTurnoverShare24h == null || previousBtcTurnoverShare24h == null ? null : btcTurnoverShare24h - previousBtcTurnoverShare24h;
|
|
344
|
+
return {
|
|
345
|
+
universe,
|
|
346
|
+
interval,
|
|
347
|
+
ts: new Date(timestamp),
|
|
348
|
+
symbolsCount: returns.length,
|
|
349
|
+
advancers,
|
|
350
|
+
decliners,
|
|
351
|
+
unchanged,
|
|
352
|
+
advanceDeclineRatio: safeDivide(advancers, decliners || 1),
|
|
353
|
+
pctAboveMa20: safeDivide(aboveMa20, aboveMa20Eligible),
|
|
354
|
+
pctAboveMa50: safeDivide(aboveMa50, aboveMa50Eligible),
|
|
355
|
+
equalWeightedReturn: mean(returns),
|
|
356
|
+
volumeWeightedReturn,
|
|
357
|
+
dispersion: standardDeviation(returns),
|
|
358
|
+
btcReturn1h,
|
|
359
|
+
btcReturn4h,
|
|
360
|
+
btcReturn24h,
|
|
361
|
+
altBasketReturn1h,
|
|
362
|
+
altBasketReturn4h,
|
|
363
|
+
altBasketReturn24h,
|
|
364
|
+
btcVsAltReturn1h,
|
|
365
|
+
btcVsAltReturn4h,
|
|
366
|
+
btcVsAltReturn24h,
|
|
367
|
+
btcTurnoverShare1h,
|
|
368
|
+
btcTurnoverShare24h,
|
|
369
|
+
btcTurnoverShareChange24h,
|
|
370
|
+
altVolToBtcVol24h: btcTurnover24h == null ? null : safeDivide(altTurnover24h, btcTurnover24h),
|
|
371
|
+
altDispersion24h: standardDeviation(altReturns24h),
|
|
372
|
+
btcAltRegime: classifyBtcAltRegime({
|
|
373
|
+
btcReturn24h,
|
|
374
|
+
altBasketReturn24h,
|
|
375
|
+
btcVsAltReturn24h
|
|
376
|
+
}),
|
|
377
|
+
source
|
|
378
|
+
};
|
|
379
|
+
}).filter((row) => row.symbolsCount > 0);
|
|
380
|
+
};
|
|
381
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
382
|
+
0 && (module.exports = {
|
|
383
|
+
MARKET_FEATURE_INTERVAL_MS,
|
|
384
|
+
aggregateAggTradesToRows,
|
|
385
|
+
buildKlineTradeFlowRows,
|
|
386
|
+
buildMarketBreadthRows,
|
|
387
|
+
classifyBtcAltRegime,
|
|
388
|
+
estimateBinanceMarketDataVolume,
|
|
389
|
+
normalizeBinanceSymbols,
|
|
390
|
+
normalizeMarketFeatureInterval,
|
|
391
|
+
selectBreadthUniverseFromTickers
|
|
392
|
+
});
|