prab-cli 1.2.6 → 1.2.7
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/index.js +41 -0
- package/dist/lib/crypto/analyzer.js +397 -93
- package/dist/lib/crypto/data-fetcher.js +342 -50
- package/dist/lib/crypto/index.js +12 -1
- package/dist/lib/crypto/signal-generator.js +278 -3
- package/dist/lib/crypto/strategy.js +673 -0
- package/dist/lib/slash-commands.js +6 -0
- package/dist/server/index.js +70 -0
- package/package.json +3 -3
|
@@ -60,42 +60,150 @@ const SYMBOL_MAP = {
|
|
|
60
60
|
wif: "WIFUSDT",
|
|
61
61
|
};
|
|
62
62
|
const BINANCE_API_BASE = "https://api.binance.com/api/v3";
|
|
63
|
+
const BYBIT_API_BASE = "https://api.bybit.com/v5/market";
|
|
64
|
+
const CRYPTOCOMPARE_API_BASE = "https://min-api.cryptocompare.com/data";
|
|
65
|
+
// Map Binance intervals to Bybit intervals
|
|
66
|
+
const BYBIT_INTERVAL_MAP = {
|
|
67
|
+
"1m": "1",
|
|
68
|
+
"5m": "5",
|
|
69
|
+
"15m": "15",
|
|
70
|
+
"1h": "60",
|
|
71
|
+
"4h": "240",
|
|
72
|
+
"1d": "D",
|
|
73
|
+
"1w": "W",
|
|
74
|
+
};
|
|
75
|
+
// Map intervals to CryptoCompare endpoints and params
|
|
76
|
+
const CRYPTOCOMPARE_INTERVAL_MAP = {
|
|
77
|
+
"1m": { endpoint: "histominute", aggregate: 1 },
|
|
78
|
+
"5m": { endpoint: "histominute", aggregate: 5 },
|
|
79
|
+
"15m": { endpoint: "histominute", aggregate: 15 },
|
|
80
|
+
"1h": { endpoint: "histohour", aggregate: 1 },
|
|
81
|
+
"4h": { endpoint: "histohour", aggregate: 4 },
|
|
82
|
+
"1d": { endpoint: "histoday", aggregate: 1 },
|
|
83
|
+
"1w": { endpoint: "histoday", aggregate: 7 },
|
|
84
|
+
};
|
|
63
85
|
// Cache for valid Binance symbols
|
|
64
86
|
let cachedSymbols = null;
|
|
65
87
|
let cacheTimestamp = 0;
|
|
66
88
|
const CACHE_DURATION = 1000 * 60 * 60; // 1 hour cache
|
|
67
89
|
/**
|
|
68
|
-
* Fetch all valid USDT trading pairs from
|
|
90
|
+
* Fetch all valid USDT trading pairs from Bybit (fallback)
|
|
69
91
|
*/
|
|
70
|
-
async function
|
|
71
|
-
// Return cached symbols if still valid
|
|
72
|
-
if (cachedSymbols && Date.now() - cacheTimestamp < CACHE_DURATION) {
|
|
73
|
-
return cachedSymbols;
|
|
74
|
-
}
|
|
92
|
+
async function fetchAllSymbolsFromBybit() {
|
|
75
93
|
try {
|
|
76
|
-
const response = await fetch(`${
|
|
94
|
+
const response = await fetch(`${BYBIT_API_BASE}/instruments-info?category=spot`);
|
|
77
95
|
if (!response.ok) {
|
|
78
|
-
throw new Error("Failed to fetch exchange info");
|
|
96
|
+
throw new Error("Failed to fetch exchange info from Bybit");
|
|
79
97
|
}
|
|
80
98
|
const data = await response.json();
|
|
81
99
|
const symbols = new Set();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
if (data.retCode === 0 && data.result.list) {
|
|
101
|
+
for (const instrument of data.result.list) {
|
|
102
|
+
// Only include USDT pairs that are trading
|
|
103
|
+
if (instrument.status === "Trading" && instrument.quoteCoin === "USDT") {
|
|
104
|
+
symbols.add(instrument.symbol);
|
|
105
|
+
// Also add the base asset for easy lookup
|
|
106
|
+
symbols.add(instrument.baseCoin.toLowerCase());
|
|
107
|
+
}
|
|
88
108
|
}
|
|
89
109
|
}
|
|
90
|
-
cachedSymbols = symbols;
|
|
91
|
-
cacheTimestamp = Date.now();
|
|
92
110
|
return symbols;
|
|
93
111
|
}
|
|
94
|
-
catch
|
|
95
|
-
// Return empty set on error, will fall back to direct API check
|
|
112
|
+
catch {
|
|
96
113
|
return new Set();
|
|
97
114
|
}
|
|
98
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Get common crypto symbols as fallback (when all APIs are blocked)
|
|
118
|
+
*/
|
|
119
|
+
function getCommonSymbols() {
|
|
120
|
+
const common = [
|
|
121
|
+
"BTC",
|
|
122
|
+
"ETH",
|
|
123
|
+
"BNB",
|
|
124
|
+
"XRP",
|
|
125
|
+
"SOL",
|
|
126
|
+
"ADA",
|
|
127
|
+
"DOGE",
|
|
128
|
+
"DOT",
|
|
129
|
+
"MATIC",
|
|
130
|
+
"LTC",
|
|
131
|
+
"AVAX",
|
|
132
|
+
"LINK",
|
|
133
|
+
"ATOM",
|
|
134
|
+
"UNI",
|
|
135
|
+
"XLM",
|
|
136
|
+
"ALGO",
|
|
137
|
+
"NEAR",
|
|
138
|
+
"APT",
|
|
139
|
+
"ARB",
|
|
140
|
+
"OP",
|
|
141
|
+
"SUI",
|
|
142
|
+
"PEPE",
|
|
143
|
+
"SHIB",
|
|
144
|
+
"WIF",
|
|
145
|
+
"TRX",
|
|
146
|
+
"ETC",
|
|
147
|
+
"FIL",
|
|
148
|
+
"HBAR",
|
|
149
|
+
"VET",
|
|
150
|
+
"ICP",
|
|
151
|
+
];
|
|
152
|
+
const symbols = new Set();
|
|
153
|
+
for (const sym of common) {
|
|
154
|
+
symbols.add(`${sym}USDT`);
|
|
155
|
+
symbols.add(sym.toLowerCase());
|
|
156
|
+
}
|
|
157
|
+
return symbols;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Fetch all valid USDT trading pairs (tries Binance -> Bybit -> fallback to common)
|
|
161
|
+
*/
|
|
162
|
+
async function fetchAllSymbols() {
|
|
163
|
+
// Return cached symbols if still valid
|
|
164
|
+
if (cachedSymbols && Date.now() - cacheTimestamp < CACHE_DURATION) {
|
|
165
|
+
return cachedSymbols;
|
|
166
|
+
}
|
|
167
|
+
// Try Binance first
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(`${BINANCE_API_BASE}/exchangeInfo`);
|
|
170
|
+
if (response.ok) {
|
|
171
|
+
const data = await response.json();
|
|
172
|
+
const symbols = new Set();
|
|
173
|
+
for (const symbol of data.symbols) {
|
|
174
|
+
// Only include USDT pairs that are trading
|
|
175
|
+
if (symbol.status === "TRADING" && symbol.quoteAsset === "USDT") {
|
|
176
|
+
symbols.add(symbol.symbol);
|
|
177
|
+
// Also add the base asset for easy lookup
|
|
178
|
+
symbols.add(symbol.baseAsset.toLowerCase());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
cachedSymbols = symbols;
|
|
182
|
+
cacheTimestamp = Date.now();
|
|
183
|
+
return symbols;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Continue to fallback
|
|
188
|
+
}
|
|
189
|
+
// Try Bybit as fallback
|
|
190
|
+
try {
|
|
191
|
+
const symbols = await fetchAllSymbolsFromBybit();
|
|
192
|
+
if (symbols.size > 0) {
|
|
193
|
+
cachedSymbols = symbols;
|
|
194
|
+
cacheTimestamp = Date.now();
|
|
195
|
+
return symbols;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Continue to fallback
|
|
200
|
+
}
|
|
201
|
+
// Use common symbols as final fallback
|
|
202
|
+
const symbols = getCommonSymbols();
|
|
203
|
+
cachedSymbols = symbols;
|
|
204
|
+
cacheTimestamp = Date.now();
|
|
205
|
+
return symbols;
|
|
206
|
+
}
|
|
99
207
|
/**
|
|
100
208
|
* Get similar symbols for suggestions
|
|
101
209
|
*/
|
|
@@ -142,49 +250,233 @@ function normalizeSymbol(input) {
|
|
|
142
250
|
return lower.toUpperCase() + "USDT";
|
|
143
251
|
}
|
|
144
252
|
/**
|
|
145
|
-
* Fetch OHLCV candle data from
|
|
253
|
+
* Fetch OHLCV candle data from Bybit (fallback)
|
|
146
254
|
*/
|
|
147
|
-
async function
|
|
255
|
+
async function fetchOHLCVFromBybit(symbol, interval = "1h", limit = 100) {
|
|
148
256
|
const normalizedSymbol = normalizeSymbol(symbol);
|
|
149
|
-
const
|
|
257
|
+
const bybitInterval = BYBIT_INTERVAL_MAP[interval];
|
|
258
|
+
const url = `${BYBIT_API_BASE}/kline?category=spot&symbol=${normalizedSymbol}&interval=${bybitInterval}&limit=${limit}`;
|
|
150
259
|
const response = await fetch(url);
|
|
151
260
|
if (!response.ok) {
|
|
152
261
|
const error = await response.text();
|
|
153
262
|
throw new Error(`Failed to fetch data for ${normalizedSymbol}: ${error}`);
|
|
154
263
|
}
|
|
155
264
|
const data = await response.json();
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
265
|
+
if (data.retCode !== 0) {
|
|
266
|
+
throw new Error(`Bybit API error: ${data.retMsg}`);
|
|
267
|
+
}
|
|
268
|
+
// Bybit klines are in reverse order (newest first), so we reverse them
|
|
269
|
+
// Format: [startTime, openPrice, highPrice, lowPrice, closePrice, volume, turnover]
|
|
270
|
+
return data.result.list
|
|
271
|
+
.map((candle) => ({
|
|
272
|
+
timestamp: parseInt(candle[0]),
|
|
160
273
|
open: parseFloat(candle[1]),
|
|
161
274
|
high: parseFloat(candle[2]),
|
|
162
275
|
low: parseFloat(candle[3]),
|
|
163
276
|
close: parseFloat(candle[4]),
|
|
164
277
|
volume: parseFloat(candle[5]),
|
|
165
|
-
}))
|
|
278
|
+
}))
|
|
279
|
+
.reverse();
|
|
166
280
|
}
|
|
167
281
|
/**
|
|
168
|
-
* Fetch 24h ticker data
|
|
282
|
+
* Fetch 24h ticker data from Bybit (fallback)
|
|
169
283
|
*/
|
|
170
|
-
async function
|
|
284
|
+
async function fetch24hTickerFromBybit(symbol) {
|
|
171
285
|
const normalizedSymbol = normalizeSymbol(symbol);
|
|
172
|
-
const url = `${
|
|
286
|
+
const url = `${BYBIT_API_BASE}/tickers?category=spot&symbol=${normalizedSymbol}`;
|
|
173
287
|
const response = await fetch(url);
|
|
174
288
|
if (!response.ok) {
|
|
175
289
|
const error = await response.text();
|
|
176
290
|
throw new Error(`Failed to fetch ticker for ${normalizedSymbol}: ${error}`);
|
|
177
291
|
}
|
|
178
292
|
const data = await response.json();
|
|
293
|
+
if (data.retCode !== 0 || !data.result.list.length) {
|
|
294
|
+
throw new Error(`Bybit API error: ${data.retMsg || "Symbol not found"}`);
|
|
295
|
+
}
|
|
296
|
+
const ticker = data.result.list[0];
|
|
297
|
+
const price = parseFloat(ticker.lastPrice);
|
|
298
|
+
const prevPrice = parseFloat(ticker.prevPrice24h);
|
|
299
|
+
const priceChange = price - prevPrice;
|
|
300
|
+
const priceChangePercent = parseFloat(ticker.price24hPcnt) * 100;
|
|
301
|
+
return {
|
|
302
|
+
price,
|
|
303
|
+
priceChange,
|
|
304
|
+
priceChangePercent,
|
|
305
|
+
high24h: parseFloat(ticker.highPrice24h),
|
|
306
|
+
low24h: parseFloat(ticker.lowPrice24h),
|
|
307
|
+
volume24h: parseFloat(ticker.volume24h),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Check if error is due to geo-restriction or CloudFront block
|
|
312
|
+
*/
|
|
313
|
+
function isGeoRestricted(error) {
|
|
314
|
+
return (error.includes("restricted location") ||
|
|
315
|
+
error.includes("Service unavailable") ||
|
|
316
|
+
error.includes("CloudFront") ||
|
|
317
|
+
error.includes("403") ||
|
|
318
|
+
error.includes("block access from your country"));
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Extract base symbol from normalized symbol (e.g., BTCUSDT -> BTC)
|
|
322
|
+
*/
|
|
323
|
+
function getBaseSymbol(normalizedSymbol) {
|
|
324
|
+
if (normalizedSymbol.endsWith("USDT")) {
|
|
325
|
+
return normalizedSymbol.slice(0, -4);
|
|
326
|
+
}
|
|
327
|
+
if (normalizedSymbol.endsWith("USD")) {
|
|
328
|
+
return normalizedSymbol.slice(0, -3);
|
|
329
|
+
}
|
|
330
|
+
return normalizedSymbol;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Fetch OHLCV candle data from CryptoCompare (globally accessible, no geo-restrictions)
|
|
334
|
+
*/
|
|
335
|
+
async function fetchOHLCVFromCryptoCompare(symbol, interval = "1h", limit = 100) {
|
|
336
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
337
|
+
const baseSymbol = getBaseSymbol(normalizedSymbol);
|
|
338
|
+
const { endpoint, aggregate } = CRYPTOCOMPARE_INTERVAL_MAP[interval];
|
|
339
|
+
const url = `${CRYPTOCOMPARE_API_BASE}/v2/${endpoint}?fsym=${baseSymbol}&tsym=USDT&limit=${limit}&aggregate=${aggregate}`;
|
|
340
|
+
const response = await fetch(url);
|
|
341
|
+
if (!response.ok) {
|
|
342
|
+
const error = await response.text();
|
|
343
|
+
throw new Error(`CryptoCompare error for ${baseSymbol}: ${error}`);
|
|
344
|
+
}
|
|
345
|
+
const data = await response.json();
|
|
346
|
+
if (data.Response === "Error") {
|
|
347
|
+
throw new Error(`CryptoCompare error: ${data.Message}`);
|
|
348
|
+
}
|
|
349
|
+
// CryptoCompare format: { time, open, high, low, close, volumefrom, volumeto }
|
|
350
|
+
return data.Data.Data.map((candle) => ({
|
|
351
|
+
timestamp: candle.time * 1000, // Convert to milliseconds
|
|
352
|
+
open: candle.open,
|
|
353
|
+
high: candle.high,
|
|
354
|
+
low: candle.low,
|
|
355
|
+
close: candle.close,
|
|
356
|
+
volume: candle.volumefrom,
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Fetch 24h ticker data from CryptoCompare (globally accessible)
|
|
361
|
+
*/
|
|
362
|
+
async function fetch24hTickerFromCryptoCompare(symbol) {
|
|
363
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
364
|
+
const baseSymbol = getBaseSymbol(normalizedSymbol);
|
|
365
|
+
// Fetch current price and 24h data
|
|
366
|
+
const [priceResponse, dayResponse] = await Promise.all([
|
|
367
|
+
fetch(`${CRYPTOCOMPARE_API_BASE}/price?fsym=${baseSymbol}&tsyms=USDT`),
|
|
368
|
+
fetch(`${CRYPTOCOMPARE_API_BASE}/v2/histoday?fsym=${baseSymbol}&tsym=USDT&limit=1`),
|
|
369
|
+
]);
|
|
370
|
+
if (!priceResponse.ok || !dayResponse.ok) {
|
|
371
|
+
throw new Error(`CryptoCompare error fetching ticker for ${baseSymbol}`);
|
|
372
|
+
}
|
|
373
|
+
const priceData = await priceResponse.json();
|
|
374
|
+
const dayData = await dayResponse.json();
|
|
375
|
+
if (priceData.Response === "Error" || dayData.Response === "Error") {
|
|
376
|
+
throw new Error(`CryptoCompare error: Symbol ${baseSymbol} not found`);
|
|
377
|
+
}
|
|
378
|
+
const currentPrice = priceData.USDT;
|
|
379
|
+
const dayCandles = dayData.Data.Data;
|
|
380
|
+
// Get yesterday's data for 24h change calculation
|
|
381
|
+
const yesterday = dayCandles[0];
|
|
382
|
+
const today = dayCandles[1] || yesterday;
|
|
383
|
+
const priceChange = currentPrice - yesterday.close;
|
|
384
|
+
const priceChangePercent = (priceChange / yesterday.close) * 100;
|
|
179
385
|
return {
|
|
180
|
-
price:
|
|
181
|
-
priceChange
|
|
182
|
-
priceChangePercent
|
|
183
|
-
high24h:
|
|
184
|
-
low24h:
|
|
185
|
-
volume24h:
|
|
386
|
+
price: currentPrice,
|
|
387
|
+
priceChange,
|
|
388
|
+
priceChangePercent,
|
|
389
|
+
high24h: today.high,
|
|
390
|
+
low24h: today.low,
|
|
391
|
+
volume24h: today.volumefrom,
|
|
186
392
|
};
|
|
187
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* Fetch OHLCV candle data (tries Binance -> Bybit -> CryptoCompare)
|
|
396
|
+
*/
|
|
397
|
+
async function fetchOHLCV(symbol, interval = "1h", limit = 100) {
|
|
398
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
399
|
+
const errors = [];
|
|
400
|
+
// Try Binance first
|
|
401
|
+
try {
|
|
402
|
+
const url = `${BINANCE_API_BASE}/klines?symbol=${normalizedSymbol}&interval=${interval}&limit=${limit}`;
|
|
403
|
+
const response = await fetch(url);
|
|
404
|
+
if (response.ok) {
|
|
405
|
+
const data = await response.json();
|
|
406
|
+
// Binance klines format:
|
|
407
|
+
// [0] Open time, [1] Open, [2] High, [3] Low, [4] Close, [5] Volume, ...
|
|
408
|
+
return data.map((candle) => ({
|
|
409
|
+
timestamp: candle[0],
|
|
410
|
+
open: parseFloat(candle[1]),
|
|
411
|
+
high: parseFloat(candle[2]),
|
|
412
|
+
low: parseFloat(candle[3]),
|
|
413
|
+
close: parseFloat(candle[4]),
|
|
414
|
+
volume: parseFloat(candle[5]),
|
|
415
|
+
}));
|
|
416
|
+
}
|
|
417
|
+
errors.push(`Binance: ${response.status}`);
|
|
418
|
+
}
|
|
419
|
+
catch (e) {
|
|
420
|
+
errors.push(`Binance: ${e.message}`);
|
|
421
|
+
}
|
|
422
|
+
// Try Bybit as fallback
|
|
423
|
+
try {
|
|
424
|
+
return await fetchOHLCVFromBybit(symbol, interval, limit);
|
|
425
|
+
}
|
|
426
|
+
catch (e) {
|
|
427
|
+
errors.push(`Bybit: ${e.message}`);
|
|
428
|
+
}
|
|
429
|
+
// Try CryptoCompare as final fallback (globally accessible)
|
|
430
|
+
try {
|
|
431
|
+
return await fetchOHLCVFromCryptoCompare(symbol, interval, limit);
|
|
432
|
+
}
|
|
433
|
+
catch (e) {
|
|
434
|
+
errors.push(`CryptoCompare: ${e.message}`);
|
|
435
|
+
}
|
|
436
|
+
throw new Error(`Failed to fetch data for ${normalizedSymbol}. Tried all providers: ${errors.join("; ")}`);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Fetch 24h ticker data for price change info (tries Binance -> Bybit -> CryptoCompare)
|
|
440
|
+
*/
|
|
441
|
+
async function fetch24hTicker(symbol) {
|
|
442
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
443
|
+
const errors = [];
|
|
444
|
+
// Try Binance first
|
|
445
|
+
try {
|
|
446
|
+
const url = `${BINANCE_API_BASE}/ticker/24hr?symbol=${normalizedSymbol}`;
|
|
447
|
+
const response = await fetch(url);
|
|
448
|
+
if (response.ok) {
|
|
449
|
+
const data = await response.json();
|
|
450
|
+
return {
|
|
451
|
+
price: parseFloat(data.lastPrice),
|
|
452
|
+
priceChange: parseFloat(data.priceChange),
|
|
453
|
+
priceChangePercent: parseFloat(data.priceChangePercent),
|
|
454
|
+
high24h: parseFloat(data.highPrice),
|
|
455
|
+
low24h: parseFloat(data.lowPrice),
|
|
456
|
+
volume24h: parseFloat(data.volume),
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
errors.push(`Binance: ${response.status}`);
|
|
460
|
+
}
|
|
461
|
+
catch (e) {
|
|
462
|
+
errors.push(`Binance: ${e.message}`);
|
|
463
|
+
}
|
|
464
|
+
// Try Bybit as fallback
|
|
465
|
+
try {
|
|
466
|
+
return await fetch24hTickerFromBybit(symbol);
|
|
467
|
+
}
|
|
468
|
+
catch (e) {
|
|
469
|
+
errors.push(`Bybit: ${e.message}`);
|
|
470
|
+
}
|
|
471
|
+
// Try CryptoCompare as final fallback (globally accessible)
|
|
472
|
+
try {
|
|
473
|
+
return await fetch24hTickerFromCryptoCompare(symbol);
|
|
474
|
+
}
|
|
475
|
+
catch (e) {
|
|
476
|
+
errors.push(`CryptoCompare: ${e.message}`);
|
|
477
|
+
}
|
|
478
|
+
throw new Error(`Failed to fetch ticker for ${normalizedSymbol}. Tried all providers: ${errors.join("; ")}`);
|
|
479
|
+
}
|
|
188
480
|
/**
|
|
189
481
|
* Fetch complete crypto data for analysis
|
|
190
482
|
*/
|
|
@@ -211,20 +503,24 @@ function getSupportedSymbols() {
|
|
|
211
503
|
return [...new Set(Object.keys(SYMBOL_MAP))];
|
|
212
504
|
}
|
|
213
505
|
/**
|
|
214
|
-
* Check if a symbol is valid/supported
|
|
506
|
+
* Check if a symbol is valid/supported by trying to fetch its price
|
|
215
507
|
*/
|
|
216
508
|
async function isValidSymbol(symbol) {
|
|
217
509
|
try {
|
|
218
510
|
const normalizedSymbol = normalizeSymbol(symbol);
|
|
219
|
-
// First check cache
|
|
511
|
+
// First check our symbol cache
|
|
220
512
|
const symbols = await fetchAllSymbols();
|
|
221
|
-
if (symbols.has(normalizedSymbol)) {
|
|
513
|
+
if (symbols.has(normalizedSymbol) || symbols.has(normalizedSymbol.toLowerCase())) {
|
|
222
514
|
return true;
|
|
223
515
|
}
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
516
|
+
// Try to actually fetch the ticker to validate
|
|
517
|
+
try {
|
|
518
|
+
await fetch24hTicker(symbol);
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
228
524
|
}
|
|
229
525
|
catch {
|
|
230
526
|
return false;
|
|
@@ -236,16 +532,12 @@ async function isValidSymbol(symbol) {
|
|
|
236
532
|
async function validateSymbol(symbol) {
|
|
237
533
|
const normalized = normalizeSymbol(symbol);
|
|
238
534
|
try {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return { valid: true, normalized, suggestions: [] };
|
|
243
|
-
}
|
|
244
|
-
// If invalid, find similar symbols
|
|
245
|
-
const suggestions = await findSimilarSymbols(symbol, 5);
|
|
246
|
-
return { valid: false, normalized, suggestions };
|
|
535
|
+
// Try to fetch the ticker - this will try all providers
|
|
536
|
+
await fetch24hTicker(symbol);
|
|
537
|
+
return { valid: true, normalized, suggestions: [] };
|
|
247
538
|
}
|
|
248
539
|
catch {
|
|
540
|
+
// If invalid, find similar symbols from our cache
|
|
249
541
|
const suggestions = await findSimilarSymbols(symbol, 5);
|
|
250
542
|
return { valid: false, normalized, suggestions };
|
|
251
543
|
}
|
package/dist/lib/crypto/index.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Exports all crypto-related functionality
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports.runStrategy = exports.displayNews = exports.fetchCryptoNews = exports.runCryptoNews = exports.displayScanResults = exports.runMarketScanner = exports.displayWhaleActivity = exports.runWhaleTracker = exports.displaySMCAnalysis = exports.runSMCAnalysis = exports.calculatePremiumDiscount = exports.findLiquidityZones = exports.findFairValueGaps = exports.findOrderBlocks = exports.findSwingPoints = exports.analyzeSMC = exports.analyzeTrend = exports.calculateSupportResistance = exports.analyzeVolume = exports.calculateATR = exports.calculateBollingerBands = exports.calculateMACD = exports.calculateRSI = exports.analyzeMarket = exports.calculateConfluenceScore = exports.calculateRSIStrategy = exports.analyzeVolumeStrategy = exports.detectPullback = exports.detectKeyLevels = exports.detectCandlePattern = exports.generateStrategySignal = exports.displayStrategyResult = exports.runSmartStrategy = exports.displayComprehensiveAnalysis = exports.comprehensiveAnalysis = exports.fullSignal = exports.quickSignal = exports.displaySignal = exports.generateTradingSignal = exports.formatSignalSummary = exports.generateSignal = exports.calculateIndicators = exports.calculateAllEMAs = exports.calculateEMA = exports.isValidSymbol = exports.getSupportedSymbols = exports.normalizeSymbol = exports.fetch24hTicker = exports.fetchOHLCV = exports.fetchCryptoData = void 0;
|
|
8
|
+
exports.displayICTSignal = exports.generateICTSignal = exports.runICTStrategy = exports.displayOrderBlockSignal = exports.generateOrderBlockSignal = exports.runOrderBlockStrategy = exports.displayTradeSetup = exports.generateTradeSetup = void 0;
|
|
8
9
|
var data_fetcher_1 = require("./data-fetcher");
|
|
9
10
|
Object.defineProperty(exports, "fetchCryptoData", { enumerable: true, get: function () { return data_fetcher_1.fetchCryptoData; } });
|
|
10
11
|
Object.defineProperty(exports, "fetchOHLCV", { enumerable: true, get: function () { return data_fetcher_1.fetchOHLCV; } });
|
|
@@ -25,6 +26,16 @@ Object.defineProperty(exports, "quickSignal", { enumerable: true, get: function
|
|
|
25
26
|
Object.defineProperty(exports, "fullSignal", { enumerable: true, get: function () { return signal_generator_1.fullSignal; } });
|
|
26
27
|
Object.defineProperty(exports, "comprehensiveAnalysis", { enumerable: true, get: function () { return signal_generator_1.comprehensiveAnalysis; } });
|
|
27
28
|
Object.defineProperty(exports, "displayComprehensiveAnalysis", { enumerable: true, get: function () { return signal_generator_1.displayComprehensiveAnalysis; } });
|
|
29
|
+
Object.defineProperty(exports, "runSmartStrategy", { enumerable: true, get: function () { return signal_generator_1.runSmartStrategy; } });
|
|
30
|
+
Object.defineProperty(exports, "displayStrategyResult", { enumerable: true, get: function () { return signal_generator_1.displayStrategyResult; } });
|
|
31
|
+
var strategy_1 = require("./strategy");
|
|
32
|
+
Object.defineProperty(exports, "generateStrategySignal", { enumerable: true, get: function () { return strategy_1.generateStrategySignal; } });
|
|
33
|
+
Object.defineProperty(exports, "detectCandlePattern", { enumerable: true, get: function () { return strategy_1.detectCandlePattern; } });
|
|
34
|
+
Object.defineProperty(exports, "detectKeyLevels", { enumerable: true, get: function () { return strategy_1.detectKeyLevels; } });
|
|
35
|
+
Object.defineProperty(exports, "detectPullback", { enumerable: true, get: function () { return strategy_1.detectPullback; } });
|
|
36
|
+
Object.defineProperty(exports, "analyzeVolumeStrategy", { enumerable: true, get: function () { return strategy_1.analyzeVolume; } });
|
|
37
|
+
Object.defineProperty(exports, "calculateRSIStrategy", { enumerable: true, get: function () { return strategy_1.calculateRSI; } });
|
|
38
|
+
Object.defineProperty(exports, "calculateConfluenceScore", { enumerable: true, get: function () { return strategy_1.calculateConfluenceScore; } });
|
|
28
39
|
var market_analyzer_1 = require("./market-analyzer");
|
|
29
40
|
Object.defineProperty(exports, "analyzeMarket", { enumerable: true, get: function () { return market_analyzer_1.analyzeMarket; } });
|
|
30
41
|
var indicators_1 = require("./indicators");
|