IDX-Chronos-API / app.py
omniverse1's picture
FastAPI
fc0fb8b verified
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))
@app.get("/analyze/")
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)