File size: 3,426 Bytes
63d3279
 
 
 
 
 
fa6a7c9
 
63d3279
 
 
fa6a7c9
 
63d3279
 
 
fa6a7c9
63d3279
 
 
fa6a7c9
63d3279
 
fa6a7c9
63d3279
 
 
 
 
fa6a7c9
63d3279
 
 
 
 
fa6a7c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63d3279
 
 
 
 
fa6a7c9
63d3279
 
fa6a7c9
63d3279
 
 
 
 
 
 
 
 
 
 
 
 
fa6a7c9
 
 
 
 
63d3279
 
 
 
 
 
 
 
fa6a7c9
63d3279
 
 
 
fa6a7c9
63d3279
 
 
fa6a7c9
 
63d3279
fa6a7c9
63d3279
 
 
 
 
 
 
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
from fastapi import FastAPI
from pydantic import BaseModel
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import load_model
import json
import os

app = FastAPI(
    title="Forex LSTM Prediction API",
    description="Prediksi harga EUR/USD H+1 dengan LSTM menggunakan scaler harian",
    version="2.0"
)

# ==========================================================
# LOAD MODEL DAN KONFIGURASI
# ==========================================================
MODEL_PATH = "lstm_model.h5"
PARAMS_PATH = "best_params.json"
SCALER_FILE = "scaler_config.json"

print("📥 Loading LSTM model...")
model = load_model(MODEL_PATH, compile=False)

print("📥 Loading best parameters...")
with open(PARAMS_PATH, "r") as f:
    best_params = json.load(f)

LOOKBACK = best_params.get("lookback", 7)
FEATURE_ORDER = best_params.get("features", [
    "mood_score", "t_pos", "t_neg", "c_pos", "c_neg",
    "norm_ema20", "norm_ema50", "norm_close"
])

# ==========================================================
# LOAD SCALER CONFIG
# ==========================================================
def load_scaler_config():
    if not os.path.exists(SCALER_FILE):
        print("⚠️ Scaler config not found, using default values.")
        return {"CLOSE_MIN": 1.05, "CLOSE_MAX": 1.15}
    with open(SCALER_FILE, "r") as f:
        return json.load(f)

scaler_cfg = load_scaler_config()
CLOSE_MIN = scaler_cfg["CLOSE_MIN"]
CLOSE_MAX = scaler_cfg["CLOSE_MAX"]

print(f"✅ Scaler range loaded: {CLOSE_MIN:.5f} - {CLOSE_MAX:.5f}")

# ==========================================================
# INPUT SCHEMA
# ==========================================================
class LSTMInput(BaseModel):
    data: list

# ==========================================================
# HELPER FUNCTIONS
# ==========================================================
def prepare_input(data):
    df = pd.DataFrame(data)
    missing_cols = [f for f in FEATURE_ORDER if f not in df.columns]
    if missing_cols:
        raise ValueError(f"Missing columns: {missing_cols}")

    X = df[FEATURE_ORDER].values[-LOOKBACK:]
    if X.shape[0] < LOOKBACK:
        raise ValueError(f"Need at least {LOOKBACK} timesteps, got {X.shape[0]}")
    X = np.expand_dims(X, axis=0)
    return X, df


def inverse_scale(norm_value):
    """Denormalisasi nilai close dari [0,1] ke skala asli"""
    return (norm_value * (CLOSE_MAX - CLOSE_MIN)) + CLOSE_MIN

# ==========================================================
# ENDPOINT
# ==========================================================
@app.post("/predict")
def predict_price(input_data: LSTMInput):
    try:
        X, df = prepare_input(input_data.data)
        pred_norm = model.predict(X)[0][0]
        pred_close = inverse_scale(pred_norm)

        last_date = pd.to_datetime(df["date"].iloc[-1])
        next_date = (last_date + pd.Timedelta(days=1)).strftime("%Y-%m-%d")

        result = {
            "next_date": next_date,
            "predicted_norm_close": float(pred_norm),
            "predicted_close": float(pred_close),
            "scaler_used": {"min": CLOSE_MIN, "max": CLOSE_MAX},
            "features_used": FEATURE_ORDER
        }
        return {"status": "ok", "result": result}

    except Exception as e:
        return {"status": "error", "message": str(e)}

@app.get("/")
def root():
    return {"message": "Forex LSTM Prediction API is active!"}