GoshawkVortexAI's picture
Update app.py
a7560e3 verified
# ============================================================
# PORTFOLIO INTELLIGENCE ENGINE - FULL APP.PY
# Live + Historical Data Enabled
# ============================================================
import yfinance as yf
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from scipy.optimize import minimize
from scipy import stats
from dataclasses import dataclass
from typing import Dict, List
import warnings
warnings.filterwarnings("ignore")
# ============================================================
# DATA ENGINE
# ============================================================
class MarketDataLoader:
def __init__(self, lookback_days=365, interval="1d"):
self.lookback_days = lookback_days
self.interval = interval
def fetch(self, symbols: List[str]) -> Dict[str, pd.DataFrame]:
end = datetime.now()
start = end - timedelta(days=self.lookback_days)
data = {}
for s in symbols:
df = yf.download(
s,
start=start.strftime("%Y-%m-%d"),
end=end.strftime("%Y-%m-%d"),
interval=self.interval,
auto_adjust=True,
progress=False
)
if not df.empty:
data[s] = df[["Open", "High", "Low", "Close", "Volume"]].dropna()
return data
# ============================================================
# AI FORECAST ENGINE (PROXY)
# ============================================================
class SimpleAIForecaster:
def forecast(self, prices: pd.Series, horizon=30) -> Dict:
returns = np.log(prices / prices.shift(1)).dropna()
mu = returns.mean() * horizon
sigma = returns.std() * np.sqrt(horizon)
samples = np.random.normal(mu, sigma, 1000)
return {
"samples": samples,
"expected_return": mu,
"confidence": float(np.clip(1 / (1 + sigma * 10), 0.3, 0.9))
}
# ============================================================
# REGIME DETECTOR
# ============================================================
class RegimeDetector:
def detect(self, returns: pd.Series) -> Dict:
vol = returns.std() * np.sqrt(252)
momentum = returns.rolling(20).mean().iloc[-1]
if momentum > 0 and vol < 0.25:
return {"regime": "bull", "confidence": 0.7}
elif momentum < 0:
return {"regime": "bear", "confidence": 0.7}
else:
return {"regime": "sideways", "confidence": 0.6}
# ============================================================
# FEATURE ENGINE
# ============================================================
@dataclass
class AssetFeature:
symbol: str
expected_return: float
confidence: float
volatility: float
returns: pd.Series
regime: str
class FeatureBuilder:
def build(self, symbol, df, forecast, regime) -> AssetFeature:
returns = np.log(df["Close"] / df["Close"].shift(1)).dropna()
vol = returns.std() * np.sqrt(252)
return AssetFeature(
symbol=symbol,
expected_return=forecast["expected_return"] * forecast["confidence"],
confidence=forecast["confidence"],
volatility=vol,
returns=returns,
regime=regime["regime"]
)
# ============================================================
# OPTIMIZATION ENGINE
# ============================================================
class Optimizer:
def optimize(self, features: List[AssetFeature]) -> np.ndarray:
returns = np.array([f.expected_return for f in features])
returns = np.clip(returns, -0.5, 0.5)
returns_df = pd.concat(
[f.returns for f in features],
axis=1
)
returns_df.columns = [f.symbol for f in features]
cov = returns_df.cov().values
n = len(features)
def objective(w):
port_ret = w @ returns
port_vol = np.sqrt(w @ cov @ w)
return -(port_ret / (port_vol + 1e-8))
bounds = [(0.05, 0.5) for _ in range(n)]
cons = [{"type": "eq", "fun": lambda w: np.sum(w) - 1}]
w0 = np.ones(n) / n
res = minimize(objective, w0, bounds=bounds, constraints=cons)
return res.x if res.success else w0
# ============================================================
# RISK ANALYTICS
# ============================================================
class RiskEngine:
def analyze(self, weights, features):
returns = np.array([f.expected_return for f in features])
returns_df = pd.concat([f.returns for f in features], axis=1)
cov = returns_df.cov().values
port_ret = weights @ returns
port_vol = np.sqrt(weights @ cov @ weights)
sharpe = (port_ret - 0.04) / port_vol if port_vol > 0 else 0
return {
"expected_return": port_ret,
"volatility": port_vol,
"sharpe": sharpe
}
# ============================================================
# MAIN ORCHESTRATOR
# ============================================================
class PortfolioApp:
def __init__(self, symbols):
self.symbols = symbols
self.data_loader = MarketDataLoader()
self.forecaster = SimpleAIForecaster()
self.regime_detector = RegimeDetector()
self.feature_builder = FeatureBuilder()
self.optimizer = Optimizer()
self.risk_engine = RiskEngine()
def run(self):
market_data = self.data_loader.fetch(self.symbols)
features = []
for s, df in market_data.items():
forecast = self.forecaster.forecast(df["Close"])
returns = np.log(df["Close"] / df["Close"].shift(1)).dropna()
regime = self.regime_detector.detect(returns)
feature = self.feature_builder.build(s, df, forecast, regime)
features.append(feature)
weights = self.optimizer.optimize(features)
risk = self.risk_engine.analyze(weights, features)
print("\n📊 PORTFÖY SONUCU\n")
for i, f in enumerate(features):
print(f"{f.symbol:5s} | Weight: {weights[i]:.2%} | Regime: {f.regime}")
print("\n--- RISK METRICS ---")
print(f"Expected Return : {risk['expected_return']:.2%}")
print(f"Volatility : {risk['volatility']:.2%}")
print(f"Sharpe Ratio : {risk['sharpe']:.2f}")
# ============================================================
# RUN
# ============================================================
if __name__ == "__main__":
symbols = ["XOM", "GOOGL", "WMT", "JNJ"]
app = PortfolioApp(symbols)
app.run()