Phase 1: initial codes

This commit is contained in:
2026-05-26 11:04:27 -04:00
parent 03bff49523
commit f49a283059
32 changed files with 4194 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
from __future__ import annotations
import pandas as pd
import yfinance as yf
from core.market_data import get_quote, get_history
def calculate_pnl(positions: list[dict], quotes: dict[str, dict]) -> list[dict]:
result = []
for pos in positions:
sym = pos["symbol"]
q = quotes.get(sym, {})
price = q.get("price", 0.0)
shares = pos.get("shares", 0.0)
avg_cost = pos.get("avg_cost", 0.0)
market_value = price * shares
cost_basis = avg_cost * shares
pnl = market_value - cost_basis
pnl_pct = (pnl / cost_basis * 100) if cost_basis else 0.0
result.append({
**pos,
"price": price,
"market_value": market_value,
"cost_basis": cost_basis,
"pnl": pnl,
"pnl_pct": pnl_pct,
"change_pct": q.get("change_pct", 0.0),
})
return result
def get_benchmark_performance(period: str = "1y") -> pd.DataFrame:
return get_history("SPY", period=period)
def calculate_sector_allocation(positions: list[dict]) -> dict[str, float]:
sector_values: dict[str, float] = {}
for pos in positions:
sector = pos.get("sector", "Unknown") or "Unknown"
value = pos.get("market_value", 0.0)
sector_values[sector] = sector_values.get(sector, 0.0) + value
total = sum(sector_values.values())
if total == 0:
return {}
return {s: (v / total * 100) for s, v in sorted(sector_values.items(), key=lambda x: -x[1])}
def get_portfolio_performance(positions: list[dict], period: str = "1y") -> pd.DataFrame:
if not positions:
return pd.DataFrame()
symbols = [p["symbol"] for p in positions]
weights = {}
total_value = sum(p.get("market_value", 0) for p in positions)
if total_value == 0:
return pd.DataFrame()
for p in positions:
weights[p["symbol"]] = p.get("market_value", 0) / total_value
frames = []
for sym in symbols:
hist = get_history(sym, period=period)
if not hist.empty:
pct = hist["Close"].pct_change().fillna(0)
pct.name = sym
frames.append(pct * weights.get(sym, 0))
if not frames:
return pd.DataFrame()
combined = pd.concat(frames, axis=1).fillna(0)
portfolio_returns = combined.sum(axis=1)
portfolio_cumulative = (1 + portfolio_returns).cumprod() - 1
spy = get_history("SPY", period=period)
if not spy.empty:
spy_returns = spy["Close"].pct_change().fillna(0)
spy_cumulative = (1 + spy_returns).cumprod() - 1
return pd.DataFrame({
"portfolio": portfolio_cumulative,
"spy": spy_cumulative,
}).dropna()
return pd.DataFrame({"portfolio": portfolio_cumulative}).dropna()