Files
links/invest/template_views.py
T
OpenClaw Sub-agent 8d05a11eb6 feat(invest): Add investment portfolio management feature
- Portfolio management (MOMO, IBKR personal, IBKR Yanhua)
- Stock holdings with transaction history (buy/sell)
- Weekly AI report generation
- Real-time price cache via Finnhub API
- Dashboard with tree view and performance charts
- REST API with AI-friendly batch update endpoint
- Management command for scheduled report generation

For大哥's personal investment advisor system.
2026-04-18 11:26:48 +10:00

81 lines
2.6 KiB
Python

"""Template views for the invest app."""
import json
import logging
from django.shortcuts import render, get_object_or_404
from .models import Portfolio, Report
from .services import portfolio_summary
logger = logging.getLogger(__name__)
def dashboard(request):
"""Landing page: list of portfolios with key metrics."""
portfolios = Portfolio.objects.prefetch_related('stocks').order_by('name')
summaries = []
for portfolio in portfolios:
try:
s = portfolio_summary(portfolio)
except Exception as exc:
logger.warning("portfolio_summary failed for %s: %s", portfolio.id, exc)
s = {
'portfolio': {'id': portfolio.id, 'name': portfolio.name},
'stocks': [],
'total_cost': 0,
'total_market_value': 0,
'total_unrealized_pnl': 0,
'total_unrealized_pnl_pct': 0,
}
summaries.append(s)
return render(request, 'invest/dashboard.html', {'summaries': summaries})
def portfolio_detail(request, pk):
"""Portfolio detail view with holdings table and allocation chart."""
portfolio = get_object_or_404(Portfolio, pk=pk)
try:
summary = portfolio_summary(portfolio)
except Exception as exc:
logger.error("portfolio_summary failed for %s: %s", pk, exc)
summary = {
'portfolio': {'id': portfolio.id, 'name': portfolio.name},
'stocks': [],
'total_cost': 0,
'total_market_value': 0,
'total_unrealized_pnl': 0,
'total_unrealized_pnl_pct': 0,
}
return render(request, 'invest/portfolio_detail.html', {
'portfolio': portfolio,
'summary': summary,
'summary_json': json.dumps(summary),
})
def portfolio_transactions(request, pk):
"""Transaction history for a portfolio."""
from .models import Transaction
portfolio = get_object_or_404(Portfolio, pk=pk)
transactions = Transaction.objects.filter(
stock__portfolio=portfolio
).select_related('stock').order_by('-date', '-created_at')
return render(request, 'invest/transactions.html', {
'portfolio': portfolio,
'transactions': transactions,
})
def reports_list(request):
"""List of all generated reports."""
reports = Report.objects.select_related('portfolio').order_by('-generated_at')
return render(request, 'invest/reports.html', {'reports': reports})
def report_detail(request, pk):
"""Single report view."""
report = get_object_or_404(Report.objects.select_related('portfolio'), pk=pk)
return render(request, 'invest/report_detail.html', {'report': report})