Developer GuideAPI Reference

API Reference

Extension interfaces and module entry points for integrating or extending Copinance OS. All contracts are defined as typing.Protocol under copinance_os.domain.ports; implementations live in data, ai, and infra.

Data providers

Implement these interfaces to plug in custom market, fundamental, alternative, or macro data sources. All methods are async. Defined in copinance_os.domain.ports.data_providers.

MarketDataProvider

Extends DataProvider (is_available, get_provider_name).

get_quote(symbol: str) -> dict[str, Any]
get_historical_data(symbol, start_date, end_date, interval) -> list[MarketDataPoint]
get_intraday_data(symbol, interval) -> list[MarketDataPoint]
search_instruments(query, limit) -> list[dict[str, Any]]
get_options_chain(underlying_symbol, expiration_date=None) -> OptionsChain

Each call returns one OptionsChain for a single selected expiry (or the provider default when expiration_date is omitted). The LLM-facing get_options_chain tool in Market data tools can pass expiration_dates and performs multiple provider calls when needed.

The question-driven registry also exposes get_options_positioning (market data tools): quote + default full chain, then aggregate surface metrics from data.analytics.options.positioning (including GEX, vanna/charm, mispricing, moneyness, pin risk when computable) plus a required methodology envelope (AnalysisMethodology: version, computed_at, specs, data_inputs) for transparent client rendering.

The default container exposes a composed MarketDataProvider (OptionAnalyticsMarketDataProvider) that fetches chains and then runs BSM Greek estimation (first- and higher-order fields on OptionGreeks when inputs are valid). Vendor-only adapters live under copinance_os.data.providers.

FundamentalDataProvider

get_financial_statements(symbol, statement_type, period) -> dict[str, Any]
get_sec_filings(symbol, filing_types, limit) -> list[dict[str, Any]]
get_earnings_transcripts(symbol, limit) -> list[dict[str, Any]]
get_esg_metrics(symbol) -> dict[str, Any]
get_insider_trading(symbol, lookback_days) -> list[dict[str, Any]]
get_detailed_fundamentals(symbol, periods, period_type) -> StockFundamentals

Built-in implementations:

ClassRole
YFinanceFundamentalProviderDefault fundamental provider: market-driven statements and ratios
EdgarToolsFundamentalProvider (data.providers.sec.edgartools)SEC EDGAR: filing lists, content, extended financial and SEC tools

MacroeconomicDataProvider

get_time_series(series_id, start_date, end_date, *, frequency=None) -> list[MacroDataPoint]

AlternativeDataProvider

get_sentiment_data(symbol, ...) -> dict[str, Any]
get_web_traffic_metrics(domain, ...) -> dict[str, Any]
get_satellite_imagery_insights(location, ...) -> dict[str, Any]
get_supply_chain_data(symbol, ...) -> dict[str, Any]
get_transaction_data(symbol, ...) -> dict[str, Any]

No built-in implementation; wire your own in infra/di/.

Market data point coercion

Helpers in copinance_os.data.schemas.market_data_conversions normalize mixed sequences (dicts and MarketDataPoint instances) into sorted lists:

  • coerce_sorted_market_data_points(..., strict=False) — drops invalid entries; logs a warning with skip counts.
  • coerce_sorted_market_data_points_detailed — returns CoerceMarketDataPointsResult with per-category counts.
  • strict=True — raises ValueError / TypeError on first invalid entry instead of skipping.

Analytics

OptionsChainGreeksEstimator

estimate_bsm_greeks_for_options_chain(chain: OptionsChain, profile=None) -> OptionsChain

Default implementation: QuantLibBsmGreekEstimator (copinance_os.data.analytics.options). European BSM via QuantLib’s AnalyticEuropeanEngine, with additional closed-form higher-order sensitivities and NPV/ITM fields merged onto OptionGreeks when available. See Options & Greeks for full detail.


LLM providers

Defined in copinance_os.ai.llm.providers.base (LLMProvider).

