File size: 4,331 Bytes
fc0fb8b
65d5f73
fc0fb8b
 
 
7458986
 
 
 
db6d471
7458986
 
65d5f73
7458986
db6d471
 
972a547
fc0fb8b
 
 
 
 
05c066f
fc0fb8b
7458986
db6d471
 
 
 
 
 
7458986
daab9d7
05c066f
7458986
fc0fb8b
525527f
65d5f73
 
db6d471
 
972a547
65d5f73
 
db6d471
 
daab9d7
db6d471
 
 
 
972a547
db6d471
 
 
 
 
05c066f
65d5f73
db6d471
fc0fb8b
65d5f73
 
fc0fb8b
 
 
 
 
db6d471
fc0fb8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65d5f73
7458986
db6d471
fc0fb8b
 
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
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)