File size: 13,009 Bytes
b190b45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/env python3
"""

Comprehensive Resources API Router

Exposes ALL free resources through dedicated endpoints

"""

from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import JSONResponse
from typing import Optional, Dict, Any, List
from datetime import datetime
import logging

# Import all aggregators
from backend.services.market_data_aggregator import market_data_aggregator
from backend.services.news_aggregator import news_aggregator
from backend.services.sentiment_aggregator import sentiment_aggregator
from backend.services.onchain_aggregator import onchain_aggregator
from backend.services.hf_dataset_aggregator import hf_dataset_aggregator

logger = logging.getLogger(__name__)

router = APIRouter(tags=["Comprehensive Resources"])


# ============================================================================
# Market Data Endpoints - Uses ALL Free Market Data APIs
# ============================================================================

@router.get("/api/resources/market/price/{symbol}")
async def get_resource_price(symbol: str):
    """

    Get price from ALL free market data providers with automatic fallback.

    Providers: CoinGecko, CoinPaprika, CoinCap, Binance, CoinLore, Messari, CoinStats

    """
    try:
        price_data = await market_data_aggregator.get_price(symbol)
        return JSONResponse(content=price_data)
    except Exception as e:
        logger.error(f"Error fetching price from all providers: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/market/prices")
async def get_resource_prices(

    symbols: Optional[str] = Query(None, description="Comma-separated symbols (e.g., BTC,ETH,BNB)"),

    limit: int = Query(100, description="Number of top coins to fetch if symbols not provided")

):
    """

    Get prices for multiple symbols from ALL free market data providers.

    If symbols not provided, returns top coins by market cap.

    """
    try:
        symbols_list = symbols.split(",") if symbols else None
        prices = await market_data_aggregator.get_multiple_prices(symbols_list, limit)
        return JSONResponse(content={"success": True, "count": len(prices), "data": prices})
    except Exception as e:
        logger.error(f"Error fetching prices from all providers: {e}")
        raise HTTPException(status_code=503, detail=str(e))


# ============================================================================
# News Endpoints - Uses ALL Free News Sources
# ============================================================================

@router.get("/api/resources/news/latest")
async def get_resource_news(

    symbol: Optional[str] = Query(None, description="Filter by cryptocurrency symbol"),

    limit: int = Query(20, description="Number of articles to fetch")

):
    """

    Get news from ALL free news sources with automatic aggregation.

    Sources: CryptoPanic, CoinStats, CoinTelegraph RSS, CoinDesk RSS, Decrypt RSS, Bitcoin Magazine RSS, CryptoSlate

    """
    try:
        news = await news_aggregator.get_news(symbol=symbol, limit=limit)
        return JSONResponse(content={"success": True, "count": len(news), "news": news})
    except Exception as e:
        logger.error(f"Error fetching news from all sources: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/news/symbol/{symbol}")
async def get_resource_symbol_news(

    symbol: str,

    limit: int = Query(10, description="Number of articles to fetch")

):
    """

    Get news for a specific cryptocurrency symbol from all sources.

    """
    try:
        news = await news_aggregator.get_symbol_news(symbol=symbol, limit=limit)
        return JSONResponse(content={"success": True, "symbol": symbol.upper(), "count": len(news), "news": news})
    except Exception as e:
        logger.error(f"Error fetching symbol news: {e}")
        raise HTTPException(status_code=503, detail=str(e))


# ============================================================================
# Sentiment Endpoints - Uses ALL Free Sentiment Sources
# ============================================================================

@router.get("/api/resources/sentiment/fear-greed")
async def get_resource_fear_greed():
    """

    Get Fear & Greed Index from ALL free sentiment providers with fallback.

    Providers: Alternative.me, CFGI API v1, CFGI Legacy

    """
    try:
        fng_data = await sentiment_aggregator.get_fear_greed_index()
        return JSONResponse(content=fng_data)
    except Exception as e:
        logger.error(f"Error fetching Fear & Greed Index: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/sentiment/global")
async def get_resource_global_sentiment():
    """

    Get global market sentiment from multiple free sources.

    Includes: Fear & Greed Index, Reddit sentiment, overall market mood

    """
    try:
        sentiment = await sentiment_aggregator.get_global_sentiment()
        return JSONResponse(content=sentiment)
    except Exception as e:
        logger.error(f"Error fetching global sentiment: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/sentiment/coin/{symbol}")
async def get_resource_coin_sentiment(symbol: str):
    """

    Get sentiment for a specific cryptocurrency from all sources.

    Sources: CoinGecko community data, Messari social metrics

    """
    try:
        sentiment = await sentiment_aggregator.get_coin_sentiment(symbol)
        return JSONResponse(content=sentiment)
    except Exception as e:
        logger.error(f"Error fetching coin sentiment: {e}")
        raise HTTPException(status_code=503, detail=str(e))


# ============================================================================
# On-Chain Data Endpoints - Uses ALL Free Block Explorers & RPC Nodes
# ============================================================================

@router.get("/api/resources/onchain/balance")
async def get_resource_balance(

    address: str = Query(..., description="Blockchain address"),

    chain: str = Query("ethereum", description="Blockchain (ethereum, bsc, tron, polygon)")

):
    """

    Get address balance from ALL free block explorers with fallback.

    Ethereum: Etherscan (2 keys), Blockchair, Blockscout

    BSC: BscScan, Blockchair

    Tron: TronScan, Blockchair

    """
    try:
        balance = await onchain_aggregator.get_address_balance(address, chain)
        return JSONResponse(content=balance)
    except Exception as e:
        logger.error(f"Error fetching balance: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/onchain/gas")