generate_text(prompt, ...) -> str
generate_with_tools(prompt, tools, ...) -> dict[str, Any]
generate_text_stream(prompt, ...) -> AsyncGenerator[LLMTextStreamEvent, None]

LLMTextStreamEvent fields: kind (text_delta / done / error / rollback), text_delta, native_streaming, optional usage.

LLMProviderFactory (ai.llm.providers.factory) builds gemini, openai, and ollama adapters from LLMConfig. LLMAnalyzerFactory (ai.llm.analyzer_factory) wraps a provider as the LLMAnalyzer port for question-driven wiring.

Streaming detail: Library — LLM text streaming.


Orchestration

ResearchOrchestrator

copinance_os.core.orchestrator.research_orchestrator

orchestrator = container.research_orchestrator()
result: RunJobResult = await orchestrator.run_job(job, context)

DefaultJobRunner dispatches Job instances to registered AnalysisExecutor implementations. Override JobRunner for custom routing (queues, retries, multi-tenant).

AnalysisExecutorFactory

copinance_os.core.execution_engine.factory

Builds the default list[AnalysisExecutor] used by DI. Extend create_all or override container.analysis_executors for custom executor types. See Extending — Adding a Custom Executor.

Analysis requests and types

from copinance_os.domain.models.analysis import (
    AnalyzeInstrumentRequest,
    AnalyzeMarketRequest,
    execution_type_from_scope_and_mode,
    resolve_analyze_mode,
)

execution_type_from_scope_and_mode(scope, mode) derives the string discriminator that selects which executor runs.


Tools and bundles

Tool discovery in copinance_os.core.pipeline.tools.discovery:

FunctionPurpose
collect_question_driven_tools(ctx)Full tool list used by the question-driven executor
build_data_provider_tool_registry(...)Market + fundamentals preset registry
load_tools_from_plugin_specs(specs, ctx)Low-level: build tools from PluginSpec list

Bundle protocol: ToolBundleFactory (domain.ports.tool_bundles). Context: ToolBundleContext (domain.models.pipeline.tool_bundle_context).

Tools can also be discovered via setuptools entry point group copinance_os.tool_bundles or by package scan of modules in core.pipeline.tools.bundles that export tool_bundle_factory.


Container entry points

from copinance_os.infra.di import get_container
 
container = get_container(
    llm_config=LLMConfig(...),      # required for question-driven analysis
    fred_api_key="...",             # optional; enables FRED macro data
    storage_type="memory",          # "file" | "memory"; avoids disk in library use
    storage_path=None,              # root path for file storage
    storage_backend=None,           # custom Storage instance (Tier 1; overrides storage_type/path)
    cache_enabled=None,             # True / False / None (use settings)
    cache_manager=None,             # custom CacheManager instance
    prompt_templates=None,          # dict overlay for prompt names
    prompt_manager=None,            # full custom PromptManager
    load_from_env=True,             # try env vars for LLM if llm_config is None
)
 
# Entry points
container.research_orchestrator()                # ResearchOrchestrator
container.market_data_provider()                 # MarketDataProvider (composed, with Greeks)
container.fundamental_data_provider()            # FundamentalDataProvider (yfinance)
container.sec_filings_provider()                 # FundamentalDataProvider (EDGAR)
container.macro_data_provider()                  # MacroeconomicDataProvider (FRED/yfinance)
container.generate_market_narrative_use_case()   # GenerateMarketNarrativeUseCase
container.generate_curated_questions_use_case()  # GenerateCuratedQuestionsUseCase

Full options and examples: Library Guide — Configuration.


Curated questions use case

GenerateCuratedQuestionsUseCase (research/workflows/curated_questions.py) turns an already-fetched JSON payload into LLM-suggested follow-up questions for Ask AI chips. It does not fetch market data.

