@tradejs/core 1.0.0

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.
Files changed (68) hide show
  1. package/README.md +60 -0
  2. package/dist/api.d.mts +7 -0
  3. package/dist/api.d.ts +7 -0
  4. package/dist/api.js +64 -0
  5. package/dist/api.mjs +39 -0
  6. package/dist/async.d.mts +4 -0
  7. package/dist/async.d.ts +4 -0
  8. package/dist/async.js +48 -0
  9. package/dist/async.mjs +20 -0
  10. package/dist/backtest.d.mts +45 -0
  11. package/dist/backtest.d.ts +45 -0
  12. package/dist/backtest.js +574 -0
  13. package/dist/backtest.mjs +355 -0
  14. package/dist/chunk-AYC2QVKI.mjs +35 -0
  15. package/dist/chunk-JG2QPVAV.mjs +190 -0
  16. package/dist/chunk-LIGD3WWX.mjs +1545 -0
  17. package/dist/chunk-M7QGVZ3J.mjs +61 -0
  18. package/dist/chunk-NQ7D3T4E.mjs +10 -0
  19. package/dist/chunk-PXLXXXLA.mjs +67 -0
  20. package/dist/config.d.mts +14 -0
  21. package/dist/config.d.ts +14 -0
  22. package/dist/config.js +49 -0
  23. package/dist/config.mjs +21 -0
  24. package/dist/constants.d.mts +41 -0
  25. package/dist/constants.d.ts +41 -0
  26. package/dist/constants.js +238 -0
  27. package/dist/constants.mjs +50 -0
  28. package/dist/data.d.mts +9 -0
  29. package/dist/data.d.ts +9 -0
  30. package/dist/data.js +100 -0
  31. package/dist/data.mjs +12 -0
  32. package/dist/figures.d.mts +103 -0
  33. package/dist/figures.d.ts +103 -0
  34. package/dist/figures.js +274 -0
  35. package/dist/figures.mjs +239 -0
  36. package/dist/indicators-x3xKl3_W.d.mts +90 -0
  37. package/dist/indicators-x3xKl3_W.d.ts +90 -0
  38. package/dist/indicators.d.mts +124 -0
  39. package/dist/indicators.d.ts +124 -0
  40. package/dist/indicators.js +1631 -0
  41. package/dist/indicators.mjs +66 -0
  42. package/dist/json.d.mts +3 -0
  43. package/dist/json.d.ts +3 -0
  44. package/dist/json.js +34 -0
  45. package/dist/json.mjs +7 -0
  46. package/dist/math.d.mts +35 -0
  47. package/dist/math.d.ts +35 -0
  48. package/dist/math.js +98 -0
  49. package/dist/math.mjs +38 -0
  50. package/dist/pine.d.mts +29 -0
  51. package/dist/pine.d.ts +29 -0
  52. package/dist/pine.js +59 -0
  53. package/dist/pine.mjs +29 -0
  54. package/dist/strategies.d.mts +104 -0
  55. package/dist/strategies.d.ts +104 -0
  56. package/dist/strategies.js +1080 -0
  57. package/dist/strategies.mjs +390 -0
  58. package/dist/tickers.d.mts +7 -0
  59. package/dist/tickers.d.ts +7 -0
  60. package/dist/tickers.js +166 -0
  61. package/dist/tickers.mjs +125 -0
  62. package/dist/time-DEyFa2vI.d.mts +11 -0
  63. package/dist/time-DEyFa2vI.d.ts +11 -0
  64. package/dist/time.d.mts +2 -0
  65. package/dist/time.d.ts +2 -0
  66. package/dist/time.js +58 -0
  67. package/dist/time.mjs +15 -0
  68. package/package.json +99 -0
