154 lines
5.0 KiB
Python
154 lines
5.0 KiB
Python
from fastapi import FastAPI, Request
|
|
from fastapi.responses import HTMLResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from fastapi.templating import Jinja2Templates
|
|
from contextlib import asynccontextmanager
|
|
import uvicorn
|
|
import logging
|
|
import os
|
|
from datetime import datetime
|
|
|
|
from main import GoldMarketAnalysisSystem
|
|
from config import GOLD_TICKER_SYMBOLS
|
|
|
|
# Logging mit Rich
|
|
from rich.logging import RichHandler
|
|
logging.basicConfig(
|
|
level="INFO",
|
|
format="%(message)s",
|
|
datefmt="[%X]",
|
|
handlers=[RichHandler(rich_tracebacks=True)]
|
|
)
|
|
logger = logging.getLogger("server")
|
|
|
|
# Global System Initialisierung
|
|
system: GoldMarketAnalysisSystem = None
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
global system
|
|
logger.info("🌲 Gold Forest Watchtower wird errichtet...")
|
|
try:
|
|
system = GoldMarketAnalysisSystem()
|
|
logger.info("🦉 Eule hat Platz genommen. System bereit.")
|
|
except Exception as e:
|
|
logger.error(f"Fehler beim Starten des Systems: {e}")
|
|
yield
|
|
logger.info("Beende Watchtower...")
|
|
|
|
app = FastAPI(title="Gold Forest Watchtower", lifespan=lifespan)
|
|
|
|
# Templates setup
|
|
templates = Jinja2Templates(directory="templates")
|
|
|
|
@app.get("/", response_class=HTMLResponse)
|
|
async def read_root(request: Request):
|
|
return templates.TemplateResponse("index.html", {"request": request})
|
|
|
|
@app.get("/api/stats")
|
|
async def get_stats():
|
|
"""Liefert aktuelle Marktstatistiken"""
|
|
if not system:
|
|
return {"error": "System not initialized"}
|
|
|
|
try:
|
|
# Aktuellen Preis laden (GC=F)
|
|
ticker_key = "GC"
|
|
current_data = system.yahoo_collector.get_realtime_data(ticker_key)
|
|
|
|
# News/Sentiment
|
|
news = system.news_collector.get_all_news(hours_back=24)
|
|
sentiment = system.news_collector.aggregate_sentiment(news)
|
|
|
|
# Technische Indikatoren berechnen (Historische Daten holen und berechnen)
|
|
hist_data = system.yahoo_collector.get_historical_data(ticker_key, period="1mo", interval="1h")
|
|
indicators = system.indicator_calculator.calculate_all_indicators(hist_data)
|
|
latest_ind = indicators.iloc[-1].to_dict()
|
|
|
|
return {
|
|
"price": current_data.get("price", 0),
|
|
"change": current_data.get("change", 0),
|
|
"percent": current_data.get("percent", 0),
|
|
"timestamp": current_data.get("timestamp"),
|
|
"sentiment": {
|
|
"score": sentiment["average_score"],
|
|
"label": sentiment["sentiment_label"],
|
|
"count": sentiment["article_count"]
|
|
},
|
|
"technical": {
|
|
"rsi": float(latest_ind.get("RSI_14", 50)),
|
|
"macd": float(latest_ind.get("MACD_12_26", 0)),
|
|
"bb_upper": float(latest_ind.get("BB_upper_20", 0)),
|
|
"bb_lower": float(latest_ind.get("BB_lower_20", 0))
|
|
}
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"API Error: {e}")
|
|
return {"error": str(e)}
|
|
|
|
@app.get("/api/history")
|
|
async def get_history():
|
|
"""Liefert historische Daten für Charts"""
|
|
if not system:
|
|
return {"error": "System not initialized"}
|
|
|
|
try:
|
|
hist_data = system.yahoo_collector.get_historical_data("GC", period="7d", interval="1h")
|
|
indicators = system.indicator_calculator.calculate_all_indicators(hist_data)
|
|
|
|
# Letzte 100 Punkte
|
|
df = indicators.tail(100)
|
|
|
|
return {
|
|
"dates": df.index.strftime("%Y-%m-%d %H:%M").tolist(),
|
|
"prices": df["Close"].tolist(),
|
|
"bb_upper": df["BB_upper_20"].fillna(0).tolist(),
|
|
"bb_lower": df["BB_lower_20"].fillna(0).tolist()
|
|
}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
@app.get("/api/news")
|
|
async def get_latest_news():
|
|
"""Liefert die letzten News"""
|
|
if not system:
|
|
return []
|
|
|
|
try:
|
|
news = system.news_collector.get_all_news(hours_back=24)
|
|
return news[:6] # Top 6
|
|
except Exception as e:
|
|
return [{"title": "Fehler beim Laden der News", "source": "System", "sentiment_label": "Neutral"}]
|
|
|
|
@app.get("/api/breath")
|
|
async def get_system_breath():
|
|
"""Liefert den ökologischen Atem des Systems"""
|
|
from CO2.breath import ForestBreath
|
|
|
|
# Singleton-like usage for demo (better: store in system)
|
|
fb = ForestBreath()
|
|
|
|
# 1. System Breath (Realtime)
|
|
sys_breath = fb.get_system_breath()
|
|
|
|
# 2. Gold Impact (Theoretical for 1 GC Contract ~ 100oz -> $200k+ but let's use current price)
|
|
price = 2500.0 # Fallback
|
|
if system:
|
|
try:
|
|
realtime = system.yahoo_collector.get_realtime_data("GC")
|
|
price = realtime.get("current_price", 2500.0)
|
|
except:
|
|
pass
|
|
|
|
# Impact for 1 oz investment
|
|
gold_impact = fb.get_gold_pricing_ecology(price)
|
|
|
|
return {
|
|
"system": sys_breath,
|
|
"gold_impact_1oz": gold_impact,
|
|
"breath_state": "Exhale" # Placeholder, could be dynamic based on volatility
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
uvicorn.run("server:app", host="0.0.0.0", port=8000, reload=True)
|