Files
IBKR-Full-Stack-Trading-Das…/routers/portfolio.py
T
coddard eabc96371b Enhance Docker support and configuration
- Updated .env.example to recommend using docker.env and secrets for sensitive data.
- Modified .gitignore to include docker.env and secrets directory.
- Adjusted docker-compose.yml to utilize environment files and updated port mappings.
- Implemented read_env_or_file utility for better environment variable management.
- Refactored portfolio and trades routers to use the new utility for fetching environment variables.
- Added integration and phase 2 test updates for new environment variable handling.
- Created new documentation for Docker operations and secret management.
- Added placeholder files for Docker secrets and configuration.
2026-05-19 01:49:11 +03:00

93 lines
2.5 KiB
Python

import os
import time
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from ib_async import IB
import dependencies
router = APIRouter(prefix="/portfolio")
templates = Jinja2Templates(directory="templates")
def _extract_summary_values(summary) -> dict:
keys = {"NetLiquidation", "TotalCashValue", "UnrealizedPnL", "RealizedPnL"}
result = {}
for item in summary:
if item.tag in keys:
try:
result[item.tag] = float(item.value)
except (ValueError, TypeError):
result[item.tag] = item.value
return result
def _extract_cached_account_values(ib) -> dict:
getter = getattr(ib, "accountValues", None)
if getter is None:
return {}
return _extract_summary_values(getter() or [])
async def _read_summary_values(ib) -> dict:
result = _extract_cached_account_values(ib)
if result:
return result
summary = await ib.reqAccountSummaryAsync()
result = _extract_summary_values(summary)
if result:
return result
return _extract_cached_account_values(ib)
async def _fetch_summary_with_fallback() -> dict:
ib = dependencies.get_ib()
result = await _read_summary_values(ib)
if result:
return result
# A fresh client recovers account summary when the shared session returns an empty snapshot.
fallback_ib = IB()
host = os.getenv("IBKR_HOST", "127.0.0.1")
port = int(os.getenv("IBKR_PORT", "7497"))
client_id = int(time.time()) % 100000 + 5000
try:
await fallback_ib.connectAsync(host, port, clientId=client_id)
return await _read_summary_values(fallback_ib)
finally:
fallback_ib.disconnect()
@router.get("", response_class=HTMLResponse)
async def portfolio_page(request: Request):
return templates.TemplateResponse(request, "portfolio.html", {})
@router.get("/data")
async def portfolio_data():
try:
ib = dependencies.get_ib()
positions = ib.positions()
return [
{
"symbol": pos.contract.symbol,
"position": pos.position,
"avg_cost": pos.avgCost,
}
for pos in positions
]
except Exception as e:
return {"error": str(e)}
@router.get("/pnl")
async def portfolio_pnl():
try:
return await _fetch_summary_with_fallback()
except Exception as e:
return {"error": str(e)}