Extending Copinance OS
Add custom data providers, analyzers, and strategies.
Adding a Custom Data Provider
Step 1: Choose Interface
Select the appropriate interface from copinanceos.domain.ports.data_providers:
MarketDataProvider- Market data (quotes, historical prices)FundamentalDataProvider- Financial statements, SEC filingsAlternativeDataProvider- Sentiment, web traffic, alternative dataMacroeconomicDataProvider- Economic indicators
Step 2: Implement the Interface
from copinanceos.domain.ports.data_providers import MarketDataProvider
from copinanceos.domain.models.stock import StockData
from datetime import datetime
from typing import Any
import httpx
class AlphaVantageProvider(MarketDataProvider):
"""Alpha Vantage market data provider."""
def __init__(self, api_key: str):
self.api_key = api_key
self._client = httpx.AsyncClient()
async def is_available(self) -> bool:
"""Check if provider is available."""
try:
# Test API connection
return True
except Exception:
return False
def get_provider_name(self) -> str:
return "alpha_vantage"
async def get_quote(self, symbol: str) -> dict[str, Any]:
"""Get current quote."""
response = await self._client.get(
"https://www.alphavantage.co/query",
params={
"function": "GLOBAL_QUOTE",
"symbol": symbol,
"apikey": self.api_key,
}
)
data = response.json()
quote = data.get("Global Quote", {})
return {
"symbol": symbol,
"current_price": float(quote.get("05. price", "0")),
"volume": int(quote.get("06. volume", "0")),
# ... map other fields
}
async def get_historical_data(
self,
symbol: str,
start_date: datetime,
end_date: datetime,
interval: str = "1d",
) -> list[StockData]:
"""Get historical data."""
# Implementation here
# Convert API response to list[StockData]
return []
async def get_intraday_data(
self,
symbol: str,
interval: str = "1min",
) -> list[StockData]:
"""Get intraday data."""
return []
async def search_stocks(self, query: str, limit: int = 10) -> list[dict[str, Any]]:
"""Search for stocks."""
return []Step 3: Register in Container
from copinanceos.infrastructure.containers import Container
from dependency_injector import providers
container = Container()
container.market_data_provider.override(
providers.Singleton(AlphaVantageProvider, api_key="your-key")
)Step 4: Use in Workflows
The provider will automatically be used by workflows that need market data.
Adding a Custom Analyzer
1. Implement the Interface
from copinanceos.domain.ports.analyzers import LLMAnalyzer
from typing import Any
class MyCustomAnalyzer(LLMAnalyzer):
"""Custom LLM analyzer."""
async def analyze(self, prompt: str, context: dict[str, Any]) -> str:
"""Analyze using custom logic."""
# Your implementation
return "Analysis result"2. Register in Container
Similar to data providers, override the analyzer in your container.
Adding a Custom Workflow
1. Extend BaseWorkflowExecutor
from copinanceos.infrastructure.workflows.base import BaseWorkflowExecutor
from copinanceos.domain.models.research import Research
from typing import Any
class MyCustomWorkflow(BaseWorkflowExecutor):
"""Custom workflow executor."""
def get_workflow_type(self) -> str:
return "custom"
async def validate(self, research: Research) -> bool:
return research.workflow_type == "custom"
async def _execute_workflow(
self, research: Research, context: dict[str, Any]
) -> dict[str, Any]:
"""Execute custom workflow logic."""
# Your implementation
return {"status": "completed", "results": {}}2. Register in Container
Add to workflow executors factory or override in container.
Best Practices
- Follow interfaces: Implement all required methods
- Handle errors: Raise appropriate domain exceptions
- Type hints: Use proper type annotations
- Documentation: Document your implementation
- Testing: Write tests for your extensions
Available Interfaces
See src/copinanceos/domain/ports/ for all available interfaces:
data_providers.py- Data provider interfacesanalyzers.py- Analyzer interfacesstrategies.py- Strategy interfacesrepositories.py- Repository interfacesworkflows.py- Workflow interfaces