Spaces:
Sleeping
Sleeping
| import warnings | |
| import yfinance as yf | |
| from fastapi import FastAPI, HTTPException, Query | |
| from fastapi.responses import JSONResponse | |
| import uvicorn | |
| from utils import ( | |
| calculate_technical_indicators, | |
| generate_trading_signals, | |
| get_fundamental_data, | |
| predict_prices, | |
| create_price_chart, | |
| create_technical_chart, | |
| create_prediction_chart, | |
| ) | |
| warnings.filterwarnings("ignore") | |
| app = FastAPI( | |
| title="IDX Stock Analysis API", | |
| description="API untuk analisis teknikal, fundamental, dan prediksi AI untuk saham IDX.", | |
| version="1.0.0" | |
| ) | |
| def analyze_stock_logic(symbol, prediction_days=30): | |
| try: | |
| if not symbol.strip(): | |
| raise ValueError("Please enter a valid stock symbol.") | |
| if not symbol.endswith(".JK"): | |
| symbol = symbol.upper() + ".JK" | |
| stock = yf.Ticker(symbol) | |
| data = stock.history(period="6mo", interval="1d") | |
| if data.empty: | |
| raise ValueError(f"No price data available for stock: {symbol}") | |
| indicators = calculate_technical_indicators(data) | |
| signals = generate_trading_signals(data, indicators) | |
| fundamental_info = get_fundamental_data(stock) | |
| predictions = predict_prices(data, prediction_days=prediction_days) | |
| fig_price = create_price_chart(data, indicators) | |
| fig_technical = create_technical_chart(data, indicators) | |
| fig_prediction = create_prediction_chart(data, predictions) | |
| # kalkulasi TP1, TP2, SL | |
| last_price = data['Close'].iloc[-1] | |
| tp1 = last_price * (1 + (predictions.get("change_pct", 0) / 200)) | |
| tp2 = last_price * (1 + (predictions.get("change_pct", 0) / 100)) | |
| sl = last_price * 0.95 | |
| predictions["tp1"] = tp1 | |
| predictions["tp2"] = tp2 | |
| predictions["sl"] = sl | |
| return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction, predictions | |
| except Exception as e: | |
| print(f"Error analyzing {symbol}: {e}") | |
| raise HTTPException(status_code=404, detail=str(e)) | |
| async def get_stock_analysis( | |
| symbol: str = Query(..., description="Simbol saham IDX (contoh: BBCA, TLKM)"), | |
| prediction_days: int = Query(30, ge=5, le=60, description="Jumlah hari untuk prediksi ke depan") | |
| ): | |
| """ | |
| Menjalankan analisis lengkap untuk simbol saham yang diberikan. | |
| """ | |
| try: | |
| ( | |
| fundamental_info, | |
| indicators, | |
| signals, | |
| fig_price, | |
| fig_technical, | |
| fig_prediction, | |
| predictions, | |
| ) = analyze_stock_logic(symbol, prediction_days) | |
| # Ubah figur Plotly menjadi JSON agar bisa dikirim via API | |
| charts_json = { | |
| "price_chart": fig_price.to_json(), | |
| "technical_chart": fig_technical.to_json(), | |
| "prediction_chart": fig_prediction.to_json() | |
| } | |
| # Hapus data 'values' yang besar dari indicators agar response tidak terlalu besar | |
| # Klien bisa membuat chart ini dari data chart utama jika perlu | |
| if 'rsi' in indicators: | |
| indicators['rsi'].pop('values', None) | |
| if 'macd' in indicators: | |
| indicators['macd'].pop('macd_values', None) | |
| indicators['macd'].pop('signal_values', None) | |
| if 'bollinger' in indicators: | |
| indicators['bollinger'].pop('upper_values', None) | |
| indicators['bollinger'].pop('middle_values', None) | |
| indicators['bollinger'].pop('lower_values', None) | |
| if 'moving_averages' in indicators: | |
| indicators['moving_averages'].pop('sma_20_values', None) | |
| indicators['moving_averages'].pop('sma_50_values', None) | |
| return JSONResponse(content={ | |
| "symbol": symbol.upper() + ".JK", | |
| "fundamentals": fundamental_info, | |
| "technical_indicators": indicators, | |
| "trading_signals": signals, | |
| "ai_predictions": predictions, | |
| "charts_json": charts_json | |
| }) | |
| except HTTPException as http_exc: | |
| raise http_exc | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"An internal error occurred: {str(e)}") | |
| if __name__ == "__main__": | |
| # Gunakan port 7860 yang merupakan default untuk Hugging Face Spaces | |
| uvicorn.run(app, host="0.0.0.0", port=7860) |