You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
7.4 KiB
Python
175 lines
7.4 KiB
Python
"""
|
|
Database models for SEC financial data
|
|
"""
|
|
|
|
from sqlalchemy import Column, String, Float, DateTime, Integer, JSON, Boolean, UniqueConstraint, Index
|
|
from sqlalchemy.dialects.postgresql import UUID, TIMESTAMP
|
|
from datetime import datetime, timezone
|
|
import uuid
|
|
from app.core.database import Base
|
|
|
|
class Company(Base):
|
|
__tablename__ = "companies"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
ticker = Column(String(10), unique=True, nullable=False, index=True)
|
|
name = Column(String(255), nullable=False)
|
|
cik = Column(String(20), unique=True, nullable=True)
|
|
sector = Column(String(100), nullable=True)
|
|
industry = Column(String(100), nullable=True)
|
|
business_description = Column(String, nullable=True)
|
|
created_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
__table_args__ = (
|
|
Index('idx_company_ticker', 'ticker'),
|
|
Index('idx_company_cik', 'cik'),
|
|
)
|
|
|
|
class FinancialData(Base):
|
|
__tablename__ = "financial_data"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
ticker = Column(String(10), nullable=False, index=True)
|
|
period_date = Column(TIMESTAMP(timezone=True), nullable=False)
|
|
period_type = Column(String(10), nullable=False) # 'quarterly' or 'annual'
|
|
filing_type = Column(String(10), nullable=True) # '10-K', '10-Q', etc.
|
|
|
|
# Income Statement
|
|
revenue = Column(Float, nullable=True)
|
|
gross_profit = Column(Float, nullable=True)
|
|
operating_income = Column(Float, nullable=True)
|
|
net_income = Column(Float, nullable=True)
|
|
eps = Column(Float, nullable=True)
|
|
|
|
# Balance Sheet
|
|
total_assets = Column(Float, nullable=True)
|
|
total_equity = Column(Float, nullable=True)
|
|
total_debt = Column(Float, nullable=True)
|
|
cash = Column(Float, nullable=True)
|
|
shares_outstanding = Column(Float, nullable=True)
|
|
|
|
# Cash Flow
|
|
operating_cash_flow = Column(Float, nullable=True)
|
|
free_cash_flow = Column(Float, nullable=True)
|
|
capex = Column(Float, nullable=True)
|
|
|
|
# Raw data storage (for additional fields)
|
|
raw_data = Column(JSON, nullable=True)
|
|
|
|
# Metadata
|
|
data_source = Column(String(50), default='SEC_EDGAR')
|
|
is_estimated = Column(Boolean, default=False)
|
|
created_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint('ticker', 'period_date', 'period_type', name='uq_financial_data'),
|
|
Index('idx_financial_ticker_date', 'ticker', 'period_date'),
|
|
Index('idx_financial_period', 'period_date', 'period_type'),
|
|
)
|
|
|
|
class CalculatedMetrics(Base):
|
|
__tablename__ = "calculated_metrics"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
ticker = Column(String(10), nullable=False, index=True)
|
|
calculation_date = Column(TIMESTAMP(timezone=True), nullable=False)
|
|
period_date = Column(TIMESTAMP(timezone=True), nullable=False) # The financial data period this is based on
|
|
|
|
# Valuation Ratios (require price data)
|
|
pe_ratio = Column(Float, nullable=True)
|
|
pb_ratio = Column(Float, nullable=True)
|
|
ps_ratio = Column(Float, nullable=True)
|
|
ev_ebitda = Column(Float, nullable=True)
|
|
|
|
# Profitability Metrics
|
|
roe = Column(Float, nullable=True) # Return on Equity %
|
|
roa = Column(Float, nullable=True) # Return on Assets %
|
|
gross_margin = Column(Float, nullable=True) # %
|
|
operating_margin = Column(Float, nullable=True) # %
|
|
net_margin = Column(Float, nullable=True) # %
|
|
|
|
# Growth Metrics
|
|
revenue_growth_yoy = Column(Float, nullable=True) # %
|
|
revenue_growth_qoq = Column(Float, nullable=True) # %
|
|
eps_growth_yoy = Column(Float, nullable=True) # %
|
|
eps_growth_qoq = Column(Float, nullable=True) # %
|
|
|
|
# Liquidity & Solvency
|
|
debt_to_equity = Column(Float, nullable=True)
|
|
debt_to_assets = Column(Float, nullable=True)
|
|
current_ratio = Column(Float, nullable=True)
|
|
quick_ratio = Column(Float, nullable=True)
|
|
|
|
# Efficiency
|
|
asset_turnover = Column(Float, nullable=True)
|
|
inventory_turnover = Column(Float, nullable=True)
|
|
|
|
# Cash Flow Metrics
|
|
ocf_margin = Column(Float, nullable=True) # Operating Cash Flow Margin %
|
|
fcf_margin = Column(Float, nullable=True) # Free Cash Flow Margin %
|
|
fcf_yield = Column(Float, nullable=True) # %
|
|
|
|
# Market Metrics (when price data available)
|
|
market_cap = Column(Float, nullable=True)
|
|
enterprise_value = Column(Float, nullable=True)
|
|
|
|
# Additional metrics stored as JSON
|
|
additional_metrics = Column(JSON, nullable=True)
|
|
|
|
# Metadata
|
|
created_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint('ticker', 'calculation_date', 'period_date', name='uq_calculated_metrics'),
|
|
Index('idx_metrics_ticker_date', 'ticker', 'calculation_date'),
|
|
)
|
|
|
|
class PriceData(Base):
|
|
__tablename__ = "price_data"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
ticker = Column(String(10), nullable=False, index=True)
|
|
date = Column(TIMESTAMP(timezone=True), nullable=False)
|
|
open = Column(Float, nullable=True)
|
|
high = Column(Float, nullable=True)
|
|
low = Column(Float, nullable=True)
|
|
close = Column(Float, nullable=False)
|
|
volume = Column(Float, nullable=True)
|
|
adjusted_close = Column(Float, nullable=True)
|
|
|
|
# Additional price metrics
|
|
market_cap = Column(Float, nullable=True)
|
|
pe_ratio = Column(Float, nullable=True)
|
|
dividend_yield = Column(Float, nullable=True)
|
|
|
|
# Metadata
|
|
data_source = Column(String(50), default='MOCK') # Will be updated when real data source is added
|
|
created_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint('ticker', 'date', name='uq_price_data'),
|
|
Index('idx_price_ticker_date', 'ticker', 'date'),
|
|
)
|
|
|
|
class DataUpdateLog(Base):
|
|
__tablename__ = "data_update_logs"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
ticker = Column(String(10), nullable=False, index=True)
|
|
update_type = Column(String(50), nullable=False) # 'financial', 'metrics', 'price'
|
|
start_date = Column(TIMESTAMP(timezone=True), nullable=True)
|
|
end_date = Column(TIMESTAMP(timezone=True), nullable=True)
|
|
status = Column(String(20), nullable=False) # 'pending', 'processing', 'completed', 'failed'
|
|
error_message = Column(String, nullable=True)
|
|
records_processed = Column(Integer, default=0)
|
|
started_at = Column(TIMESTAMP(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
completed_at = Column(TIMESTAMP(timezone=True), nullable=True)
|
|
|
|
__table_args__ = (
|
|
Index('idx_update_log_ticker', 'ticker'),
|
|
Index('idx_update_log_status', 'status'),
|
|
) |