from copinance_os import (
    ArtifactType,
    CuratedQuestionsBlock,
    GenerateCuratedQuestionsRequest,
    FinancialLiteracy,
)
from copinance_os.ai.llm.config import LLMConfig
from copinance_os.infra.di import get_container
 
container = get_container(llm_config=LLMConfig(provider="openai", api_key="sk-..."))
block: CuratedQuestionsBlock = await container.generate_curated_questions_use_case().execute(
    GenerateCuratedQuestionsRequest(
        artifact=ArtifactType.OPTIONS_CHAIN,
        payload=chain.model_dump(mode="json"),
        count=5,
        financial_literacy=FinancialLiteracy.INTERMEDIATE,
    ),
    llm_provider_override=user_provider,  # optional per-request LLM
)
SymbolRole
ArtifactTypePayload shape: options_chain, quote, historical_bars, instrument, fundamentals, market_regime, macro_snapshot, sector_rotation, upcoming_events, watchlist_risk, options_positioning
GenerateCuratedQuestionsRequestartifact, payload, count (1–10), financial_literacy, optional learning_step, no_cache
CuratedQuestionsBlockquestions: list[CuratedQuestion], meta: CuratedQuestionsMeta
CuratedQuestiontext, focus, suggested_tools, requires_symbol
LLMUnavailableReasonno_llm_config, provider_error, parse_error, rate_limited, timeout

Flow: validate payload → optional cache hit → deterministic context summary (data/curated_questions/context.py) → LLM JSON (ai/llm/resources/curated_questions.json) → filter suggested_tools against collect_question_driven_tools names.

Client integration patterns: Curated questions (clients).


Domain utilities (public API)

These standalone functions are re-exported from copinance_os root and require no container.

SymbolModulePurpose
regime_confidence_score(confidence)copinance_os.domain.models.regimeMaps "high"/"medium"/"low" or float → int 0–100 for regime snapshot storage and comparison across snapshots
signal_agreement_direction(agreement)copinance_os.data.analytics.options.positioning.biasMaps SignalAgreement string → "bullish"/"bearish"/"neutral" tri-state
iv_percentile_rank(current_iv, history)copinance_os.data.analytics.options.positioning.iv_rankIV percentile rank (0–100) from a caller-supplied rolling history sequence

Curated questions types (also on copinance_os root): ArtifactType, GenerateCuratedQuestionsRequest, CuratedQuestionsBlock, CuratedQuestion, CuratedQuestionsMeta, LLMUnavailableReason — see Curated questions use case.

from copinance_os import regime_confidence_score, signal_agreement_direction, iv_percentile_rank
 
# Regime confidence — store as int for comparison, charts, or thresholds
score = regime_confidence_score("high")   # → 85
score = regime_confidence_score(0.72)     # → 72
 
# Options signal direction — tri-state summary for UI chips / filters
direction = signal_agreement_direction("strong_bullish")   # → "bullish"
direction = signal_agreement_direction("mixed")            # → "neutral"
 
# IV percentile rank — caller owns the rolling IV history
rank = iv_percentile_rank(current_iv=0.28, history=[0.15, 0.20, 0.25, 0.30, 0.35])  # → 60

Persistence note: regime_confidence_score is designed for consumers who want to store regime snapshots (e.g. in Postgres) and compare confidence values numerically. Copinance OS produces the regime data; you own the persistence.


Ports reference

All extension contracts live in src/copinance_os/domain/ports/:

FileInterfaces
data_providers.pyMarketDataProvider, FundamentalDataProvider, MacroeconomicDataProvider, AlternativeDataProvider
analytics.pyOptionsChainGreeksEstimator
analyzers.pyLLMAnalyzer
analysis_execution.pyJobRunner, AnalysisExecutor
repositories.pyStockRepository, AnalysisProfileRepository
storage.pyStorage, CacheBackend
tools.pyTool, ToolSchema, ToolParameter
tool_bundles.pyToolBundleFactory
strategies.pyScreening, due diligence, valuation, risk, thematic, monitoring protocols

Step-by-step implementation: Extending.