async def get_resource_gas_price(

    chain: str = Query("ethereum", description="Blockchain (ethereum, bsc, polygon)")

):
    """

    Get current gas prices from explorers or RPC nodes.

    Uses: Etherscan/BscScan APIs, Free RPC nodes (Ankr, PublicNode, Cloudflare, etc.)

    """
    try:
        gas_data = await onchain_aggregator.get_gas_price(chain)
        return JSONResponse(content=gas_data)
    except Exception as e:
        logger.error(f"Error fetching gas price: {e}")
        raise HTTPException(status_code=503, detail=str(e))


@router.get("/api/resources/onchain/transactions")
async def get_resource_transactions(

    address: str = Query(..., description="Blockchain address"),

    chain: str = Query("ethereum", description="Blockchain (ethereum, bsc, tron)"),

    limit: int = Query(20, description="Number of transactions to fetch")

):
    """

    Get transaction history for an address from all available explorers.

    """
    try:
        transactions = await onchain_aggregator.get_transactions(address, chain, limit)
        return JSONResponse(content={"success": True, "count": len(transactions), "transactions": transactions})
    except Exception as e:
        logger.error(f"Error fetching transactions: {e}")
        raise HTTPException(status_code=503, detail=str(e))


# ============================================================================
# HuggingFace Dataset Endpoints - FREE Historical OHLCV Data
# ============================================================================

@router.get("/api/resources/hf/ohlcv")
async def get_resource_hf_ohlcv(

    symbol: str = Query(..., description="Cryptocurrency symbol"),

    timeframe: str = Query("1h", description="Timeframe"),

    limit: int = Query(1000, description="Number of candles to fetch")

):
    """

    Get historical OHLCV data from FREE HuggingFace datasets.

    Sources:

    - linxy/CryptoCoin (26 symbols, 7 timeframes)

    - WinkingFace/CryptoLM (BTC, ETH, SOL, XRP)

    """
    try:
        ohlcv = await hf_dataset_aggregator.get_ohlcv(symbol, timeframe, limit)
        return JSONResponse(content={"success": True, "count": len(ohlcv), "data": ohlcv})
    except Exception as e:
        logger.error(f"Error fetching HF dataset OHLCV: {e}")
        raise HTTPException(status_code=404, detail=str(e))


@router.get("/api/resources/hf/symbols")
async def get_resource_hf_symbols():
    """

    Get list of available symbols from all HuggingFace datasets.

    """
    try:
        symbols = await hf_dataset_aggregator.get_available_symbols()
        return JSONResponse(content=symbols)
    except Exception as e:
        logger.error(f"Error fetching HF symbols: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/api/resources/hf/timeframes/{symbol}")
async def get_resource_hf_timeframes(symbol: str):
    """

    Get available timeframes for a specific symbol from HuggingFace datasets.

    """
    try:
        timeframes = await hf_dataset_aggregator.get_available_timeframes(symbol)
        return JSONResponse(content={"symbol": symbol.upper(), "timeframes": timeframes})
    except Exception as e:
        logger.error(f"Error fetching HF timeframes: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================================
# Resource Status & Info
# ============================================================================

@router.get("/api/resources/status")
async def get_resources_status():
    """

    Get status of all free resources.

    """
    return JSONResponse(content={
        "success": True,
        "timestamp": int(datetime.utcnow().timestamp() * 1000),
        "resources": {
            "market_data": {
                "providers": [
                    "CoinGecko", "CoinPaprika", "CoinCap", "Binance",
                    "CoinLore", "Messari", "DefiLlama", "DIA Data", "CoinStats"
                ],
                "total": 9,
                "all_free": True
            },
            "news": {
                "providers": [
                    "CryptoPanic", "CoinStats", "CoinTelegraph RSS", "CoinDesk RSS",
                    "Decrypt RSS", "Bitcoin Magazine RSS", "CryptoSlate"
                ],
                "total": 7,
                "all_free": True
            },
            "sentiment": {
                "providers": [
                    "Alternative.me", "CFGI v1", "CFGI Legacy",
                    "CoinGecko Community", "Messari Social", "Reddit"
                ],
                "total": 6,
                "all_free": True
            },
            "onchain": {
                "explorers": {
                    "ethereum": ["Etherscan (2 keys)", "Blockchair", "Blockscout"],
                    "bsc": ["BscScan", "Blockchair"],
                    "tron": ["TronScan", "Blockchair"],
                    "polygon": ["RPC nodes"]
                },
                "rpc_nodes": {
                    "ethereum": 7,
                    "bsc": 5,
                    "polygon": 3,
                    "tron": 2
                },
                "total_explorers": 10,
                "total_rpc_nodes": 17,
                "mostly_free": True
            },
            "datasets": {
                "huggingface": {
                    "linxy_cryptocoin": {"symbols": 26, "timeframes": 7, "total_files": 182},
                    "winkingface": {"symbols": ["BTC", "ETH", "SOL", "XRP"]}
                },
                "all_free": True
            }
        },
        "total_free_resources": {
            "market_data_apis": 9,
            "news_sources": 7,
            "sentiment_apis": 6,
            "block_explorers": 10,
            "rpc_nodes": 17,
            "hf_datasets": 2,
            "total": 51
        },
        "message": "ALL resources are FREE with automatic fallback and intelligent load balancing"
    })


# Export router
__all__ = ["router"]