stock/update_financial_baostock.py

211 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
兼容Baostock格式的财务数据更新脚本
将6位股票代码转换为9位格式进行财务数据采集
"""
import sys
import os
import asyncio
import logging
from datetime import date, datetime
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.storage.database import db_manager
from src.storage.stock_repository import StockRepository
from src.data.data_manager import DataManager
from src.config.settings import Settings
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def convert_to_baostock_format(stock_code: str) -> str:
"""
将6位股票代码转换为Baostock格式9位
Args:
stock_code: 6位股票代码
Returns:
9位Baostock格式股票代码
"""
if len(stock_code) == 6:
# 判断市场类型
if stock_code.startswith(('6', '9')):
return f"sh.{stock_code}"
elif stock_code.startswith(('0', '3')):
return f"sz.{stock_code}"
else:
return stock_code
return stock_code
async def update_financial_data_baostock():
"""
使用Baostock格式更新财务数据
"""
try:
logger.info("开始使用Baostock格式更新财务数据...")
# 加载配置
settings = Settings()
logger.info("配置加载成功")
# 创建数据管理器
data_manager = DataManager()
logger.info("数据管理器创建成功")
# 创建存储库
repository = StockRepository(db_manager.get_session())
logger.info("存储库创建成功")
# 获取股票基础信息
stocks = repository.get_stock_basic_info()
logger.info(f"获取到{len(stocks)}只股票基础信息")
if not stocks:
logger.error("没有股票基础信息,无法更新财务数据")
return {"success": False, "error": "没有股票基础信息"}
# 选择前20只股票进行测试
test_stocks = stocks[:20]
test_codes = [stock.code for stock in test_stocks]
logger.info(f"测试股票代码: {test_codes}")
# 设置测试年份和季度
test_year = 2023
test_quarter = 4
total_financial_data = []
success_count = 0
error_count = 0
# 为每只测试股票获取财务数据
for stock in test_stocks:
try:
# 转换为Baostock格式
baostock_code = convert_to_baostock_format(stock.code)
logger.info(f"获取股票{stock.code}({baostock_code})的财务数据...")
# 使用数据管理器获取财务数据
financial_data = await data_manager.get_financial_report(
baostock_code, test_year, test_quarter
)
if financial_data:
# 将数据中的代码转换回6位格式
for data in financial_data:
data["code"] = stock.code # 使用原始6位代码
total_financial_data.extend(financial_data)
success_count += 1
logger.info(f"股票{stock.code}获取到{len(financial_data)}条财务数据")
else:
logger.warning(f"股票{stock.code}未获取到财务数据")
error_count += 1
# 小延迟避免请求过快
await asyncio.sleep(0.5)
except Exception as e:
logger.error(f"获取股票{stock.code}财务数据失败: {str(e)}")
error_count += 1
continue
# 保存财务数据
if total_financial_data:
try:
logger.info(f"开始保存{len(total_financial_data)}条财务数据...")
save_result = repository.save_financial_report_data(total_financial_data)
logger.info(f"财务数据保存结果: {save_result}")
except Exception as e:
logger.error(f"保存财务数据失败: {str(e)}")
error_count += len(test_stocks)
else:
logger.warning("没有获取到任何财务数据")
# 验证数据库中的财务数据
try:
financial_count = repository.session.query(repository.FinancialReport).count()
logger.info(f"财务报告表: {financial_count}条记录")
if financial_count > 0:
# 显示最新的5条财务数据
latest_financial = repository.session.query(repository.FinancialReport).order_by(
repository.FinancialReport.report_date.desc()
).limit(5).all()
logger.info("最新的5条财务数据:")
for i, financial in enumerate(latest_financial):
logger.info(f" {i+1}. {financial.stock_code} - {financial.report_date} - EPS: {financial.eps}")
except Exception as e:
logger.error(f"查询财务数据失败: {str(e)}")
# 汇总更新结果
result = {
"success": True,
"test_stocks": len(test_stocks),
"success_count": success_count,
"error_count": error_count,
"financial_data_count": len(total_financial_data),
"saved_count": save_result.get("added_count", 0) + save_result.get("updated_count", 0) if total_financial_data else 0
}
logger.info(f"财务数据更新完成: {result}")
return result
except Exception as e:
logger.error(f"财务数据更新异常: {str(e)}")
return {"success": False, "error": str(e)}
def main():
"""
主函数
"""
logger.info("开始兼容Baostock格式的财务数据更新...")
# 运行异步更新
result = asyncio.run(update_financial_data_baostock())
if result["success"]:
logger.info("财务数据更新成功!")
print(f"更新结果: {result}")
if result["financial_data_count"] > 0:
print("✓ 财务数据获取成功")
print(f"✓ 共获取{result['financial_data_count']}条财务数据")
else:
print("⚠ 未获取到财务数据")
if result["saved_count"] > 0:
print("✓ 财务数据保存成功")
print(f"✓ 共保存{result['saved_count']}条财务数据")
else:
print("⚠ 财务数据保存失败")
print(f"✓ 成功股票数: {result['success_count']}")
print(f"✓ 失败股票数: {result['error_count']}")
else:
logger.error("财务数据更新失败!")
print(f"更新失败: {result.get('error')}")
return result
if __name__ == "__main__":
# 运行更新
result = main()
# 输出最终结果
if result.get("success", False):
print("\n兼容Baostock格式的财务数据更新完成")
sys.exit(0)
else:
print("\n兼容Baostock格式的财务数据更新失败")
sys.exit(1)