feat: Refactor services architecture and update project structure
- Remove Docker-based microservices (docker-compose.yml, Makefile, Dockerfiles) - Update start-dev.sh to use backend.app:app entry point - Add shared schema and client modules for service communication - Add team coordination modules (messenger, registry, task_delegator, coordinator) - Add evaluation hooks and skill adaptation hooks - Add skill template and gateway server - Update frontend WebSocket URL configuration - Add explain components for insider and technical analysis Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
207
shared/client/trading_client.py
Normal file
207
shared/client/trading_client.py
Normal file
@@ -0,0 +1,207 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Trading service client for market data operations."""
|
||||
|
||||
import httpx
|
||||
|
||||
from shared.schema.price import PriceResponse
|
||||
from shared.schema.financial import FinancialMetricsResponse, LineItemResponse
|
||||
from shared.schema.market import InsiderTradeResponse, CompanyFactsResponse
|
||||
from shared.schema.portfolio import Portfolio
|
||||
|
||||
|
||||
class TradingServiceClient:
|
||||
"""Async client for the Trading Service API."""
|
||||
|
||||
def __init__(self, base_url: str = "http://localhost:8001"):
|
||||
"""Initialize the client with a base URL.
|
||||
|
||||
Args:
|
||||
base_url: Base URL for the trading service API.
|
||||
"""
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self._client: httpx.AsyncClient | None = None
|
||||
|
||||
async def __aenter__(self) -> "TradingServiceClient":
|
||||
self._client = httpx.AsyncClient(base_url=self.base_url, timeout=30.0)
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
||||
if self._client:
|
||||
await self._client.aclose()
|
||||
|
||||
async def get_prices(
|
||||
self,
|
||||
ticker: str,
|
||||
start_date: str | None = None,
|
||||
end_date: str | None = None,
|
||||
) -> PriceResponse:
|
||||
"""Get price data for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
start_date: Start date (YYYY-MM-DD).
|
||||
end_date: End date (YYYY-MM-DD).
|
||||
|
||||
Returns:
|
||||
PriceResponse with price data.
|
||||
"""
|
||||
params = {"ticker": ticker}
|
||||
if start_date:
|
||||
params["start_date"] = start_date
|
||||
if end_date:
|
||||
params["end_date"] = end_date
|
||||
response = await self._client.get("/api/prices", params=params)
|
||||
response.raise_for_status()
|
||||
return PriceResponse.model_validate(response.json())
|
||||
|
||||
async def get_news(
|
||||
self,
|
||||
ticker: str,
|
||||
start_date: str | None = None,
|
||||
end_date: str | None = None,
|
||||
) -> dict:
|
||||
"""Get news for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
start_date: Start date (YYYY-MM-DD).
|
||||
end_date: End date (YYYY-MM-DD).
|
||||
|
||||
Returns:
|
||||
Dictionary with news data.
|
||||
"""
|
||||
params = {"ticker": ticker}
|
||||
if start_date:
|
||||
params["start_date"] = start_date
|
||||
if end_date:
|
||||
params["end_date"] = end_date
|
||||
response = await self._client.get("/api/news", params=params)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def get_financials(
|
||||
self,
|
||||
ticker: str,
|
||||
period: str | None = None,
|
||||
limit: int | None = None,
|
||||
) -> FinancialMetricsResponse:
|
||||
"""Get financial metrics for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
period: Reporting period (e.g., "annual", "quarterly").
|
||||
limit: Maximum number of records to return.
|
||||
|
||||
Returns:
|
||||
FinancialMetricsResponse with financial data.
|
||||
"""
|
||||
params = {"ticker": ticker}
|
||||
if period:
|
||||
params["period"] = period
|
||||
if limit:
|
||||
params["limit"] = limit
|
||||
response = await self._client.get("/api/financials", params=params)
|
||||
response.raise_for_status()
|
||||
return FinancialMetricsResponse.model_validate(response.json())
|
||||
|
||||
async def get_insider_trades(
|
||||
self,
|
||||
ticker: str,
|
||||
limit: int | None = None,
|
||||
) -> InsiderTradeResponse:
|
||||
"""Get insider trades for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
limit: Maximum number of records to return.
|
||||
|
||||
Returns:
|
||||
InsiderTradeResponse with insider trade data.
|
||||
"""
|
||||
params = {"ticker": ticker}
|
||||
if limit:
|
||||
params["limit"] = limit
|
||||
response = await self._client.get("/api/insider-trades", params=params)
|
||||
response.raise_for_status()
|
||||
return InsiderTradeResponse.model_validate(response.json())
|
||||
|
||||
async def get_portfolio(self) -> Portfolio:
|
||||
"""Get the current portfolio.
|
||||
|
||||
Returns:
|
||||
Portfolio with current positions and cash.
|
||||
"""
|
||||
response = await self._client.get("/api/portfolio")
|
||||
response.raise_for_status()
|
||||
return Portfolio.model_validate(response.json())
|
||||
|
||||
async def post_trades(self, trades: list[dict]) -> dict:
|
||||
"""Submit trades for execution.
|
||||
|
||||
Args:
|
||||
trades: List of trade orders.
|
||||
|
||||
Returns:
|
||||
Dictionary with trade execution results.
|
||||
"""
|
||||
response = await self._client.post("/api/trades", json=trades)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def post_settle(self) -> dict:
|
||||
"""Settle all pending trades.
|
||||
|
||||
Returns:
|
||||
Dictionary with settlement results.
|
||||
"""
|
||||
response = await self._client.post("/api/settle")
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def get_market_status(self) -> dict:
|
||||
"""Get current market status.
|
||||
|
||||
Returns:
|
||||
Dictionary with market status information.
|
||||
"""
|
||||
response = await self._client.get("/api/market/status")
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def get_company_facts(self, ticker: str) -> CompanyFactsResponse:
|
||||
"""Get company facts for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
|
||||
Returns:
|
||||
CompanyFactsResponse with company information.
|
||||
"""
|
||||
response = await self._client.get(f"/api/company/{ticker}/facts")
|
||||
response.raise_for_status()
|
||||
return CompanyFactsResponse.model_validate(response.json())
|
||||
|
||||
async def get_line_items(
|
||||
self,
|
||||
ticker: str,
|
||||
statement_type: str | None = None,
|
||||
period: str | None = None,
|
||||
) -> LineItemResponse:
|
||||
"""Get line items (financial statement data) for a ticker.
|
||||
|
||||
Args:
|
||||
ticker: Stock ticker symbol.
|
||||
statement_type: Type of statement (income, balance, cash_flow).
|
||||
period: Reporting period.
|
||||
|
||||
Returns:
|
||||
LineItemResponse with financial statement data.
|
||||
"""
|
||||
params = {"ticker": ticker}
|
||||
if statement_type:
|
||||
params["statement_type"] = statement_type
|
||||
if period:
|
||||
params["period"] = period
|
||||
response = await self._client.get("/api/line-items", params=params)
|
||||
response.raise_for_status()
|
||||
return LineItemResponse.model_validate(response.json())
|
||||
Reference in New Issue
Block a user