feat(data): 财务/日线同步增量 + 新浪「两边一致」校验兜底 + 逐只进度
- financial 默认增量:按 A 股披露节奏判断已最新并跳过;--full 强制全量重拉 - Tushare fina_indicator 增加报告期窗口与 100 条/请求自动分页(修复老报告期静默截断) - 新浪兜底收紧为校验兜底:两源重叠历史一致才导入缺失键,行标记 source=sina; 财务可比字段取 eps/销售毛利率(ROE 两端口径不同不作依据),日线只比较最近重叠交易日 - CLI 输出逐只进度与导入内容描述(来源/行数/报告期与公告区间),失败股票留待重跑 - financial_indicator 增 source 列(迁移 d3f6c9a21b04);新增一致性/分页/服务测试
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
"""financial_indicator 增加 source 来源标记
|
||||
|
||||
Revision ID: d3f6c9a21b04
|
||||
Revises: 91c4e27a03fb
|
||||
Create Date: 2026-09-08
|
||||
|
||||
新浪校验兜底导入的财务行带 source=sina(字段可能不全),与 Tushare
|
||||
首选行区分;现有行回填默认 tushare(SQLite ADD COLUMN 带常量默认值,
|
||||
不重写现有数据)。AGENT.md §7 数据来源可追溯。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "d3f6c9a21b04"
|
||||
down_revision: str | None = "91c4e27a03fb"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"financial_indicator",
|
||||
sa.Column("source", sa.String(length=16), nullable=False, server_default="tushare"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("financial_indicator", "source")
|
||||
@@ -93,6 +93,9 @@ class FinancialIndicatorModel(Base):
|
||||
symbol: Mapped[str] = mapped_column(String(SYMBOL_LEN), index=True)
|
||||
report_date: Mapped[date] = mapped_column(Date, index=True)
|
||||
announce_date: Mapped[date] = mapped_column(Date, index=True)
|
||||
source: Mapped[str] = mapped_column(
|
||||
String(16), default="tushare", server_default="tushare"
|
||||
)
|
||||
eps: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
||||
roe: Mapped[Decimal | None] = mapped_column(Numeric(10, 4), nullable=True)
|
||||
total_revenue: Mapped[Decimal | None] = mapped_column(Numeric(24, 2), nullable=True)
|
||||
|
||||
@@ -241,6 +241,25 @@ class SqlAlchemyFinancialRepository:
|
||||
def upsert_many(self, rows: Sequence[FinancialIndicator]) -> int:
|
||||
return _upsert_by_business_key(self._session, FinancialIndicator, rows)
|
||||
|
||||
def list_symbol(self, symbol: str) -> list[FinancialIndicator]:
|
||||
rows = self._session.scalars(
|
||||
select(FinancialIndicatorModel)
|
||||
.where(FinancialIndicatorModel.symbol == symbol)
|
||||
.order_by(FinancialIndicatorModel.announce_date, FinancialIndicatorModel.report_date)
|
||||
).all()
|
||||
return [FinancialIndicator.model_validate(r, from_attributes=True) for r in rows]
|
||||
|
||||
def has_report_period(self, symbol: str, report_date: date) -> bool:
|
||||
exists = self._session.scalar(
|
||||
select(FinancialIndicatorModel.id)
|
||||
.where(
|
||||
FinancialIndicatorModel.symbol == symbol,
|
||||
FinancialIndicatorModel.report_date == report_date,
|
||||
)
|
||||
.limit(1)
|
||||
)
|
||||
return exists is not None
|
||||
|
||||
def list_announced(
|
||||
self,
|
||||
symbol: str,
|
||||
|
||||
Reference in New Issue
Block a user