@@ -0,0 +1,390 @@
1
+ import {
2
+ uuid
3
+ } from "./chunk-NQ7D3T4E.mjs";
4
+ import {
5
+ createIndicators
6
+ } from "./chunk-LIGD3WWX.mjs";
7
+ import "./chunk-AYC2QVKI.mjs";
8
+ import {
9
+ getTimestamp
10
+ } from "./chunk-PXLXXXLA.mjs";
11
+ import {
12
+ FEE_PERCENT
13
+ } from "./chunk-JG2QPVAV.mjs";
14
+ import "./chunk-M7QGVZ3J.mjs";
15
+
16
+ // src/utils/strategyHelpers/indicators.ts
17
+ var buildDefaultIndicatorPeriods = (config) => ({
18
+ maFast: config.MA_FAST,
19
+ maMedium: config.MA_MEDIUM,
20
+ maSlow: config.MA_SLOW,
21
+ obvSma: config.OBV_SMA,
22
+ atr: config.ATR,
23
+ atrPctShort: config.ATR_PCT_SHORT,
24
+ atrPctLong: config.ATR_PCT_LONG,
25
+ bb: config.BB,
26
+ bbStd: config.BB_STD,
27
+ macdFast: config.MACD_FAST,
28
+ macdSlow: config.MACD_SLOW,
29
+ macdSignal: config.MACD_SIGNAL,
30
+ levelLookback: config.LEVEL_LOOKBACK,
31
+ levelDelay: config.LEVEL_DELAY
32
+ });
33
+ var createStrategyIndicatorsState = ({
34
+ env,
35
+ data,
36
+ btcData,
37
+ btcBinanceData,
38
+ btcCoinbaseData,
39
+ periods
40
+ }) => {
41
+ let controller = env === "BACKTEST" ? createIndicators(data, btcData, {
42
+ periods,
43
+ btcBinanceData,
44
+ btcCoinbaseData
45
+ }) : null;
46
+ let currentBarPair;
47
+ const withSnapshot = (value) => Object.assign(value, {
48
+ snapshot: () => value.result()
49
+ });
50
+ const applyBar = (candle, btcCandle) => {
51
+ if (!controller) return;
52
+ controller.next(candle, btcCandle);
53
+ };
54
+ const ensureControllerInitialized = () => {
55
+ if (controller) return withSnapshot(controller);
56
+ controller = createIndicators(data.slice(0, -1), btcData.slice(0, -1), {
57
+ periods,
58
+ btcBinanceData,
59
+ btcCoinbaseData
60
+ });
61
+ const lastCandle = data[data.length - 1];
62
+ const lastBtcCandle = btcData[btcData.length - 1];
63
+ if (lastCandle && lastBtcCandle) {
64
+ controller.next(lastCandle, lastBtcCandle);
65
+ }
66
+ return withSnapshot(controller);
67
+ };
68
+ return {
69
+ isInitialized: () => controller != null,
70
+ setCurrentBar: (candle, btcCandle) => {
71
+ currentBarPair = { candle, btcCandle };
72
+ },
73
+ onBar: (candle, btcCandle) => {
74
+ const resolvedCandle = candle ?? currentBarPair?.candle;
75
+ const resolvedBtcCandle = btcCandle ?? currentBarPair?.btcCandle;
76
+ if (!resolvedCandle || !resolvedBtcCandle) return;
77
+ applyBar(resolvedCandle, resolvedBtcCandle);
78
+ },
79
+ next: (candle, btcCandle) => {
80
+ if (!controller) return void 0;
81
+ return controller.next(candle, btcCandle);
82
+ },
83
+ // Lazy bootstrap for live mode: initialize on history before current bar and then apply current bar once.
84
+ ensureInitializedWithCurrentBar: ensureControllerInitialized,
85
+ snapshot: () => ensureControllerInitialized().snapshot(),
86
+ latestNumber: (key) => {
87
+ const snapshot = ensureControllerInitialized().snapshot();
88
+ const value = snapshot?.[key];
89
+ if (!Array.isArray(value) || value.length === 0) {
90
+ return void 0;
91
+ }
92
+ const last = value[value.length - 1];
93
+ return typeof last === "number" ? last : void 0;
94
+ }
95
+ };
96
+ };
97
+
98
+ // src/utils/strategyHelpers/market.ts
99
+ var getStrategyMarketSnapshot = async ({
100
+ env,
101
+ connector,
102
+ symbol,
103
+ interval,
104
+ cachedData,
105
+ preloadStart,
106
+ backtestPriceMode = "mid"
107
+ }) => {
108
+ const fullData = env === "BACKTEST" ? cachedData : await connector.kline({
109
+ symbol,
110
+ start: preloadStart,
111
+ end: getTimestamp(),
112
+ cacheOnly: false,
113
+ interval
114
+ });
115
+ const lastCandle = fullData[fullData.length - 1];
116
+ let currentPrice = lastCandle.close;
117
+ if (env === "BACKTEST") {
118
+ if (backtestPriceMode === "mid") {
119
+ currentPrice = (lastCandle.open + lastCandle.close) / 2;
120
+ } else if (backtestPriceMode === "open") {
121
+ currentPrice = lastCandle.open;
122
+ } else if (backtestPriceMode === "rand") {
123
+ const min = Math.min(lastCandle.low, lastCandle.high);
124
+ const max = Math.max(lastCandle.low, lastCandle.high);
125
+ currentPrice = min + Math.random() * (max - min);
126
+ }
127
+ }
128
+ return {
129
+ fullData,
130
+ lastCandle,
131
+ timestamp: lastCandle.timestamp,
132
+ currentPrice
133
+ };
134
+ };
135
+ var calculateRiskRatio = ({
136
+ direction,
137
+ currentPrice,
138
+ takeProfitPrice,
139
+ stopLossPrice
140
+ }) => {
141
+ const isLong = direction === "LONG";
142
+ const reward = isLong ? takeProfitPrice - currentPrice : currentPrice - takeProfitPrice;
143
+ const risk = isLong ? currentPrice - stopLossPrice : stopLossPrice - currentPrice;
144
+ return risk > 0 ? reward / risk : 0;
145
+ };
146
+ var getDirectionalTpSlPrices = ({
147
+ price,
148
+ direction,
149
+ takeProfitDelta,
150
+ stopLossDelta,
151
+ unit = "percent",
152
+ maxLossValue,
153
+ feePercent = FEE_PERCENT
154
+ }) => {
155
+ const deltaFactor = unit === "percent" ? 100 : 1;
156
+ const tp = takeProfitDelta / deltaFactor;
157
+ const sl = stopLossDelta / deltaFactor;
158
+ const isLong = direction === "LONG";
159
+ const stopLossPrice = isLong ? price * (1 - sl) : price * (1 + sl);
160
+ const takeProfitPrice = isLong ? price * (1 + tp) : price * (1 - tp);
161
+ const riskRatio = calculateRiskRatio({
162
+ direction,
163
+ currentPrice: price,
164
+ takeProfitPrice,
165
+ stopLossPrice
166
+ });
167
+ const slPercent = unit === "percent" ? stopLossDelta : stopLossDelta * 100;
168
+ const qty = typeof maxLossValue === "number" && Number.isFinite(maxLossValue) && maxLossValue > 0 ? maxLossValue / (price * (slPercent + feePercent) / 100) : void 0;
169
+ return {
170
+ stopLossPrice,
171
+ takeProfitPrice,
172
+ riskRatio,
173
+ qty
174
+ };
175
+ };
176
+
177
+ // src/utils/strategyHelpers/state.ts
178
+ var createLastTradeController = ({
179
+ env,
180
+ enabled = env ? env === "BACKTEST" : true,
181
+ cooldownMs = 864e5
182
+ }) => {
183
+ let lastTradeTimestamp = null;
184
+ return {
185
+ isInCooldown: (timestamp) => Boolean(
186
+ enabled && lastTradeTimestamp != null && timestamp <= lastTradeTimestamp + cooldownMs
187
+ ),
188
+ markTrade: (timestamp) => {
189
+ if (!enabled) return;
190
+ lastTradeTimestamp = timestamp;
191
+ },
192
+ getLastTradeTimestamp: () => lastTradeTimestamp
193
+ };
194
+ };
195
+
196
+ // src/utils/strategyHelpers/signalBuilders.ts
197
+ var mapAiRuntimeFromConfig = (config, overrides = {}) => ({
198
+ enabled: Boolean(config.AI_ENABLED ?? true),
199
+ minQuality: Number(config.MIN_AI_QUALITY ?? 4),
200
+ ...overrides
201
+ });
202
+ var mapMlRuntimeFromConfig = (config, overrides = {}) => ({
203
+ enabled: Boolean(config.ML_ENABLED ?? true),
204
+ mlThreshold: Number(config.ML_THRESHOLD ?? 0),
205
+ ...overrides
206
+ });
207
+ var buildStrategySignal = ({
208
+ signalId,
209
+ strategy,
210
+ symbol,
211
+ interval,
212
+ direction,
213
+ timestamp,
214
+ prices,
215
+ figures = {},
216
+ indicators = {},
217
+ additionalIndicators,
218
+ isConfigFromBacktest
219
+ }) => ({
220
+ signalId,
221
+ strategy,
222
+ symbol,
223
+ interval,
224
+ direction,
225
+ timestamp,
226
+ figures,
227
+ prices,
228
+ indicators,
229
+ additionalIndicators,
230
+ isConfigFromBacktest
231
+ });
232
+ var buildEntrySignalDecision = ({
233
+ code,
234
+ entryContext,
235
+ figures,
236
+ indicators,
237
+ additionalIndicators,
238
+ signalId,
239
+ orderPlan,
240
+ runtime
241
+ }) => ({
242
+ kind: "entry",
243
+ code,
244
+ entryContext,
245
+ signal: buildStrategySignal({
246
+ signalId: signalId ?? uuid(),
247
+ strategy: entryContext.strategy,
248
+ symbol: entryContext.symbol,
249
+ interval: entryContext.interval,
250
+ direction: entryContext.direction,
251
+ timestamp: entryContext.timestamp,
252
+ prices: entryContext.prices,
253
+ figures,
254
+ indicators,
255
+ additionalIndicators,
256
+ isConfigFromBacktest: entryContext.isConfigFromBacktest
257
+ }),
258
+ orderPlan,
259
+ runtime
260
+ });
261
+ var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
262
+ var toDefaultEntryCode = (strategy, direction) => `${strategy.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toUpperCase()}_${direction}_ENTRY`;
263
+ var resolveTakeProfitPrice = ({
264
+ direction,
265
+ takeProfits
266
+ }) => {
267
+ if (!Array.isArray(takeProfits) || takeProfits.length === 0) {
268
+ throw new Error("strategyApi.entry requires at least one takeProfit");
269
+ }
270
+ const prices = takeProfits.map((tp) => tp?.price).filter((price) => isFiniteNumber(price));
271
+ if (prices.length === 0) {
272
+ throw new Error("strategyApi.entry requires finite takeProfit prices");
273
+ }
274
+ return direction === "LONG" ? Math.max(...prices) : Math.min(...prices);
275
+ };
276
+ var createStrategyAPI = ({
277
+ strategy,
278
+ symbol,
279
+ interval,
280
+ env,
281
+ connector,
282
+ cachedData,
283
+ indicatorsState,
284
+ preloadStart,
285
+ backtestPriceMode,
286
+ isConfigFromBacktest
287
+ }) => {
288
+ const getCurrentPosition = () => connector.getPosition(symbol);
289
+ const isPositionExists = async () => {
290
+ const position = await getCurrentPosition();
291
+ return Boolean(
292
+ position && typeof position.qty === "number" && position.qty > 0
293
+ );
294
+ };
295
+ const getMarketData = async (params = {}) => {
296
+ const resolvedPreloadStart = params.preloadStart ?? preloadStart;
297
+ if (typeof resolvedPreloadStart !== "number") {
298
+ throw new Error("strategyApi.getMarketData requires preloadStart");
299
+ }
300
+ const snapshot = await getStrategyMarketSnapshot({
301
+ env,
302
+ connector,
303
+ symbol,
304
+ interval,
305
+ cachedData,
306
+ preloadStart: resolvedPreloadStart,
307
+ backtestPriceMode: params.backtestPriceMode ?? backtestPriceMode
308
+ });
309
+ return snapshot;
310
+ };
311
+ return {
312
+ skip: (code) => ({ kind: "skip", code }),
313
+ entry: async ({
314
+ code,
315
+ direction,
316
+ figures,
317
+ indicators,
318
+ additionalIndicators,
319
+ signalId,
320
+ orderPlan,
321
+ runtime
322
+ }) => {
323
+ const marketData = await getMarketData();
324
+ const currentPrice = marketData.currentPrice;
325
+ const timestamp = marketData.timestamp;
326
+ const stopLossPrice = orderPlan.stopLossPrice;
327
+ const takeProfitPrice = resolveTakeProfitPrice({
328
+ direction,
329
+ takeProfits: orderPlan.takeProfits
330
+ });
331
+ if (!isFiniteNumber(stopLossPrice)) {
332
+ throw new Error(
333
+ "strategyApi.entry requires finite orderPlan.stopLossPrice"
334
+ );
335
+ }
336
+ const resolvedCode = code ?? toDefaultEntryCode(String(strategy), direction);
337
+ const riskRatio = calculateRiskRatio({
338
+ direction,
339
+ currentPrice,
340
+ takeProfitPrice,
341
+ stopLossPrice
342
+ });
343
+ return buildEntrySignalDecision({
344
+ code: resolvedCode,
345
+ entryContext: {
346
+ strategy,
347
+ symbol,
348
+ interval,
349
+ direction,
350
+ timestamp,
351
+ prices: {
352
+ currentPrice,
353
+ takeProfitPrice,
354
+ stopLossPrice,
355
+ riskRatio
356
+ },
357
+ isConfigFromBacktest
358
+ },
359
+ figures,
360
+ indicators,
361
+ additionalIndicators,
362
+ signalId,
363
+ orderPlan,
364
+ runtime
365
+ });
366
+ },
367
+ getMarketData,
368
+ nextIndicators: (candle, btcCandle) => indicatorsState?.next(candle, btcCandle),
369
+ getCurrentPosition,
370
+ isCurrentPositionExists: isPositionExists,
371
+ getDirectionalTpSlPrices: (params) => getDirectionalTpSlPrices(params),
372
+ createLastTradeController: (params) => createLastTradeController({
373
+ env,
374
+ ...params
375
+ })
376
+ };
377
+ };
378
+ export {
379
+ buildDefaultIndicatorPeriods,
380
+ buildEntrySignalDecision,
381
+ buildStrategySignal,
382
+ calculateRiskRatio,
383
+ createLastTradeController,
384
+ createStrategyAPI,
385
+ createStrategyIndicatorsState,
386
+ getDirectionalTpSlPrices,
387
+ getStrategyMarketSnapshot,
388
+ mapAiRuntimeFromConfig,
389
+ mapMlRuntimeFromConfig
390
+ };
@@ -0,0 +1,7 @@
1
+ import { Ticker, Item } from '@tradejs/types';
2
+
3
+ declare const getVolatilityTickers: (data: Ticker[]) => Item[];
4
+ declare const getTopTickers: (data: Ticker[], topN?: number) => Item<Ticker>[];
5
+ declare const normalizeTickerData: (raw: Record<string, string>) => Ticker;
6
+
7
+ export { getTopTickers, getVolatilityTickers, normalizeTickerData };
@@ -0,0 +1,7 @@
1
+ import { Ticker, Item } from '@tradejs/types';
2
+
3
+ declare const getVolatilityTickers: (data: Ticker[]) => Item[];
4
+ declare const getTopTickers: (data: Ticker[], topN?: number) => Item<Ticker>[];
5
+ declare const normalizeTickerData: (raw: Record<string, string>) => Ticker;
6
+
7
+ export { getTopTickers, getVolatilityTickers, normalizeTickerData };
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/tickers.ts
31
+ var tickers_exports = {};
32
+ __export(tickers_exports, {
33
+ getTopTickers: () => getTopTickers,
34
+ getVolatilityTickers: () => getVolatilityTickers,
35
+ normalizeTickerData: () => normalizeTickerData
36
+ });
37
+ module.exports = __toCommonJS(tickers_exports);
38
+
39
+ // src/utils/tickers.ts
40
+ var import_lodash2 = __toESM(require("lodash"));
41
+
42
+ // src/utils/math.ts
43
+ var import_lodash = __toESM(require("lodash"));
44
+ var round = (value, precision = 2) => precision > 0 ? Math.round(value * 10 ** precision) / 10 ** precision : Math.round(value);
45
+
46
+ // src/utils/tickers.ts
47
+ var EXCLUDE_TICKERS = [
48
+ "USDEUSDT",
49
+ "USDCUSDT",
50
+ "USDTUSDT",
51
+ "RLUSDUSDT",
52
+ "PAXGUSDT",
53
+ "XAUTUSDT"
54
+ ];
55
+ var getVolatilityTickers = (data) => {
56
+ const result = [];
57
+ const selected = /* @__PURE__ */ new Set();
58
+ const getBaseSymbol = (symbol) => symbol.replace(/(USDT)$/i, "");
59
+ const byVol24h = [...data].map((coin) => ({
60
+ ...coin,
61
+ volatility24h: Math.abs(coin.price24hPcnt)
62
+ })).sort((a, b) => b.volatility24h - a.volatility24h);
63
+ const byVol1h = [...data].map((coin) => {
64
+ const prev1h = coin.prevPrice1h;
65
+ const last = coin.lastPrice;
66
+ const volatility1h = prev1h ? Math.abs((last - prev1h) / prev1h) : 0;
67
+ return {
68
+ ...coin,
69
+ volatility1h
70
+ };
71
+ }).sort((a, b) => b.volatility1h - a.volatility1h);
72
+ const byVolume = [...data].map((coin) => ({
73
+ ...coin,
74
+ volume24hNum: coin.volume24h
75
+ })).sort((a, b) => b.volume24hNum - a.volume24hNum);
76
+ const addTop = (list, category, limit) => {
77
+ for (const coin of list) {
78
+ if (!selected.has(coin.symbol)) {
79
+ selected.add(coin.symbol);
80
+ result.push({
81
+ label: `${getBaseSymbol(coin.symbol)}`,
82
+ value: coin.symbol,
83
+ category
84
+ });
85
+ if (result.length >= limit) break;
86
+ }
87
+ }
88
+ };
89
+ addTop(byVol24h, "volatility24h", 10);
90
+ addTop(byVol1h, "volatility1h", 20);
91
+ addTop(byVolume, "volume", 30);
92
+ return result.slice(0, 30).sort(
93
+ (a, b) => a.category === b.category ? a.value.localeCompare(b.value) : a.category.localeCompare(b.category)
94
+ ).map(({ value, label, category }) => ({
95
+ label,
96
+ value,
97
+ description: category
98
+ }));
99
+ };
100
+ var getTopTickers = (data, topN) => {
101
+ const scores = data.filter(({ symbol }) => {
102
+ if (symbol.includes("BTC") && symbol !== "BTCUSDT") {
103
+ return false;
104
+ }
105
+ if (symbol.startsWith("USD") || !symbol.endsWith("USDT")) {
106
+ return false;
107
+ }
108
+ if (EXCLUDE_TICKERS.includes(symbol)) {
109
+ return false;
110
+ }
111
+ return true;
112
+ }).map((coin) => {
113
+ const volumeMln = coin.volume24h / 1e6;
114
+ return {
115
+ ...coin,
116
+ symbol: coin.symbol,
117
+ volume24h: volumeMln
118
+ };
119
+ });
120
+ const sortedByVlolume = import_lodash2.default.sortBy(scores, (item) => -item.volume24h);
121
+ const items = sortedByVlolume.map(({ symbol, volume24h, ...coin }, i) => ({
122
+ label: symbol.replace(/(USDT)$/i, ""),
123
+ value: symbol,
124
+ description: `volume: ${round(volume24h, 2)}m (#${i + 1})`,
125
+ data: {
126
+ ...coin,
127
+ symbol,
128
+ volume24h
129
+ }
130
+ }));
131
+ return import_lodash2.default.sortBy(topN ? items.slice(0, topN) : items, "label");
132
+ };
133
+ var normalizeTickerData = (raw) => ({
134
+ symbol: raw.symbol,
135
+ lastPrice: parseFloat(raw.lastPrice),
136
+ indexPrice: parseFloat(raw.indexPrice),
137
+ markPrice: parseFloat(raw.markPrice),
138
+ prevPrice24h: parseFloat(raw.prevPrice24h),
139
+ price24hPcnt: parseFloat(raw.price24hPcnt),
140
+ highPrice24h: parseFloat(raw.highPrice24h),
141
+ lowPrice24h: parseFloat(raw.lowPrice24h),
142
+ prevPrice1h: parseFloat(raw.prevPrice1h),
143
+ openInterest: parseFloat(raw.openInterest),
144
+ openInterestValue: parseFloat(raw.openInterestValue),
145
+ turnover24h: parseFloat(raw.turnover24h),
146
+ volume24h: parseFloat(raw.volume24h),
147
+ fundingRate: parseFloat(raw.fundingRate),
148
+ nextFundingTime: parseInt(raw.nextFundingTime),
149
+ predictedDeliveryPrice: raw.predictedDeliveryPrice,
150
+ basisRate: raw.basisRate,
151
+ deliveryFeeRate: raw.deliveryFeeRate,
152
+ deliveryTime: parseInt(raw.deliveryTime),
153
+ ask1Size: parseFloat(raw.ask1Size),
154
+ bid1Price: parseFloat(raw.bid1Price),
155
+ ask1Price: parseFloat(raw.ask1Price),
156
+ bid1Size: parseFloat(raw.bid1Size),
157
+ basis: raw.basis,
158
+ preOpenPrice: raw.preOpenPrice,
159
+ preQty: raw.preQty
160
+ });
161
+ // Annotate the CommonJS export names for ESM import in node:
162
+ 0 && (module.exports = {
163
+ getTopTickers,
164
+ getVolatilityTickers,
165
+ normalizeTickerData
166
+ });
@@ -0,0 +1,125 @@
1
+ import {
2
+ round
3
+ } from "./chunk-AYC2QVKI.mjs";
4
+
5
+ // src/utils/tickers.ts
6
+ import _ from "lodash";
7
+ var EXCLUDE_TICKERS = [
8
+ "USDEUSDT",
9
+ "USDCUSDT",
10
+ "USDTUSDT",
11
+ "RLUSDUSDT",
12
+ "PAXGUSDT",
13
+ "XAUTUSDT"
14
+ ];
15
+ var getVolatilityTickers = (data) => {
16
+ const result = [];
17
+ const selected = /* @__PURE__ */ new Set();
18
+ const getBaseSymbol = (symbol) => symbol.replace(/(USDT)$/i, "");
19
+ const byVol24h = [...data].map((coin) => ({
20
+ ...coin,
21
+ volatility24h: Math.abs(coin.price24hPcnt)
22
+ })).sort((a, b) => b.volatility24h - a.volatility24h);
23
+ const byVol1h = [...data].map((coin) => {
24
+ const prev1h = coin.prevPrice1h;
25
+ const last = coin.lastPrice;
26
+ const volatility1h = prev1h ? Math.abs((last - prev1h) / prev1h) : 0;
27
+ return {
28
+ ...coin,
29
+ volatility1h
30
+ };
31
+ }).sort((a, b) => b.volatility1h - a.volatility1h);
32
+ const byVolume = [...data].map((coin) => ({
33
+ ...coin,
34
+ volume24hNum: coin.volume24h
35
+ })).sort((a, b) => b.volume24hNum - a.volume24hNum);
36
+ const addTop = (list, category, limit) => {
37
+ for (const coin of list) {
38
+ if (!selected.has(coin.symbol)) {
39
+ selected.add(coin.symbol);
40
+ result.push({
41
+ label: `${getBaseSymbol(coin.symbol)}`,
42
+ value: coin.symbol,
43
+ category
44
+ });
45
+ if (result.length >= limit) break;
46
+ }
47
+ }
48
+ };
49
+ addTop(byVol24h, "volatility24h", 10);
50
+ addTop(byVol1h, "volatility1h", 20);
51
+ addTop(byVolume, "volume", 30);
52
+ return result.slice(0, 30).sort(
53
+ (a, b) => a.category === b.category ? a.value.localeCompare(b.value) : a.category.localeCompare(b.category)
54
+ ).map(({ value, label, category }) => ({
55
+ label,
56
+ value,
57
+ description: category
58
+ }));
59
+ };
60
+ var getTopTickers = (data, topN) => {
61
+ const scores = data.filter(({ symbol }) => {
62
+ if (symbol.includes("BTC") && symbol !== "BTCUSDT") {
63
+ return false;
64
+ }
65
+ if (symbol.startsWith("USD") || !symbol.endsWith("USDT")) {
66
+ return false;
67
+ }
68
+ if (EXCLUDE_TICKERS.includes(symbol)) {
69
+ return false;
70
+ }
71
+ return true;
72
+ }).map((coin) => {
73
+ const volumeMln = coin.volume24h / 1e6;
74
+ return {
75
+ ...coin,
76
+ symbol: coin.symbol,
77
+ volume24h: volumeMln
78
+ };
79
+ });
80
+ const sortedByVlolume = _.sortBy(scores, (item) => -item.volume24h);
81
+ const items = sortedByVlolume.map(({ symbol, volume24h, ...coin }, i) => ({
82
+ label: symbol.replace(/(USDT)$/i, ""),
83
+ value: symbol,
84
+ description: `volume: ${round(volume24h, 2)}m (#${i + 1})`,
85
+ data: {
86
+ ...coin,
87
+ symbol,
88
+ volume24h
89
+ }
90
+ }));
91
+ return _.sortBy(topN ? items.slice(0, topN) : items, "label");
92
+ };
93
+ var normalizeTickerData = (raw) => ({
94
+ symbol: raw.symbol,
95
+ lastPrice: parseFloat(raw.lastPrice),
96
+ indexPrice: parseFloat(raw.indexPrice),
97
+ markPrice: parseFloat(raw.markPrice),
98
+ prevPrice24h: parseFloat(raw.prevPrice24h),
99
+ price24hPcnt: parseFloat(raw.price24hPcnt),
100
+ highPrice24h: parseFloat(raw.highPrice24h),
101
+ lowPrice24h: parseFloat(raw.lowPrice24h),
102
+ prevPrice1h: parseFloat(raw.prevPrice1h),
103
+ openInterest: parseFloat(raw.openInterest),
104
+ openInterestValue: parseFloat(raw.openInterestValue),
105
+ turnover24h: parseFloat(raw.turnover24h),
106
+ volume24h: parseFloat(raw.volume24h),
107
+ fundingRate: parseFloat(raw.fundingRate),
108
+ nextFundingTime: parseInt(raw.nextFundingTime),
109
+ predictedDeliveryPrice: raw.predictedDeliveryPrice,
110
+ basisRate: raw.basisRate,
111
+ deliveryFeeRate: raw.deliveryFeeRate,
112
+ deliveryTime: parseInt(raw.deliveryTime),
113
+ ask1Size: parseFloat(raw.ask1Size),
114
+ bid1Price: parseFloat(raw.bid1Price),
115
+ ask1Price: parseFloat(raw.ask1Price),
116
+ bid1Size: parseFloat(raw.bid1Size),
117
+ basis: raw.basis,
118
+ preOpenPrice: raw.preOpenPrice,
119
+ preQty: raw.preQty
120
+ });
121
+ export {
122
+ getTopTickers,
123
+ getVolatilityTickers,
124
+ normalizeTickerData
125
+ };
@@ -0,0 +1,11 @@
1
+ import { OrderLogData, SimpleOrderLogData, KlineChartData, KlineChartItem } from '@tradejs/types';
2
+
3
+ declare const toMs: (ts: number) => number;
4
+ declare const getTimestamp: (days?: number) => number;
5
+ declare const getItemTimestamp: (item: KlineChartItem) => number;
6
+ declare const getDataTimestamp: (data: KlineChartData) => number | null;
7
+ declare const formatUnix: (dt: number) => string;
8
+ declare const getTimeline: (start?: number, end?: number, step?: number) => number[];
9
+ declare const compactOrderLog: (timeline: number[], orderLog: OrderLogData) => SimpleOrderLogData;
10
+
11
+ export { getDataTimestamp as a, getItemTimestamp as b, compactOrderLog as c, getTimestamp as d, formatUnix as f, getTimeline as g, toMs as t };