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!"}
|