Upload 3 files
Browse files- app.py +20 -8
- model.py +60 -22
- requirements.txt +0 -1
app.py
CHANGED
|
@@ -36,6 +36,10 @@ app = Flask(__name__)
|
|
| 36 |
CORS(app)
|
| 37 |
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
# [OPT-A] Lightweight TF smoke-test instead of building & running a full LSTM
|
| 40 |
def validate_tensorflow():
|
| 41 |
"""Quick TensorFlow sanity-check (no model created, no GPU required)."""
|
|
@@ -492,16 +496,24 @@ def diagnose():
|
|
| 492 |
|
| 493 |
api_status = {}
|
| 494 |
try:
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
"
|
| 500 |
-
"
|
| 501 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
}
|
| 503 |
except Exception as e:
|
| 504 |
-
api_status["
|
| 505 |
|
| 506 |
try:
|
| 507 |
headers = {"X-Finnhub-Token": stock_model.FINNHUB_API_KEY}
|
|
|
|
| 36 |
CORS(app)
|
| 37 |
|
| 38 |
|
| 39 |
+
@app.route("/", methods=["GET"])
|
| 40 |
+
def home():
|
| 41 |
+
return jsonify({"status": "running", "message": "StockBuddy API is live!"})
|
| 42 |
+
|
| 43 |
# [OPT-A] Lightweight TF smoke-test instead of building & running a full LSTM
|
| 44 |
def validate_tensorflow():
|
| 45 |
"""Quick TensorFlow sanity-check (no model created, no GPU required)."""
|
|
|
|
| 496 |
|
| 497 |
api_status = {}
|
| 498 |
try:
|
| 499 |
+
url = "https://www.alphavantage.co/query"
|
| 500 |
+
params = {
|
| 501 |
+
"function": "TIME_SERIES_DAILY",
|
| 502 |
+
"symbol": "AAPL",
|
| 503 |
+
"apikey": stock_model.ALPHAVANTAGE_API_KEY,
|
| 504 |
+
"outputsize": "compact",
|
| 505 |
+
"datatype": "json",
|
| 506 |
+
}
|
| 507 |
+
resp = requests.get(url, params=params)
|
| 508 |
+
rj = resp.json()
|
| 509 |
+
api_status["alpha_vantage"] = {
|
| 510 |
+
"status_code": resp.status_code,
|
| 511 |
+
"has_data": "Time Series (Daily)" in rj,
|
| 512 |
+
"error": rj.get("Error Message") or rj.get("Note") or rj.get("Information")
|
| 513 |
+
if "Time Series (Daily)" not in rj else None,
|
| 514 |
}
|
| 515 |
except Exception as e:
|
| 516 |
+
api_status["alpha_vantage"] = {"error": str(e)}
|
| 517 |
|
| 518 |
try:
|
| 519 |
headers = {"X-Finnhub-Token": stock_model.FINNHUB_API_KEY}
|
model.py
CHANGED
|
@@ -44,29 +44,67 @@ FINNHUB_API_KEY = "cu5gvghr01qqj8u6iau0cu5gvghr01qqj8u6iaug"
|
|
| 44 |
# STOCK PRICE PREDICTION FUNCTIONS
|
| 45 |
# =============================================================================
|
| 46 |
|
| 47 |
-
import yfinance as yf
|
| 48 |
-
|
| 49 |
def fetch_stock_data(symbol, outputsize="full"):
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
|
| 72 |
# [OPT-2] Reduced feature set: 11 → 6 (Close, RSI, SMA5, MACD, Upper_Band, ROC)
|
|
|
|
| 44 |
# STOCK PRICE PREDICTION FUNCTIONS
|
| 45 |
# =============================================================================
|
| 46 |
|
|
|
|
|
|
|
| 47 |
def fetch_stock_data(symbol, outputsize="full"):
|
| 48 |
+
url = "https://www.alphavantage.co/query"
|
| 49 |
+
params = {
|
| 50 |
+
"function": "TIME_SERIES_DAILY",
|
| 51 |
+
"symbol": symbol,
|
| 52 |
+
"apikey": ALPHAVANTAGE_API_KEY,
|
| 53 |
+
"outputsize": outputsize,
|
| 54 |
+
"datatype": "json",
|
| 55 |
+
}
|
| 56 |
+
response = requests.get(url, params=params)
|
| 57 |
+
data = response.json()
|
| 58 |
+
|
| 59 |
+
if "Time Series (Daily)" not in data:
|
| 60 |
+
if "Error Message" in data:
|
| 61 |
+
raise ValueError(
|
| 62 |
+
f"Symbol '{symbol}' not found. Please verify the stock symbol.")
|
| 63 |
+
elif "Note" in data:
|
| 64 |
+
raise ValueError("API request limit reached. Please try again in a minute.")
|
| 65 |
+
elif "Information" in data:
|
| 66 |
+
raise ValueError(f"Alpha Vantage API daily limit reached. Please try again tomorrow. Details: {data['Information']}")
|
| 67 |
+
else:
|
| 68 |
+
raise ValueError(
|
| 69 |
+
f"Unable to fetch data for symbol '{symbol}'. Please verify the symbol.")
|
| 70 |
+
|
| 71 |
+
ts = data["Time Series (Daily)"]
|
| 72 |
+
|
| 73 |
+
df = pd.DataFrame.from_dict(ts, orient="index")
|
| 74 |
+
df.index = pd.to_datetime(df.index)
|
| 75 |
+
df.sort_index(inplace=True)
|
| 76 |
+
|
| 77 |
+
for col in ["1. open", "2. high", "3. low", "4. close", "5. volume"]:
|
| 78 |
+
if col in df.columns:
|
| 79 |
+
df[col] = df[col].astype(float)
|
| 80 |
+
|
| 81 |
+
df = df.rename(columns={
|
| 82 |
+
"1. open": "Open",
|
| 83 |
+
"2. high": "High",
|
| 84 |
+
"3. low": "Low",
|
| 85 |
+
"4. close": "Close",
|
| 86 |
+
"5. volume": "Volume",
|
| 87 |
+
})
|
| 88 |
+
|
| 89 |
+
latest_date = df.index[-1]
|
| 90 |
+
today = pd.Timestamp.now().normalize()
|
| 91 |
+
market_closed_days = 0
|
| 92 |
+
if today.dayofweek >= 5:
|
| 93 |
+
market_closed_days = today.dayofweek - 4
|
| 94 |
+
elif today.hour < 16:
|
| 95 |
+
market_closed_days = 1
|
| 96 |
+
expected_latest = today - pd.Timedelta(days=market_closed_days)
|
| 97 |
+
date_diff = (expected_latest - latest_date).days
|
| 98 |
+
if date_diff > 5:
|
| 99 |
+
print(f"WARNING: Latest data for {symbol} is from "
|
| 100 |
+
f"{latest_date.strftime('%Y-%m-%d')} ({date_diff} days old).")
|
| 101 |
+
|
| 102 |
+
print(f"\nLatest closing price for {symbol} "
|
| 103 |
+
f"(as of {latest_date.strftime('%Y-%m-%d')}): ${df['Close'].iloc[-1]:.2f}")
|
| 104 |
+
|
| 105 |
+
# Add lightweight technical indicators
|
| 106 |
+
df = add_technical_indicators(df)
|
| 107 |
+
return df
|
| 108 |
|
| 109 |
|
| 110 |
# [OPT-2] Reduced feature set: 11 → 6 (Close, RSI, SMA5, MACD, Upper_Band, ROC)
|
requirements.txt
CHANGED
|
@@ -11,4 +11,3 @@ transformers==4.33.2
|
|
| 11 |
plotly==5.17.0
|
| 12 |
gunicorn==21.2.0
|
| 13 |
tf-keras==2.15.0
|
| 14 |
-
yfinance==0.2.40
|
|
|
|
| 11 |
plotly==5.17.0
|
| 12 |
gunicorn==21.2.0
|
| 13 |
tf-keras==2.15.0
|
|
|