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.
This commit is contained in:
+55
-11
@@ -1,6 +1,10 @@
|
||||
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
|
||||
|
||||
@@ -8,6 +12,56 @@ 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", {})
|
||||
@@ -33,16 +87,6 @@ async def portfolio_data():
|
||||
@router.get("/pnl")
|
||||
async def portfolio_pnl():
|
||||
try:
|
||||
ib = dependencies.get_ib()
|
||||
summary = await ib.reqAccountSummaryAsync()
|
||||
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
|
||||
return await _fetch_summary_with_fallback()
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user