大改版,默认bloomberg做数据源
This commit is contained in:
parent
3290b3bdf2
commit
11fa7093ba
2
.env
2
.env
@ -12,4 +12,4 @@ DB_HOST=192.168.3.195
|
|||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_USER=value
|
DB_USER=value
|
||||||
DB_PASSWORD=Value609!
|
DB_PASSWORD=Value609!
|
||||||
DB_NAME=FA
|
DB_NAME=fa3
|
||||||
168
QUICKSTART.md
Normal file
168
QUICKSTART.md
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
# FA3 新架构快速开始指南
|
||||||
|
|
||||||
|
## 启动应用
|
||||||
|
|
||||||
|
### 1. 启动后端
|
||||||
|
```bash
|
||||||
|
cd /Users/xucheng/git.qubit.ltd/FA3/backend
|
||||||
|
uvicorn app.main:app --reload --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 启动前端
|
||||||
|
```bash
|
||||||
|
cd /Users/xucheng/git.qubit.ltd/FA3/frontend
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 访问应用
|
||||||
|
打开浏览器访问: http://localhost:3000
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用新架构
|
||||||
|
|
||||||
|
### 完整流程示例(HK市场)
|
||||||
|
|
||||||
|
1. **搜索公司**
|
||||||
|
- 在搜索框输入 "腾讯"
|
||||||
|
- 点击搜索结果中的 "选择" 按钮
|
||||||
|
|
||||||
|
2. **选择数据源**
|
||||||
|
- 系统自动显示 HK 市场可用的数据源(iFinD)
|
||||||
|
- 确认选择或切换数据源
|
||||||
|
|
||||||
|
3. **获取数据**
|
||||||
|
- 点击 "获取数据" 按钮
|
||||||
|
- 等待数据获取完成(约30秒-2分钟)
|
||||||
|
- 系统会自动轮询状态并更新
|
||||||
|
|
||||||
|
4. **查看财务数据**
|
||||||
|
- 数据获取完成后,自动显示财务表格
|
||||||
|
- 切换 Tab 查看不同报表:
|
||||||
|
- 利润表
|
||||||
|
- 资产负债表
|
||||||
|
- 现金流量表
|
||||||
|
- 估值数据
|
||||||
|
|
||||||
|
5. **启动AI分析**
|
||||||
|
- 点击 "开始 AI 分析" 按钮
|
||||||
|
- 等待分析完成(约1-2分钟)
|
||||||
|
|
||||||
|
6. **查看分析报告**
|
||||||
|
- 分析完成后,自动显示报告
|
||||||
|
- 切换 Tab 查看不同部分:
|
||||||
|
- 公司简介
|
||||||
|
- 基本面分析
|
||||||
|
- 内部人士分析
|
||||||
|
- 看涨分析
|
||||||
|
- 看跌分析
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 测试
|
||||||
|
|
||||||
|
### 使用 curl 测试新API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 检查数据状态
|
||||||
|
curl "http://localhost:8000/api/data/check?market=HK&symbol=00700&data_source=iFinD"
|
||||||
|
|
||||||
|
# 2. 获取可用数据源
|
||||||
|
curl "http://localhost:8000/api/data/sources?market=HK"
|
||||||
|
|
||||||
|
# 3. 触发数据获取
|
||||||
|
curl -X POST "http://localhost:8000/api/data/fetch" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"market": "HK",
|
||||||
|
"symbol": "00700",
|
||||||
|
"company_name": "腾讯控股",
|
||||||
|
"data_source": "iFinD"
|
||||||
|
}'
|
||||||
|
|
||||||
|
# 4. 查询获取状态(替换 {update_id})
|
||||||
|
curl "http://localhost:8000/api/data/status/1"
|
||||||
|
|
||||||
|
# 5. 读取财务数据(替换 {company_id})
|
||||||
|
curl "http://localhost:8000/api/data/financial?company_id=1&data_source=iFinD"
|
||||||
|
|
||||||
|
# 6. 启动AI分析
|
||||||
|
curl -X POST "http://localhost:8000/api/analysis/start" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"company_id": 1,
|
||||||
|
"data_source": "iFinD",
|
||||||
|
"model": "gemini-2.0-flash"
|
||||||
|
}'
|
||||||
|
|
||||||
|
# 7. 查询分析状态(替换 {analysis_id})
|
||||||
|
curl "http://localhost:8000/api/analysis/status/1"
|
||||||
|
|
||||||
|
# 8. 获取分析结果
|
||||||
|
curl "http://localhost:8000/api/analysis/result/1"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q: 数据获取失败怎么办?
|
||||||
|
A: 检查以下几点:
|
||||||
|
1. 确认 API Token 配置正确(.env 文件)
|
||||||
|
2. 检查数据库连接是否正常
|
||||||
|
3. 查看后端日志中的错误信息
|
||||||
|
|
||||||
|
### Q: 前端显示类型错误?
|
||||||
|
A: 运行以下命令重新编译:
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Q: Bloomberg 数据源不可用?
|
||||||
|
A: Bloomberg Fetcher 需要 Bloomberg API License,目前为存根实现。
|
||||||
|
|
||||||
|
### Q: 如何查看数据库中的数据?
|
||||||
|
A: 使用 psql 或 pgAdmin:
|
||||||
|
```bash
|
||||||
|
psql -h 192.168.3.195 -U value -d fa3
|
||||||
|
SELECT * FROM companies;
|
||||||
|
SELECT * FROM data_updates;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据库表结构
|
||||||
|
|
||||||
|
### 核心表
|
||||||
|
- `companies` - 公司信息
|
||||||
|
- `data_updates` - 数据更新记录
|
||||||
|
- `ai_analyses` - AI分析报告
|
||||||
|
- `data_source_availability` - 数据源可用性
|
||||||
|
- `settings` - 系统配置
|
||||||
|
|
||||||
|
### 数据源表
|
||||||
|
- `ifind_hk_*` - iFinD 香港数据
|
||||||
|
- `ifind_int_*` - iFinD 国际数据(JP, US, VN)
|
||||||
|
- `bloomberg_*` - Bloomberg 数据
|
||||||
|
- `tushare_cn_*` - Tushare 中国数据
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 下一步优化
|
||||||
|
|
||||||
|
### 待实现功能
|
||||||
|
1. `get_financial_data_from_db()` - 从数据库读取财务数据
|
||||||
|
2. Bloomberg Fetcher 完整实现
|
||||||
|
3. WebSocket 实时更新(替代轮询)
|
||||||
|
4. 图表可视化
|
||||||
|
5. 数据导出功能
|
||||||
|
|
||||||
|
### 已知问题
|
||||||
|
- 部分财务指标的中文名称映射需要完善
|
||||||
|
- 大数据量表格可能需要虚拟滚动优化
|
||||||
|
- 错误提示可以更详细
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**快速开始完成!** 祝使用愉快 🎉
|
||||||
182
backend/app/api/analysis_routes.py
Normal file
182
backend/app/api/analysis_routes.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
"""
|
||||||
|
AI 分析 API 路由
|
||||||
|
处理 LLM 分析的启动、状态查询和结果获取
|
||||||
|
"""
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy import select, and_
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from app.database import get_db
|
||||||
|
from app.schemas import (
|
||||||
|
AnalysisStartRequest,
|
||||||
|
AnalysisStartResponse,
|
||||||
|
AnalysisStatusResponse,
|
||||||
|
AnalysisResultResponse
|
||||||
|
)
|
||||||
|
from app.models import AIAnalysis, Company
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/analysis", tags=["analysis"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/start", response_model=AnalysisStartResponse)
|
||||||
|
async def start_analysis(
|
||||||
|
request: AnalysisStartRequest,
|
||||||
|
background_tasks: BackgroundTasks,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
启动 AI 分析
|
||||||
|
|
||||||
|
基于指定公司和数据源的财务数据启动 LLM 分析
|
||||||
|
"""
|
||||||
|
# 1. 创建分析记录
|
||||||
|
analysis = AIAnalysis(
|
||||||
|
company_id=request.company_id,
|
||||||
|
data_source=request.data_source,
|
||||||
|
ai_model=request.model,
|
||||||
|
status='pending'
|
||||||
|
)
|
||||||
|
db.add(analysis)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(analysis)
|
||||||
|
|
||||||
|
# 2. 启动后台分析任务
|
||||||
|
background_tasks.add_task(
|
||||||
|
run_analysis_background,
|
||||||
|
analysis_id=analysis.id,
|
||||||
|
company_id=request.company_id,
|
||||||
|
data_source=request.data_source,
|
||||||
|
model=request.model
|
||||||
|
)
|
||||||
|
|
||||||
|
return AnalysisStartResponse(
|
||||||
|
analysis_id=analysis.id,
|
||||||
|
company_id=request.company_id,
|
||||||
|
data_source=request.data_source,
|
||||||
|
status='pending',
|
||||||
|
message='AI 分析已加入队列'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def run_analysis_background(
|
||||||
|
analysis_id: int,
|
||||||
|
company_id: int,
|
||||||
|
data_source: str,
|
||||||
|
model: str
|
||||||
|
):
|
||||||
|
"""后台 AI 分析任务"""
|
||||||
|
from app.database import SessionLocal
|
||||||
|
from app.services.analysis_service import run_llm_analysis
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
async with SessionLocal() as db:
|
||||||
|
try:
|
||||||
|
# 更新状态为进行中
|
||||||
|
result = await db.execute(
|
||||||
|
select(AIAnalysis).where(AIAnalysis.id == analysis_id)
|
||||||
|
)
|
||||||
|
analysis = result.scalar_one()
|
||||||
|
analysis.status = 'in_progress'
|
||||||
|
await db.commit()
|
||||||
|
|
||||||
|
# 执行 LLM 分析
|
||||||
|
analysis_result = await run_llm_analysis(
|
||||||
|
company_id=company_id,
|
||||||
|
data_source=data_source,
|
||||||
|
model=model,
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
# 更新分析结果
|
||||||
|
analysis.status = 'completed'
|
||||||
|
analysis.company_profile = analysis_result.get('company_profile')
|
||||||
|
analysis.fundamental_analysis = analysis_result.get('fundamental_analysis')
|
||||||
|
analysis.insider_analysis = analysis_result.get('insider_analysis')
|
||||||
|
analysis.bullish_analysis = analysis_result.get('bullish_analysis')
|
||||||
|
analysis.bearish_analysis = analysis_result.get('bearish_analysis')
|
||||||
|
analysis.total_tokens = analysis_result.get('total_tokens', 0)
|
||||||
|
analysis.tokens_by_section = analysis_result.get('tokens_by_section')
|
||||||
|
analysis.completed_at = datetime.now()
|
||||||
|
|
||||||
|
await db.commit()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 更新为失败状态
|
||||||
|
result = await db.execute(
|
||||||
|
select(AIAnalysis).where(AIAnalysis.id == analysis_id)
|
||||||
|
)
|
||||||
|
analysis = result.scalar_one()
|
||||||
|
analysis.status = 'failed'
|
||||||
|
analysis.error_message = str(e)
|
||||||
|
await db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/status/{analysis_id}", response_model=AnalysisStatusResponse)
|
||||||
|
async def get_analysis_status(
|
||||||
|
analysis_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
查询分析状态
|
||||||
|
|
||||||
|
通过 analysis_id 查询 AI 分析任务的当前状态
|
||||||
|
"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(AIAnalysis).where(AIAnalysis.id == analysis_id)
|
||||||
|
)
|
||||||
|
analysis = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not analysis:
|
||||||
|
raise HTTPException(status_code=404, detail="分析记录不存在")
|
||||||
|
|
||||||
|
return analysis
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/result/{analysis_id}", response_model=AnalysisResultResponse)
|
||||||
|
async def get_analysis_result(
|
||||||
|
analysis_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
获取分析结果
|
||||||
|
|
||||||
|
获取已完成的 AI 分析的完整报告内容
|
||||||
|
"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(AIAnalysis).where(AIAnalysis.id == analysis_id)
|
||||||
|
)
|
||||||
|
analysis = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not analysis:
|
||||||
|
raise HTTPException(status_code=404, detail="分析记录不存在")
|
||||||
|
|
||||||
|
if analysis.status != 'completed':
|
||||||
|
raise HTTPException(status_code=400, detail="分析尚未完成")
|
||||||
|
|
||||||
|
return analysis
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/history", response_model=List[AnalysisStatusResponse])
|
||||||
|
async def get_analysis_history(
|
||||||
|
company_id: int,
|
||||||
|
data_source: str = None,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
历史分析列表
|
||||||
|
|
||||||
|
获取指定公司的所有历史分析记录
|
||||||
|
可选择按数据源筛选
|
||||||
|
"""
|
||||||
|
query = select(AIAnalysis).where(AIAnalysis.company_id == company_id)
|
||||||
|
|
||||||
|
if data_source:
|
||||||
|
query = query.where(AIAnalysis.data_source == data_source)
|
||||||
|
|
||||||
|
query = query.order_by(AIAnalysis.created_at.desc())
|
||||||
|
|
||||||
|
result = await db.execute(query)
|
||||||
|
analyses = result.scalars().all()
|
||||||
|
|
||||||
|
return analyses
|
||||||
317
backend/app/api/data_routes.py
Normal file
317
backend/app/api/data_routes.py
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
"""
|
||||||
|
数据管理 API 路由
|
||||||
|
处理财务数据的检查、获取和读取
|
||||||
|
"""
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from app.database import get_db
|
||||||
|
from app.schemas import (
|
||||||
|
DataCheckRequest,
|
||||||
|
DataCheckResponse,
|
||||||
|
FetchDataRequest,
|
||||||
|
FetchDataResponse,
|
||||||
|
DataUpdateResponse,
|
||||||
|
FinancialDataResponse,
|
||||||
|
DataSourceListResponse,
|
||||||
|
DataSourceInfo
|
||||||
|
)
|
||||||
|
from app.services import data_fetcher_service
|
||||||
|
from app.models import DataUpdate
|
||||||
|
from sqlalchemy import select
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/data", tags=["data"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/check", response_model=DataCheckResponse)
|
||||||
|
async def check_data_status(
|
||||||
|
market: str,
|
||||||
|
symbol: str,
|
||||||
|
data_source: str,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
检查公司数据状态
|
||||||
|
|
||||||
|
查询数据库中是否存在指定公司和数据源的数据,
|
||||||
|
如果存在则返回最近一次更新的时间和数据范围
|
||||||
|
"""
|
||||||
|
return await data_fetcher_service.check_data_status(
|
||||||
|
market=market,
|
||||||
|
symbol=symbol,
|
||||||
|
data_source=data_source,
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/fetch", response_model=FetchDataResponse)
|
||||||
|
async def fetch_data(
|
||||||
|
request: FetchDataRequest,
|
||||||
|
background_tasks: BackgroundTasks,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
获取/更新财务数据
|
||||||
|
|
||||||
|
从指定数据源获取公司的财务数据并存储到数据库
|
||||||
|
此操作在后台异步执行
|
||||||
|
"""
|
||||||
|
# 1. 创建或获取公司记录
|
||||||
|
company = await data_fetcher_service.create_or_get_company(
|
||||||
|
market=request.market,
|
||||||
|
symbol=request.symbol,
|
||||||
|
company_name=request.company_name,
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. 创建数据更新记录
|
||||||
|
data_update = await data_fetcher_service.create_data_update_record(
|
||||||
|
company_id=company.id,
|
||||||
|
data_source=request.data_source,
|
||||||
|
update_type='full',
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 启动后台任务
|
||||||
|
background_tasks.add_task(
|
||||||
|
fetch_data_background,
|
||||||
|
company_id=company.id,
|
||||||
|
market=request.market,
|
||||||
|
symbol=request.symbol,
|
||||||
|
data_source=request.data_source,
|
||||||
|
update_id=data_update.id
|
||||||
|
)
|
||||||
|
|
||||||
|
return FetchDataResponse(
|
||||||
|
update_id=data_update.id,
|
||||||
|
data_source=request.data_source,
|
||||||
|
status='in_progress',
|
||||||
|
message=f'正在从 {request.data_source} 获取数据,请稍候...'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_data_background(
|
||||||
|
company_id: int,
|
||||||
|
market: str,
|
||||||
|
symbol: str,
|
||||||
|
data_source: str,
|
||||||
|
update_id: int
|
||||||
|
):
|
||||||
|
"""后台数据获取任务 - 完全同步执行,避免event loop冲突"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import psycopg2
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 确保项目根目录在 Python 路径中
|
||||||
|
project_root = Path(__file__).parent.parent.parent.parent
|
||||||
|
if str(project_root) not in sys.path:
|
||||||
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 执行数据获取(同步)
|
||||||
|
result = data_fetcher_service.fetch_financial_data_sync(
|
||||||
|
company_id=company_id,
|
||||||
|
market=market,
|
||||||
|
symbol=symbol,
|
||||||
|
data_source=data_source,
|
||||||
|
update_id=update_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# 更新数据更新记录 - 使用psycopg2同步连接
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=os.getenv('DB_HOST', '192.168.3.195'),
|
||||||
|
user=os.getenv('DB_USER', 'value'),
|
||||||
|
password=os.getenv('DB_PASSWORD', 'Value609!'),
|
||||||
|
dbname=os.getenv('DB_NAME', 'fa3'),
|
||||||
|
port=os.getenv('DB_PORT', '5432')
|
||||||
|
)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# 更新记录
|
||||||
|
update_sql = """
|
||||||
|
UPDATE data_updates
|
||||||
|
SET status = %s,
|
||||||
|
completed_at = %s,
|
||||||
|
error_message = %s,
|
||||||
|
data_start_date = %s,
|
||||||
|
data_end_date = %s,
|
||||||
|
fetched_tables = %s,
|
||||||
|
row_counts = %s
|
||||||
|
WHERE id = %s
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
cur.execute(
|
||||||
|
update_sql,
|
||||||
|
(
|
||||||
|
result['status'],
|
||||||
|
datetime.now() if result['status'] == 'completed' else None,
|
||||||
|
result.get('error_message'),
|
||||||
|
result.get('data_start_date'),
|
||||||
|
result.get('data_end_date'),
|
||||||
|
json.dumps(result.get('fetched_tables')),
|
||||||
|
json.dumps(result.get('row_counts')),
|
||||||
|
update_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 后台任务执行错误: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# 尝试更新错误状态
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=os.getenv('DB_HOST', '192.168.3.195'),
|
||||||
|
user=os.getenv('DB_USER', 'value'),
|
||||||
|
password=os.getenv('DB_PASSWORD', 'Value609!'),
|
||||||
|
dbname=os.getenv('DB_NAME', 'fa3'),
|
||||||
|
port=os.getenv('DB_PORT', '5432')
|
||||||
|
)
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"UPDATE data_updates SET status = %s, error_message = %s, completed_at = %s WHERE id = %s",
|
||||||
|
('failed', str(e), datetime.now(), update_id)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/status/{update_id}", response_model=DataUpdateResponse)
|
||||||
|
async def get_fetch_status(
|
||||||
|
update_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
查询数据获取状态
|
||||||
|
|
||||||
|
通过 update_id 查询数据获取任务的当前状态
|
||||||
|
"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(DataUpdate).where(DataUpdate.id == update_id)
|
||||||
|
)
|
||||||
|
data_update = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not data_update:
|
||||||
|
raise HTTPException(status_code=404, detail="数据更新记录不存在")
|
||||||
|
|
||||||
|
# ⚠️ 特殊处理:由于 fetched_tables 和 row_counts 现在是 TEXT 类型存储 JSON 字符串
|
||||||
|
# 我们需要手动解析它们,否则 Pydantic 会校验失败
|
||||||
|
import json
|
||||||
|
|
||||||
|
fetched_tables = []
|
||||||
|
if data_update.fetched_tables:
|
||||||
|
if isinstance(data_update.fetched_tables, str):
|
||||||
|
try:
|
||||||
|
fetched_tables = json.loads(data_update.fetched_tables)
|
||||||
|
except:
|
||||||
|
fetched_tables = []
|
||||||
|
else:
|
||||||
|
fetched_tables = data_update.fetched_tables
|
||||||
|
|
||||||
|
row_counts = {}
|
||||||
|
if data_update.row_counts:
|
||||||
|
if isinstance(data_update.row_counts, str):
|
||||||
|
try:
|
||||||
|
row_counts = json.loads(data_update.row_counts)
|
||||||
|
except:
|
||||||
|
row_counts = {}
|
||||||
|
else:
|
||||||
|
row_counts = data_update.row_counts
|
||||||
|
|
||||||
|
# 手动构建响应对象
|
||||||
|
return DataUpdateResponse(
|
||||||
|
id=data_update.id,
|
||||||
|
company_id=data_update.company_id,
|
||||||
|
data_source=data_update.data_source,
|
||||||
|
update_type=data_update.update_type,
|
||||||
|
status=data_update.status,
|
||||||
|
progress_message=data_update.progress_message,
|
||||||
|
progress_percentage=data_update.progress_percentage,
|
||||||
|
started_at=data_update.started_at,
|
||||||
|
completed_at=data_update.completed_at,
|
||||||
|
error_message=data_update.error_message,
|
||||||
|
data_start_date=data_update.data_start_date,
|
||||||
|
data_end_date=data_update.data_end_date,
|
||||||
|
fetched_tables=fetched_tables, # 传入解析后的 List
|
||||||
|
row_counts=row_counts # 传入解析后的 Dict
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/financial", response_model=FinancialDataResponse)
|
||||||
|
async def get_financial_data(
|
||||||
|
company_id: int,
|
||||||
|
data_source: str,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
读取财务数据
|
||||||
|
|
||||||
|
从数据库中读取指定公司和数据源的所有财务数据
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = await data_fetcher_service.get_financial_data_from_db(
|
||||||
|
company_id=company_id,
|
||||||
|
data_source=data_source,
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
# 递归清理 NaN/Infinity 值,这会导致 JSON 序列化失败
|
||||||
|
import math
|
||||||
|
def clean_nan(obj):
|
||||||
|
if isinstance(obj, float):
|
||||||
|
if math.isnan(obj) or math.isinf(obj):
|
||||||
|
return None
|
||||||
|
return obj
|
||||||
|
elif isinstance(obj, dict):
|
||||||
|
return {k: clean_nan(v) for k, v in obj.items()}
|
||||||
|
elif isinstance(obj, list):
|
||||||
|
return [clean_nan(v) for v in obj]
|
||||||
|
return obj
|
||||||
|
|
||||||
|
return clean_nan(data)
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/sources", response_model=DataSourceListResponse)
|
||||||
|
async def get_available_sources(market: str):
|
||||||
|
"""
|
||||||
|
获取可用数据源列表
|
||||||
|
|
||||||
|
返回指定市场支持的所有数据源
|
||||||
|
"""
|
||||||
|
sources = data_fetcher_service.get_available_data_sources(market)
|
||||||
|
|
||||||
|
return DataSourceListResponse(
|
||||||
|
market=market,
|
||||||
|
sources=[DataSourceInfo(**s) for s in sources]
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/recent", response_model=List[dict])
|
||||||
|
async def get_recent_companies(
|
||||||
|
data_source: str = "Bloomberg",
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取最近更新的公司列表"""
|
||||||
|
return await data_fetcher_service.get_recent_companies(
|
||||||
|
data_source=data_source,
|
||||||
|
db=db,
|
||||||
|
limit=20
|
||||||
|
)
|
||||||
@ -3,9 +3,9 @@ from fastapi.responses import HTMLResponse, FileResponse
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
from app.database import get_db
|
from app.legacy.database_old import get_db
|
||||||
from app.schemas import StockSearchRequest, StockSearchResponse, AnalysisRequest, ReportResponse, AnalysisStatus, ConfigUpdateRequest
|
from app.legacy.schemas import StockSearchRequest, StockSearchResponse, AnalysisRequest, ReportResponse, AnalysisStatus, ConfigUpdateRequest
|
||||||
from app.models import Report, Setting
|
from app.legacy.models_old import Report, Setting
|
||||||
from app.services import analysis_service
|
from app.services import analysis_service
|
||||||
import os
|
import os
|
||||||
import markdown
|
import markdown
|
||||||
@ -89,6 +89,23 @@ async def get_reports(db: AsyncSession = Depends(get_db)):
|
|||||||
result = await db.execute(select(Report).options(selectinload(Report.sections)).order_by(Report.created_at.desc()))
|
result = await db.execute(select(Report).options(selectinload(Report.sections)).order_by(Report.created_at.desc()))
|
||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
|
@router.get("/reports")
|
||||||
|
async def get_all_reports(db: AsyncSession = Depends(get_db)):
|
||||||
|
"""获取所有报告列表"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(Report).order_by(Report.created_at.desc()).limit(100)
|
||||||
|
)
|
||||||
|
reports = result.scalars().all()
|
||||||
|
return [{
|
||||||
|
"id": r.id,
|
||||||
|
"market": r.market,
|
||||||
|
"symbol": r.symbol,
|
||||||
|
"company_name": r.company_name,
|
||||||
|
"status": r.status,
|
||||||
|
"ai_model": r.ai_model,
|
||||||
|
"created_at": r.created_at.isoformat() if r.created_at else None
|
||||||
|
} for r in reports]
|
||||||
|
|
||||||
@router.get("/reports/{report_id}", response_model=ReportResponse)
|
@router.get("/reports/{report_id}", response_model=ReportResponse)
|
||||||
async def get_report(report_id: int, db: AsyncSession = Depends(get_db)):
|
async def get_report(report_id: int, db: AsyncSession = Depends(get_db)):
|
||||||
result = await db.execute(select(Report).options(selectinload(Report.sections)).where(Report.id == report_id))
|
result = await db.execute(select(Report).options(selectinload(Report.sections)).where(Report.id == report_id))
|
||||||
|
|||||||
3
backend/app/clients/__init__.py
Normal file
3
backend/app/clients/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Client package initialization
|
||||||
|
"""
|
||||||
775
backend/app/clients/bloomberg_client.py
Normal file
775
backend/app/clients/bloomberg_client.py
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
import websocket
|
||||||
|
import psycopg2
|
||||||
|
import pandas as pd
|
||||||
|
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
from datetime import datetime
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Configure logger
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Explicitly load .env
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
# --- Configurations ---
|
||||||
|
|
||||||
|
CURRENCY_CONFIG = {
|
||||||
|
"Revenue": "SALES_REV_TURN",
|
||||||
|
"Net_Income": "EARN_FOR_COMMON",
|
||||||
|
"Cash_From_Operating": "CF_CASH_FROM_OPER",
|
||||||
|
"Capital_Expenditure": "CAPITAL_EXPEND",
|
||||||
|
"Free_Cash_Flow": "CF_FREE_CASH_FLOW",
|
||||||
|
"Dividends_Paid": "CF_DVD_PAID",
|
||||||
|
"Total_Assets": "BS_TOT_ASSET",
|
||||||
|
"Equity": "BS_TOT_EQY",
|
||||||
|
"Goodwill": "BS_GOODWILL",
|
||||||
|
"SG&A": "IS_SG_AND_A_EXPENSE",
|
||||||
|
"Selling&Marketing": "IS_SELLING_EXPENSES",
|
||||||
|
"General&Admin": "IS_GENERAL_AND_ADMIN_GAAP",
|
||||||
|
"R&D": "IS_RD_EXPEND",
|
||||||
|
"Depreciation": "IS_DEPR_EXP",
|
||||||
|
"Cash": "BS_CASH_NEAR_CASH_ITEM",
|
||||||
|
"Inventory": "BS_INVENTORIES",
|
||||||
|
"Accounts&Notes_Receivable": "BS_ACCT_NOTE_RCV",
|
||||||
|
"Prepaid": "BS_PREPAY",
|
||||||
|
"Property_Plant&Equipment": "BS_NET_FIX_ASSET",
|
||||||
|
"LT_Investment": "BS_LT_INVEST",
|
||||||
|
"Accounts_Payable": "BS_ACCT_PAYABLE",
|
||||||
|
"ST_Debt": "BS_ST_BORROW",
|
||||||
|
"LT_Debt": "BS_LT_BORROW",
|
||||||
|
"ST_Defer_Rev":"ST_DEFERRED_REVENUE",
|
||||||
|
"repurchase":"cf_proceeds_repurchase_equity"
|
||||||
|
}
|
||||||
|
|
||||||
|
NON_CURRENCY_CONFIG = {
|
||||||
|
"ROE": "RETURN_COM_EQY",
|
||||||
|
"ROA": "RETURN_ON_ASSET",
|
||||||
|
"ROCE": "RETURN_ON_CAPITAL_EMPLOYED",
|
||||||
|
"Gross_Margin": "GROSS_MARGIN",
|
||||||
|
"EBITDA_margin": "EBITDA_TO_REVENUE",
|
||||||
|
"Net_Profit_Margin": "PROF_MARGIN",
|
||||||
|
"Tax_Rate": "IS_STATUTORY_TAX_RATE",
|
||||||
|
"Inventory_Days": "INVENT_DAYS",
|
||||||
|
"Days_Sales_Outstanding": "ANNUALIZED_DAYS_SALES_OUTSTDG",
|
||||||
|
"Payables_Days": "ACCOUNTS_PAYABLE_TURNOVER_DAYS",
|
||||||
|
"Employee": "NUM_OF_EMPLOYEES",
|
||||||
|
"PE": "PE_RATIO",
|
||||||
|
"PB": "PX_TO_BOOK_RATIO",
|
||||||
|
"Shareholders": "BS_NUM_OF_SHAREHOLDERS",
|
||||||
|
"Dividend_Payout_Ratio":"DVD_PAYOUT_RATIO",
|
||||||
|
"Total_Debt_Ratio":"TOT_DEBT_TO_TOT_ASSET",
|
||||||
|
"Net_Fixed_Asset_Turnover":"NET_FIX_ASSET_TURN",
|
||||||
|
"Asset_Turnover":"ASSET_TURNOVER",
|
||||||
|
"NetIncome_Growth":"earn_for_com_growth",
|
||||||
|
"Revenue_Growth":"sales_growth",
|
||||||
|
}
|
||||||
|
|
||||||
|
PRICE_CONFIG = {
|
||||||
|
"Last_Price": "PX_LAST",
|
||||||
|
"Market_Cap":"cur_mkt_cap",
|
||||||
|
"Dividend_Yield": "DIVIDEND_12_MONTH_YIELD"
|
||||||
|
}
|
||||||
|
|
||||||
|
STOCKCARD_CONFIG = {
|
||||||
|
"period": 15,
|
||||||
|
"unit": 100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BloombergClient:
|
||||||
|
"""
|
||||||
|
Backend Bloomberg Client.
|
||||||
|
Connects to remote Jupyter Kernel via WebSocket to execute 'blp' code.
|
||||||
|
Persists data to 'stockcard' table (EAV pattern) using direct DB connection.
|
||||||
|
"""
|
||||||
|
def __init__(self, jupyter_url=None, password=None):
|
||||||
|
self.jupyter_url = jupyter_url or os.getenv("JUPYTER_URL", "http://192.168.3.161:8888")
|
||||||
|
self.jupyter_url = self.jupyter_url.rstrip("/")
|
||||||
|
self.password = password or os.getenv("JUPYTER_PASSWORD", "Value609!")
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.kernel_id = None
|
||||||
|
self.ws = None
|
||||||
|
|
||||||
|
# Authenticate and setup connection
|
||||||
|
try:
|
||||||
|
self._authenticate()
|
||||||
|
self._setup_kernel()
|
||||||
|
self._connect_websocket()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to initialize Bloomberg Client connection: {e}")
|
||||||
|
# Don't raise here, allow instantiation but methods might fail
|
||||||
|
# or caller handles initialization failure
|
||||||
|
|
||||||
|
def _authenticate(self):
|
||||||
|
"""Authenticate with JupyterHub/Lab using password to get session cookies."""
|
||||||
|
logger.info(f"Connecting to Jupyter at {self.jupyter_url}...")
|
||||||
|
try:
|
||||||
|
# 1. Get Login Page to fetch _xsrf (if needed)
|
||||||
|
r = self.session.get(f"{self.jupyter_url}/login")
|
||||||
|
if r.status_code != 200:
|
||||||
|
logger.warning(f"Failed to access login page: {r.status_code}")
|
||||||
|
|
||||||
|
xsrf = self.session.cookies.get("_xsrf", "")
|
||||||
|
|
||||||
|
# 2. Post Password
|
||||||
|
data = {"password": self.password}
|
||||||
|
if xsrf:
|
||||||
|
data["_xsrf"] = xsrf
|
||||||
|
|
||||||
|
login_resp = self.session.post(f"{self.jupyter_url}/login", data=data)
|
||||||
|
|
||||||
|
# 3. Verify Auth
|
||||||
|
api_resp = self.session.get(f"{self.jupyter_url}/api/status")
|
||||||
|
if api_resp.status_code == 200:
|
||||||
|
logger.info("✅ Authentication successful.")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Authentication failed. Status: {api_resp.status_code}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error during authentication: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _setup_kernel(self):
|
||||||
|
"""Find an existing kernel or create a new one."""
|
||||||
|
try:
|
||||||
|
# List kernels
|
||||||
|
resp = self.session.get(f"{self.jupyter_url}/api/kernels")
|
||||||
|
kernels = resp.json()
|
||||||
|
|
||||||
|
# Try to find 'remote_env' or just pick the first available
|
||||||
|
target_kernel = None
|
||||||
|
for k in kernels:
|
||||||
|
if k.get('name') == 'remote_env': # Ideal match
|
||||||
|
target_kernel = k
|
||||||
|
break
|
||||||
|
|
||||||
|
if not target_kernel and kernels:
|
||||||
|
target_kernel = kernels[0] # Fallback
|
||||||
|
|
||||||
|
if target_kernel:
|
||||||
|
self.kernel_id = target_kernel['id']
|
||||||
|
logger.info(f"✅ Found existing kernel: {self.kernel_id} ({target_kernel.get('name')})")
|
||||||
|
else:
|
||||||
|
logger.info("No active kernels found. Starting a new one...")
|
||||||
|
# Start new kernel (assuming python3)
|
||||||
|
start_resp = self.session.post(f"{self.jupyter_url}/api/kernels", json={"name": "python3"})
|
||||||
|
if start_resp.status_code == 201:
|
||||||
|
self.kernel_id = start_resp.json()['id']
|
||||||
|
logger.info(f"✅ Started new kernel: {self.kernel_id}")
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to start kernel: {start_resp.text}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error setting up kernel: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _connect_websocket(self):
|
||||||
|
"""Connect to the Kernel's WebSocket channel."""
|
||||||
|
base_ws_url = self.jupyter_url.replace("http", "ws")
|
||||||
|
ws_url = f"{base_ws_url}/api/kernels/{self.kernel_id}/channels"
|
||||||
|
|
||||||
|
# Extract cookies for WS connection
|
||||||
|
cookies = self.session.cookies.get_dict()
|
||||||
|
cookie_str = "; ".join([f"{k}={v}" for k, v in cookies.items()])
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.ws = websocket.create_connection(
|
||||||
|
ws_url,
|
||||||
|
header={"Cookie": cookie_str},
|
||||||
|
timeout=60 # Connection timeout
|
||||||
|
)
|
||||||
|
logger.info("✅ WebSocket connected.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ WebSocket connection failed: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def execute_remote_code(self, code_str):
|
||||||
|
"""
|
||||||
|
Send code to remote kernel via WebSocket and wait for result.
|
||||||
|
Returns list of output strings (stdout).
|
||||||
|
"""
|
||||||
|
if not self.ws:
|
||||||
|
raise Exception("WebSocket not connected")
|
||||||
|
|
||||||
|
msg_id = str(uuid.uuid4())
|
||||||
|
msg = {
|
||||||
|
"header": {
|
||||||
|
"msg_id": msg_id,
|
||||||
|
"username": "client",
|
||||||
|
"session": str(uuid.uuid4()),
|
||||||
|
"msg_type": "execute_request",
|
||||||
|
"version": "5.3"
|
||||||
|
},
|
||||||
|
"parent_header": {},
|
||||||
|
"metadata": {},
|
||||||
|
"content": {
|
||||||
|
"code": code_str,
|
||||||
|
"silent": False,
|
||||||
|
"store_history": True,
|
||||||
|
"user_expressions": {},
|
||||||
|
"allow_stdin": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ws.send(json.dumps(msg))
|
||||||
|
|
||||||
|
outputs = []
|
||||||
|
error = None
|
||||||
|
|
||||||
|
# Loop to receive messages until 'idle'
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
resp = json.loads(self.ws.recv())
|
||||||
|
msg_type = resp['msg_type']
|
||||||
|
|
||||||
|
# Check for idle status (command finished)
|
||||||
|
if msg_type == 'status':
|
||||||
|
if resp['content']['execution_state'] == 'idle':
|
||||||
|
# Make sure it's the response to OUR request (simple check)
|
||||||
|
if resp['parent_header'].get('msg_id') == msg_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
elif msg_type == 'stream':
|
||||||
|
# Stdout/Stderr
|
||||||
|
outputs.append(resp['content']['text'])
|
||||||
|
|
||||||
|
elif msg_type == 'error':
|
||||||
|
error = resp['content']['evalue']
|
||||||
|
logger.error(f"❌ Remote Execution Error: {error}")
|
||||||
|
for line in resp['content']['traceback']:
|
||||||
|
logger.error(line)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error receiving WS message: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
if error:
|
||||||
|
raise Exception(f"Remote Code Execution Failed: {error}")
|
||||||
|
|
||||||
|
return "".join(outputs)
|
||||||
|
|
||||||
|
# --- Database Operations ---
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""Create a database connection."""
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3") # Default to fa3 now? fa legacy used 'FA'
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
return conn
|
||||||
|
except psycopg2.OperationalError as e:
|
||||||
|
logger.error(f"DB Connection Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _ensure_schema(self, conn):
|
||||||
|
"""Ensure the necessary tables exist."""
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# Create table if not exists (Inferred schema from legacy use)
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS stockcard (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
Company_code TEXT,
|
||||||
|
update_date DATE,
|
||||||
|
currency TEXT,
|
||||||
|
indicator TEXT,
|
||||||
|
value TEXT,
|
||||||
|
value_date DATE,
|
||||||
|
source TEXT
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Ensure column exists if table was already created
|
||||||
|
try:
|
||||||
|
cur.execute("ALTER TABLE stockcard ADD COLUMN IF NOT EXISTS source TEXT;")
|
||||||
|
except Exception:
|
||||||
|
conn.rollback() # Should not happen with IF NOT EXISTS but good practice
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def save_data(self, data_list):
|
||||||
|
"""Insert a list of data dictionaries into the database."""
|
||||||
|
if not data_list:
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return
|
||||||
|
|
||||||
|
self._ensure_schema(conn)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
args_list = []
|
||||||
|
for d in data_list:
|
||||||
|
# Format: (Company_code, update_date, currency, indicator, value, value_date, source)
|
||||||
|
args_list.append((
|
||||||
|
d['Company_code'],
|
||||||
|
d['update_date'],
|
||||||
|
d['currency'],
|
||||||
|
d['indicator'],
|
||||||
|
d['value'],
|
||||||
|
d['value_date'],
|
||||||
|
'bloomberg'
|
||||||
|
))
|
||||||
|
|
||||||
|
query = """
|
||||||
|
INSERT INTO stockcard (Company_code, update_date, currency, indicator, value, value_date, source)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
cur.executemany(query, args_list)
|
||||||
|
conn.commit()
|
||||||
|
logger.info(f"✅ Saved {len(data_list)} records to database.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving to stockcard: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def run_cleanup(self):
|
||||||
|
"""Run deduplication and view refresh logic."""
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# 1. Deduplication
|
||||||
|
cur.execute('''
|
||||||
|
WITH DuplicateRows AS (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
ROW_NUMBER() OVER(
|
||||||
|
PARTITION BY company_code, currency, indicator, value_date
|
||||||
|
ORDER BY update_date DESC
|
||||||
|
) as rn
|
||||||
|
FROM
|
||||||
|
stockcard
|
||||||
|
)
|
||||||
|
DELETE FROM stockcard
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT id
|
||||||
|
FROM DuplicateRows
|
||||||
|
WHERE rn > 1
|
||||||
|
);
|
||||||
|
''')
|
||||||
|
|
||||||
|
# 2. Materialized View Refresh
|
||||||
|
cur.execute('''
|
||||||
|
CREATE MATERIALIZED VIEW IF NOT EXISTS public.unique_company_codes AS
|
||||||
|
SELECT
|
||||||
|
s.Company_code,
|
||||||
|
(SELECT cn_sub.value
|
||||||
|
FROM public.stockcard AS cn_sub
|
||||||
|
WHERE cn_sub.Company_code = s.Company_code
|
||||||
|
AND cn_sub.indicator = 'company_name'
|
||||||
|
ORDER BY cn_sub.value ASC
|
||||||
|
LIMIT 1) AS company_name
|
||||||
|
FROM
|
||||||
|
(SELECT DISTINCT Company_code FROM public.stockcard WHERE Company_code IS NOT NULL) s
|
||||||
|
ORDER BY
|
||||||
|
s.Company_code;
|
||||||
|
''')
|
||||||
|
# Try refresh
|
||||||
|
try:
|
||||||
|
cur.execute("REFRESH MATERIALIZED VIEW public.unique_company_codes;")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
logger.info("✅ Cleanup and View Refresh completed.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Cleanup failed: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# --- Core Fetching Logic ---
|
||||||
|
|
||||||
|
def fetch_company(self, market, symbol, progress_callback=None):
|
||||||
|
"""
|
||||||
|
Main entry point to fetch data for a single company.
|
||||||
|
"""
|
||||||
|
# Determine Bloomberg Ticker format
|
||||||
|
# If symbol already has Equity, use it. Else append.
|
||||||
|
if "Equity" in symbol:
|
||||||
|
company_code = symbol
|
||||||
|
else:
|
||||||
|
# Special case for China market: use 'CH Equity' instead of 'CN Equity'
|
||||||
|
mapped_market = "CH" if market == "CN" else market
|
||||||
|
company_code = f"{symbol} {mapped_market} Equity"
|
||||||
|
|
||||||
|
today_str = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
logger.info(f"🚀 Starting fetch for: {company_code}")
|
||||||
|
if progress_callback: progress_callback("Starting Bloomberg session...", 0)
|
||||||
|
|
||||||
|
# 0. Prep Remote Environment
|
||||||
|
init_code = """
|
||||||
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
from datetime import datetime
|
||||||
|
try:
|
||||||
|
from blp import blp
|
||||||
|
except ImportError:
|
||||||
|
print("Error: 'blp' module not found.")
|
||||||
|
|
||||||
|
# Ensure bquery is started
|
||||||
|
if 'bquery' not in globals():
|
||||||
|
try:
|
||||||
|
bquery = blp.BlpQuery().start()
|
||||||
|
print("BlpQuery started.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error starting BlpQuery: {e}")
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.execute_remote_code(init_code)
|
||||||
|
|
||||||
|
# 1. Fetch Basic Info
|
||||||
|
logger.info("Fetching Basic Data...")
|
||||||
|
if progress_callback: progress_callback("Fetching Company Basic Info...", 10)
|
||||||
|
basic_data = self._fetch_basic_remote(company_code, "USD")
|
||||||
|
self.save_data(basic_data)
|
||||||
|
|
||||||
|
# Determine currency
|
||||||
|
currency = "USD"
|
||||||
|
if "JP" in market.upper(): currency = "JPY"
|
||||||
|
elif "VN" in market.upper(): currency = "VND"
|
||||||
|
elif "CN" in market.upper(): currency = "CNY"
|
||||||
|
elif "HK" in market.upper(): currency = "HKD"
|
||||||
|
|
||||||
|
logger.info(f"Using currency: {currency}")
|
||||||
|
|
||||||
|
# 2. Fetch Currency Data
|
||||||
|
logger.info("Fetching Currency Data...")
|
||||||
|
if progress_callback: progress_callback(f"正在获取货币指标 ({currency})...", 30)
|
||||||
|
curr_data = self._fetch_series_remote(company_code, currency, CURRENCY_CONFIG, "currency")
|
||||||
|
self.save_data(curr_data)
|
||||||
|
|
||||||
|
# 3. Fetch Non-Currency Data
|
||||||
|
logger.info("Fetching Non-Currency Data...")
|
||||||
|
if progress_callback: progress_callback("正在获取非货币指标...", 50)
|
||||||
|
non_curr_data = self._fetch_series_remote(company_code, currency, NON_CURRENCY_CONFIG, "non_currency")
|
||||||
|
self.save_data(non_curr_data)
|
||||||
|
|
||||||
|
# 4. Fetch Price Data (Aligned with Revenue Dates)
|
||||||
|
logger.info("Fetching Price Data (Aligned)...")
|
||||||
|
if progress_callback: progress_callback("正在获取价格指标...", 70)
|
||||||
|
|
||||||
|
# Extract Revenue dates
|
||||||
|
revenue_dates = []
|
||||||
|
rev_key = CURRENCY_CONFIG.get("Revenue", "SALES_REV_TURN")
|
||||||
|
# The saved data uses indicator name from config keys (e.g. "Revenue")
|
||||||
|
# So looking for "Revenue" in saved entries
|
||||||
|
|
||||||
|
for item in curr_data:
|
||||||
|
# Check for "Revenue" (case insensitive match if needed)
|
||||||
|
if item['indicator'].lower() == 'revenue':
|
||||||
|
if item['value_date']:
|
||||||
|
# Ensure YYYY-MM-DD
|
||||||
|
revenue_dates.append(item['value_date'])
|
||||||
|
|
||||||
|
# Remove specs, duplicates, sort
|
||||||
|
revenue_dates = sorted(list(set(revenue_dates)), reverse=True)
|
||||||
|
|
||||||
|
if revenue_dates:
|
||||||
|
logger.info(f"Found {len(revenue_dates)} revenue reporting dates. Fetching aligned price data...")
|
||||||
|
price_data = self._fetch_price_by_dates_remote(company_code, currency, revenue_dates)
|
||||||
|
self.save_data(price_data)
|
||||||
|
else:
|
||||||
|
logger.warning("No revenue dates found. Falling back to yearly price fetch.")
|
||||||
|
price_data = self._fetch_series_remote(company_code, currency, PRICE_CONFIG, "price")
|
||||||
|
self.save_data(price_data)
|
||||||
|
|
||||||
|
# 5. Cleanup
|
||||||
|
if progress_callback: progress_callback("Finalizing data...", 90)
|
||||||
|
self.run_cleanup()
|
||||||
|
logger.info(f"✅ Completed processing for {company_code}")
|
||||||
|
if progress_callback: progress_callback("Bloomberg data sync complete", 100)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fetch failed for {company_code}: {e}")
|
||||||
|
if progress_callback: progress_callback(f"Error: {e}", 0)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def _fetch_basic_remote(self, company_code, currency):
|
||||||
|
"""Generates code to fetch basic data"""
|
||||||
|
code = f"""
|
||||||
|
def get_basic():
|
||||||
|
company = "{company_code}"
|
||||||
|
curr = "{currency}"
|
||||||
|
res_list = []
|
||||||
|
|
||||||
|
# 1. BQL query
|
||||||
|
q = f"for(['{{company}}']) get(name,listing_date,pe_ratio,px_to_book_ratio,cur_mkt_cap(currency={{curr}}),PCT_REVENUE_FROM_FOREIGN_SOURCES)"
|
||||||
|
try:
|
||||||
|
df = bquery.bql(q)
|
||||||
|
if not df.empty:
|
||||||
|
def get_val(df, field_name):
|
||||||
|
if field_name == 'name':
|
||||||
|
rows = df[df['field'] == 'name']
|
||||||
|
elif 'cur_mkt_cap' in field_name:
|
||||||
|
rows = df[df['field'].str.contains('cur_mkt_cap')]
|
||||||
|
elif 'FOREIGN' in field_name:
|
||||||
|
rows = df[df['field'].str.contains('FOREIGN')]
|
||||||
|
else:
|
||||||
|
rows = df[df['field'] == field_name]
|
||||||
|
|
||||||
|
if not rows.empty:
|
||||||
|
val = rows['value'].iloc[0]
|
||||||
|
# Handle Timestamp object from remote pandas
|
||||||
|
if hasattr(val, 'strftime'):
|
||||||
|
return val.strftime('%Y-%m-%d')
|
||||||
|
return str(val) if val is not None else None
|
||||||
|
return None
|
||||||
|
|
||||||
|
res_list.append({{"indicator": "company_name", "value": get_val(df, 'name')}})
|
||||||
|
res_list.append({{"indicator": "pe_ratio", "value": get_val(df, 'pe_ratio')}})
|
||||||
|
res_list.append({{"indicator": "pb_ratio", "value": get_val(df, 'pb_ratio')}})
|
||||||
|
res_list.append({{"indicator": "market_cap", "value": get_val(df, 'cur_mkt_cap')}})
|
||||||
|
res_list.append({{"indicator": "Rev_Abroad", "value": get_val(df, 'FOREIGN')}})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Basic BQL Error: {{e}}")
|
||||||
|
|
||||||
|
# 2. BDP for IPO and Dividend
|
||||||
|
try:
|
||||||
|
did = bquery.bdp([company], ["DIVIDEND_12_MONTH_YIELD"])
|
||||||
|
if not did.empty and 'DIVIDEND_12_MONTH_YIELD' in did.columns:
|
||||||
|
res_list.append({{"indicator": "dividend_yield", "value": str(did['DIVIDEND_12_MONTH_YIELD'][0])}})
|
||||||
|
|
||||||
|
ipo = bquery.bdp([company], ["EQY_INIT_PO_DT"])
|
||||||
|
if not ipo.empty and 'EQY_INIT_PO_DT' in ipo.columns:
|
||||||
|
val = ipo['EQY_INIT_PO_DT'][0]
|
||||||
|
val_str = str(val)
|
||||||
|
if hasattr(val, 'strftime'):
|
||||||
|
val_str = val.strftime('%Y-%m-%d')
|
||||||
|
res_list.append({{"indicator": "IPO_date", "value": val_str}})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Basic BDP Error: {{e}}")
|
||||||
|
|
||||||
|
# Format result
|
||||||
|
final_res = []
|
||||||
|
today = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
for item in res_list:
|
||||||
|
if item['value']:
|
||||||
|
final_res.append({{
|
||||||
|
"Company_code": company,
|
||||||
|
"update_date": today,
|
||||||
|
"currency": curr,
|
||||||
|
"indicator": item['indicator'],
|
||||||
|
"value": item['value'],
|
||||||
|
"value_date": today
|
||||||
|
}})
|
||||||
|
|
||||||
|
print("JSON_START")
|
||||||
|
print(json.dumps(final_res))
|
||||||
|
print("JSON_END")
|
||||||
|
|
||||||
|
get_basic()
|
||||||
|
"""
|
||||||
|
return self._execute_and_parse(code)
|
||||||
|
|
||||||
|
def _fetch_series_remote(self, company_code, currency, config_dict, result_type):
|
||||||
|
"""Generates code to fetch series data using BDH"""
|
||||||
|
|
||||||
|
config_json = json.dumps(config_dict)
|
||||||
|
period_years = STOCKCARD_CONFIG['period']
|
||||||
|
|
||||||
|
start_year = datetime.now().year - period_years
|
||||||
|
start_date = f"{start_year}0101"
|
||||||
|
end_date = datetime.now().strftime('%Y%m%d')
|
||||||
|
|
||||||
|
bdh_options = {
|
||||||
|
'periodicitySelection': 'YEARLY',
|
||||||
|
'currency': currency,
|
||||||
|
'nonTradingDayFillOption': 'ALL_CALENDAR_DAYS',
|
||||||
|
'nonTradingDayFillMethod': 'PREVIOUS_VALUE'
|
||||||
|
}
|
||||||
|
bdh_opts_json = json.dumps(bdh_options)
|
||||||
|
|
||||||
|
code = f"""
|
||||||
|
def get_series():
|
||||||
|
company = "{company_code}"
|
||||||
|
curr = "{currency}"
|
||||||
|
config = {config_json}
|
||||||
|
|
||||||
|
mnemonic_map = {{v.upper(): k for k, v in config.items()}}
|
||||||
|
fields = list(mnemonic_map.keys())
|
||||||
|
|
||||||
|
res_list = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
df = bquery.bdh(
|
||||||
|
[company],
|
||||||
|
fields,
|
||||||
|
start_date='{start_date}',
|
||||||
|
end_date='{end_date}',
|
||||||
|
options={bdh_opts_json}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
for _, row in df.iterrows():
|
||||||
|
date_val = None
|
||||||
|
if 'date' in df.columns: date_val = row['date']
|
||||||
|
elif 'DATE' in df.columns: date_val = row['DATE']
|
||||||
|
|
||||||
|
if not date_val: continue
|
||||||
|
|
||||||
|
date_str = str(date_val)[:10]
|
||||||
|
|
||||||
|
for mnemonic, indicator_name in mnemonic_map.items():
|
||||||
|
col_name = mnemonic
|
||||||
|
# Handle multi-column result from bdh if any
|
||||||
|
# Usually bdh returns column names as requested fields
|
||||||
|
|
||||||
|
val = None
|
||||||
|
# Flexible column matching
|
||||||
|
if col_name in row:
|
||||||
|
val = row[col_name]
|
||||||
|
elif col_name in df.columns:
|
||||||
|
val = row[col_name]
|
||||||
|
else:
|
||||||
|
# Try case insensitive
|
||||||
|
for c in df.columns:
|
||||||
|
if c.upper() == col_name:
|
||||||
|
val = row[c]
|
||||||
|
break
|
||||||
|
|
||||||
|
if pd.isna(val) or val is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
val_str = str(val)
|
||||||
|
|
||||||
|
res_list.append({{
|
||||||
|
"Company_code": company,
|
||||||
|
"update_date": "{datetime.now().strftime('%Y-%m-%d')}",
|
||||||
|
"currency": curr,
|
||||||
|
"indicator": indicator_name,
|
||||||
|
"value": val_str,
|
||||||
|
"value_date": date_str
|
||||||
|
}})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"BDH Error: {{e}}")
|
||||||
|
|
||||||
|
print("JSON_START")
|
||||||
|
print(json.dumps(res_list))
|
||||||
|
print("JSON_END")
|
||||||
|
|
||||||
|
get_series()
|
||||||
|
"""
|
||||||
|
return self._execute_and_parse(code)
|
||||||
|
|
||||||
|
def _fetch_price_by_dates_remote(self, company_code, currency, dates):
|
||||||
|
"""Generates code to fetch price/mkt_cap for specific dates"""
|
||||||
|
if not dates:
|
||||||
|
return []
|
||||||
|
|
||||||
|
dates_json = json.dumps(dates)
|
||||||
|
config_json = json.dumps(PRICE_CONFIG)
|
||||||
|
|
||||||
|
bdh_options = {
|
||||||
|
'currency': currency,
|
||||||
|
'nonTradingDayFillOption': 'ALL_CALENDAR_DAYS',
|
||||||
|
'nonTradingDayFillMethod': 'PREVIOUS_VALUE'
|
||||||
|
}
|
||||||
|
bdh_opts_json = json.dumps(bdh_options)
|
||||||
|
|
||||||
|
code = f"""
|
||||||
|
def get_price_by_dates():
|
||||||
|
company = "{company_code}"
|
||||||
|
curr = "{currency}"
|
||||||
|
dates = {dates_json}
|
||||||
|
config = {config_json}
|
||||||
|
|
||||||
|
mnemonic_map = {{v.upper(): k for k, v in config.items()}}
|
||||||
|
fields = list(mnemonic_map.keys())
|
||||||
|
|
||||||
|
res_list = []
|
||||||
|
|
||||||
|
for d_str in dates:
|
||||||
|
# d_str is 'YYYY-MM-DD', bdh needs 'YYYYMMDD'
|
||||||
|
d_param = d_str.replace('-', '')
|
||||||
|
|
||||||
|
try:
|
||||||
|
df = bquery.bdh(
|
||||||
|
[company],
|
||||||
|
fields,
|
||||||
|
start_date=d_param,
|
||||||
|
end_date=d_param,
|
||||||
|
options={bdh_opts_json}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
for _, row in df.iterrows():
|
||||||
|
# value_date is d_str
|
||||||
|
|
||||||
|
for mnemonic, indicator_name in mnemonic_map.items():
|
||||||
|
col_name = mnemonic
|
||||||
|
# bdh columns might be tuple or just string depending on request
|
||||||
|
# usually 'PX_LAST'
|
||||||
|
|
||||||
|
val = None
|
||||||
|
if col_name in df.columns:
|
||||||
|
val = row[col_name]
|
||||||
|
|
||||||
|
if pd.isna(val) or val is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
val_str = str(val)
|
||||||
|
|
||||||
|
res_list.append({{
|
||||||
|
"Company_code": company,
|
||||||
|
"update_date": "{datetime.now().strftime('%Y-%m-%d')}",
|
||||||
|
"currency": curr,
|
||||||
|
"indicator": indicator_name,
|
||||||
|
"value": val_str,
|
||||||
|
"value_date": d_str
|
||||||
|
}})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching price for {{d_str}}: {{e}}")
|
||||||
|
|
||||||
|
print("JSON_START")
|
||||||
|
print(json.dumps(res_list))
|
||||||
|
print("JSON_END")
|
||||||
|
|
||||||
|
get_price_by_dates()
|
||||||
|
"""
|
||||||
|
return self._execute_and_parse(code)
|
||||||
|
|
||||||
|
def _execute_and_parse(self, code):
|
||||||
|
"""Execute code and parse [JSON_START]...[JSON_END]"""
|
||||||
|
raw_output_list = self.execute_remote_code(code)
|
||||||
|
raw_output = "".join(raw_output_list) if isinstance(raw_output_list, list) else str(raw_output_list)
|
||||||
|
# logger.debug(f"Remote execution returned {len(raw_output)} chars.") # Optional debug
|
||||||
|
|
||||||
|
# Simple parser
|
||||||
|
try:
|
||||||
|
start_idx = raw_output.find("JSON_START")
|
||||||
|
end_idx = raw_output.find("JSON_END")
|
||||||
|
|
||||||
|
if start_idx != -1 and end_idx != -1:
|
||||||
|
json_str = raw_output[start_idx + len("JSON_START"):end_idx].strip()
|
||||||
|
data = json.loads(json_str)
|
||||||
|
logger.info(f"✅ Parsed {len(data) if isinstance(data, list) else 1} items from remote.")
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
logger.warning(f"⚠️ No JSON output found in remote response.")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Error parsing JSON from remote: {e}")
|
||||||
|
return []
|
||||||
86
backend/app/clients/ifind_client.py
Normal file
86
backend/app/clients/ifind_client.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from requests.adapters import HTTPAdapter
|
||||||
|
from urllib3.util.retry import Retry
|
||||||
|
|
||||||
|
# Configure logger
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class IFindClient:
|
||||||
|
"""
|
||||||
|
iFinD HTTP API Client Base Class.
|
||||||
|
Handles authentication and token management.
|
||||||
|
"""
|
||||||
|
def __init__(self, refresh_token: str):
|
||||||
|
self.refresh_token = refresh_token
|
||||||
|
self.access_token = None
|
||||||
|
self.token_expiry = 0
|
||||||
|
self.base_url = "https://quantapi.51ifind.com/api/v1"
|
||||||
|
|
||||||
|
# Initialize Session with Retry logic
|
||||||
|
self.session = requests.Session()
|
||||||
|
retries = Retry(
|
||||||
|
total=5,
|
||||||
|
backoff_factor=1,
|
||||||
|
status_forcelist=[500, 502, 503, 504],
|
||||||
|
allowed_methods=["POST", "GET"]
|
||||||
|
)
|
||||||
|
self.session.mount('https://', HTTPAdapter(max_retries=retries))
|
||||||
|
|
||||||
|
def _get_access_token(self):
|
||||||
|
"""Get or refresh access_token"""
|
||||||
|
if self.access_token and time.time() < self.token_expiry:
|
||||||
|
return self.access_token
|
||||||
|
|
||||||
|
url = f"{self.base_url}/get_access_token"
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"refresh_token": self.refresh_token
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.session.post(url, headers=headers)
|
||||||
|
data = response.json()
|
||||||
|
if data.get("errorcode") == 0:
|
||||||
|
self.access_token = data["data"]["access_token"]
|
||||||
|
# Expires in 7 days, refresh every 6 days
|
||||||
|
self.token_expiry = time.time() + (6 * 24 * 3600)
|
||||||
|
return self.access_token
|
||||||
|
else:
|
||||||
|
error_msg = f"iFinD access token error: {data.get('errmsg')} (Code: {data.get('errorcode')})"
|
||||||
|
if data.get("errorcode") == -1301:
|
||||||
|
logger.critical(f"CRITICAL ERROR: {error_msg}")
|
||||||
|
logger.critical("Please check your IFIND_REFRESH_TOKEN in .env file.")
|
||||||
|
# In backend service, we shouldn't sys.exit() as it kills the server
|
||||||
|
# Just raise exception
|
||||||
|
raise Exception(error_msg)
|
||||||
|
raise Exception(error_msg)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error refreshing iFinD access token: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def post(self, endpoint: str, params: dict):
|
||||||
|
"""Send POST request to API endpoint"""
|
||||||
|
token = self._get_access_token()
|
||||||
|
if not token:
|
||||||
|
return None
|
||||||
|
|
||||||
|
url = f"{self.base_url}/{endpoint}"
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"access_token": token
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.session.post(url, headers=headers, json=params, timeout=30)
|
||||||
|
if response.status_code != 200:
|
||||||
|
logger.error(f"iFinD API HTTP Error: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
return response.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"iFinD API Request Error on {endpoint}: {e}")
|
||||||
|
return None
|
||||||
758
backend/app/clients/ifind_hk_client.py
Normal file
758
backend/app/clients/ifind_hk_client.py
Normal file
@ -0,0 +1,758 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
import numpy as np
|
||||||
|
from typing import List, Union
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
from .ifind_client import IFindClient
|
||||||
|
|
||||||
|
# Get logger
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Explicitly load .env from project root
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
class IFindHKClient:
|
||||||
|
"""
|
||||||
|
iFinD Client specifically for Hong Kong Market (Backend Version).
|
||||||
|
Uses 'THS' indicators and Chinese accounting standard mappings.
|
||||||
|
Implements direct Postgres persistence (Side-Channel) for background task compatibility.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
self.cli = IFindClient(refresh_token=api_key)
|
||||||
|
self.market = 'HK'
|
||||||
|
self._basic_info_cache = {}
|
||||||
|
self._active_years_cache = {}
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""Create a database connection."""
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
conn.set_client_encoding('UTF8')
|
||||||
|
return conn
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"DB Connection Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _map_dtype_to_sql(self, dtype):
|
||||||
|
"""Map pandas dtype to PostgreSQL type."""
|
||||||
|
if pd.api.types.is_integer_dtype(dtype):
|
||||||
|
return "BIGINT"
|
||||||
|
elif pd.api.types.is_float_dtype(dtype):
|
||||||
|
return "NUMERIC"
|
||||||
|
elif pd.api.types.is_bool_dtype(dtype):
|
||||||
|
return "BOOLEAN"
|
||||||
|
elif pd.api.types.is_datetime64_any_dtype(dtype):
|
||||||
|
return "TIMESTAMP"
|
||||||
|
else:
|
||||||
|
return "TEXT"
|
||||||
|
|
||||||
|
def _save_df_to_wide_table(self, table_name: str, df: pd.DataFrame, pk_cols: List[str]):
|
||||||
|
"""
|
||||||
|
Save DataFrame to a specific wide table using direct psycopg2 connection.
|
||||||
|
Creates table if not exists using DF columns.
|
||||||
|
Performs incremental UPSERT.
|
||||||
|
"""
|
||||||
|
if df is None or df.empty:
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Clean Data
|
||||||
|
df_clean = df.replace({np.nan: None})
|
||||||
|
|
||||||
|
# Convert date columns to YYYY-MM-DD format if needed
|
||||||
|
for col in df_clean.columns:
|
||||||
|
if 'date' in col.lower() and df_clean[col].dtype == 'object':
|
||||||
|
try:
|
||||||
|
sample = df_clean[col].dropna().astype(str).iloc[0] if not df_clean[col].dropna().empty else ""
|
||||||
|
if len(sample) == 8 and sample.isdigit():
|
||||||
|
df_clean[col] = df_clean[col].astype(str).apply(
|
||||||
|
lambda x: f"{x[:4]}-{x[4:6]}-{x[6:]}" if x and len(str(x))==8 else x
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
columns = list(df_clean.columns)
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# 2. Check/Create Table
|
||||||
|
cur.execute("SELECT to_regclass(%s)", (f"public.{table_name}",))
|
||||||
|
table_exists = cur.fetchone()[0] is not None
|
||||||
|
|
||||||
|
# Filter out valid columns for SQL
|
||||||
|
# Just use dataframe columns for initial creation
|
||||||
|
|
||||||
|
if not table_exists:
|
||||||
|
logger.info(f"🆕 [Database] Creating table {table_name}...")
|
||||||
|
col_defs = ['"id" SERIAL PRIMARY KEY']
|
||||||
|
for col in columns:
|
||||||
|
sql_type = self._map_dtype_to_sql(df_clean[col].dtype)
|
||||||
|
col_defs.append(f'"{col}" {sql_type}')
|
||||||
|
|
||||||
|
col_defs.append('"update_date" TIMESTAMP DEFAULT CURRENT_TIMESTAMP')
|
||||||
|
pk_str = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
constraint_name = f"uq_{table_name}"
|
||||||
|
|
||||||
|
create_sql = f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS {table_name} (
|
||||||
|
{', '.join(col_defs)},
|
||||||
|
CONSTRAINT {constraint_name} UNIQUE ({pk_str})
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
cur.execute(create_sql)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# 3. Get existing columns to avoid insertion errors
|
||||||
|
cur.execute("""
|
||||||
|
SELECT column_name
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = %s
|
||||||
|
""", (table_name,))
|
||||||
|
db_cols = {row[0] for row in cur.fetchall()}
|
||||||
|
|
||||||
|
# Check if 'id' column exists, if not add it (JIT schema evolution)
|
||||||
|
if 'id' not in db_cols:
|
||||||
|
try:
|
||||||
|
cur.execute(f'ALTER TABLE "{table_name}" ADD COLUMN "id" SERIAL')
|
||||||
|
conn.commit()
|
||||||
|
db_cols.add('id')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error adding id column to {table_name}: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
valid_cols = [c for c in columns if c in db_cols]
|
||||||
|
if not valid_cols: return
|
||||||
|
|
||||||
|
# 4. Upsert
|
||||||
|
cols_str = ", ".join([f'"{c}"' for c in valid_cols])
|
||||||
|
vals_str = ", ".join(["%s"] * len(valid_cols))
|
||||||
|
updates = [f'"{c}" = EXCLUDED."{c}"' for c in valid_cols if c not in pk_cols]
|
||||||
|
if 'update_date' in db_cols:
|
||||||
|
updates.append('"update_date" = CURRENT_TIMESTAMP')
|
||||||
|
update_clause = f"DO UPDATE SET {', '.join(updates)}" if updates else "DO NOTHING"
|
||||||
|
pk_conflict = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
|
||||||
|
insert_sql = f"""
|
||||||
|
INSERT INTO {table_name} ({cols_str})
|
||||||
|
VALUES ({vals_str})
|
||||||
|
ON CONFLICT ({pk_conflict})
|
||||||
|
{update_clause}
|
||||||
|
"""
|
||||||
|
|
||||||
|
data_tuples = [tuple(x) for x in df_clean[valid_cols].to_numpy()]
|
||||||
|
cur.executemany(insert_sql, data_tuples)
|
||||||
|
conn.commit()
|
||||||
|
# logger.info(f"✅ Saved {len(data_tuples)} rows to {table_name}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving to {table_name}: {e}", exc_info=True)
|
||||||
|
conn.rollback()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def _parse_ifind_tables(self, res: dict, params: dict = None) -> pd.DataFrame:
|
||||||
|
if not res:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
error_code = res.get("errorcode", 0)
|
||||||
|
if error_code != 0:
|
||||||
|
logger.error(f"iFinD API Error: {res.get('errmsg')} (code: {error_code})")
|
||||||
|
if params:
|
||||||
|
logger.error(f"Failed Params: {params}")
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
tables = res.get("tables", [])
|
||||||
|
if not tables:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
table_info = tables[0]
|
||||||
|
table_data = table_info.get("table", {})
|
||||||
|
times = table_info.get("time", [])
|
||||||
|
|
||||||
|
if not table_data:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
processed_table_data = {}
|
||||||
|
for k, v in table_data.items():
|
||||||
|
if not isinstance(v, list):
|
||||||
|
processed_table_data[k] = [v]
|
||||||
|
else:
|
||||||
|
processed_table_data[k] = v
|
||||||
|
|
||||||
|
df = pd.DataFrame(processed_table_data)
|
||||||
|
if times and len(times) == len(df):
|
||||||
|
df['end_date'] = [str(t).replace('-', '').replace('/', '').split(' ')[0] for t in times]
|
||||||
|
elif times and len(df) == 1:
|
||||||
|
df['end_date'] = str(times[0]).replace('-', '').replace('/', '').split(' ')[0]
|
||||||
|
|
||||||
|
if 'end_date' not in df.columns:
|
||||||
|
for col in ['time', 'date', 'trade_date', 'REPORT_DATE']:
|
||||||
|
if col in df.columns:
|
||||||
|
df['end_date'] = df[col].astype(str).str.replace('-', '').str.replace('/', '').str.split(' ').str[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def _filter_data(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
if df.empty or 'end_date' not in df.columns:
|
||||||
|
return df
|
||||||
|
|
||||||
|
df = df.sort_values(by='end_date', ascending=False)
|
||||||
|
df = df.drop_duplicates(subset=['end_date'], keep='first')
|
||||||
|
|
||||||
|
if df.empty:
|
||||||
|
return df
|
||||||
|
|
||||||
|
latest_record = df.iloc[[0]]
|
||||||
|
try:
|
||||||
|
latest_date_str = str(latest_record['end_date'].values[0])
|
||||||
|
last_year_date_str = str(int(latest_date_str) - 10000)
|
||||||
|
comparable_record = df[df['end_date'].astype(str) == last_year_date_str]
|
||||||
|
except:
|
||||||
|
comparable_record = pd.DataFrame()
|
||||||
|
|
||||||
|
if comparable_record.empty:
|
||||||
|
dfs_to_concat = [latest_record, df]
|
||||||
|
else:
|
||||||
|
dfs_to_concat = [latest_record, comparable_record, df]
|
||||||
|
|
||||||
|
combined = pd.concat(dfs_to_concat)
|
||||||
|
combined = combined.drop_duplicates(subset=['end_date'])
|
||||||
|
combined = combined.sort_values(by='end_date', ascending=False)
|
||||||
|
return combined
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str, code: str) -> dict:
|
||||||
|
if code in self._basic_info_cache:
|
||||||
|
return self._basic_info_cache[code]
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "corp_cn_name", "indiparams": []},
|
||||||
|
{"indicator": "accounting_date", "indiparams": []},
|
||||||
|
{"indicator": "ipo_date", "indiparams": []}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res, params)
|
||||||
|
if not df.empty:
|
||||||
|
df['code'] = code # Inject ID
|
||||||
|
# In backend, we skip file saving and rely on DB
|
||||||
|
# self._save_raw_data(df, symbol, "basic_info_raw")
|
||||||
|
self._save_df_to_wide_table("ifind_hk_stock_basic", df, ["code"])
|
||||||
|
|
||||||
|
info = {
|
||||||
|
"name": "",
|
||||||
|
"accounting_date": "1231",
|
||||||
|
"ipo_date": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
row = df.iloc[0]
|
||||||
|
info["name"] = str(row.get("corp_cn_name", ""))
|
||||||
|
info["acc_date"] = str(row.get("accounting_date", "1231"))
|
||||||
|
info["accounting_date"] = "1231"
|
||||||
|
info["ipo_date"] = str(row.get("ipo_date", "")).replace("-", "").replace("/", "")
|
||||||
|
|
||||||
|
self._basic_info_cache[code] = info
|
||||||
|
return info
|
||||||
|
|
||||||
|
def _fetch_financial_data_annual(self, symbol: str, code: str, indicator_configs: list) -> pd.DataFrame:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
|
||||||
|
last_valid_year = None
|
||||||
|
for offset in range(3):
|
||||||
|
test_year = current_year - offset
|
||||||
|
test_date = f"{test_year}1231"
|
||||||
|
first_indicator = indicator_configs[0]
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": first_indicator["indicator"], "indiparams": [test_date, first_indicator.get("type", "1"), "CNY"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
valid_val = df.iloc[0, 0] if not df.empty and df.shape[1] > 0 else None
|
||||||
|
if pd.notna(valid_val) and valid_val != 0:
|
||||||
|
last_valid_year = test_year
|
||||||
|
break
|
||||||
|
|
||||||
|
if last_valid_year is None:
|
||||||
|
last_valid_year = current_year
|
||||||
|
|
||||||
|
all_dfs = []
|
||||||
|
for i in range(5):
|
||||||
|
target_year = last_valid_year - i
|
||||||
|
target_date = f"{target_year}1231"
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": item["indicator"], "indiparams": [target_date, item.get("type", "1"), "CNY"]}
|
||||||
|
for item in indicator_configs
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res, params)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
valid_cols = [c for c in df.columns if c not in ['end_date', 'date']]
|
||||||
|
if not df[valid_cols].isnull().all().all():
|
||||||
|
df['end_date'] = target_date
|
||||||
|
all_dfs.append(df)
|
||||||
|
|
||||||
|
if not all_dfs:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
# Cache the actual years found in financial statements
|
||||||
|
try:
|
||||||
|
years = sorted([int(str(d)[:4]) for d in pd.concat(all_dfs)['end_date'].unique() if str(d)[:4].isdigit()])
|
||||||
|
if years:
|
||||||
|
self._active_years_cache[code] = years
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return pd.concat(all_dfs, ignore_index=True)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "total_oi"},
|
||||||
|
{"indicator": "prime_oi"},
|
||||||
|
{"indicator": "other_oi"},
|
||||||
|
{"indicator": "operating_cost"},
|
||||||
|
{"indicator": "operating_expense"},
|
||||||
|
{"indicator": "operating_fee"},
|
||||||
|
{"indicator": "p_depreciation_and_amortization"},
|
||||||
|
{"indicator": "gross_profit"},
|
||||||
|
{"indicator": "sales_ad_and_ga"},
|
||||||
|
{"indicator": "rad_cost"},
|
||||||
|
{"indicator": "sales_fee"},
|
||||||
|
{"indicator": "financial_expense"},
|
||||||
|
{"indicator": "sales_income"},
|
||||||
|
{"indicator": "sales_cost"},
|
||||||
|
{"indicator": "other_income"},
|
||||||
|
{"indicator": "manage_fee"},
|
||||||
|
{"indicator": "deprec_and_amorti"},
|
||||||
|
{"indicator": "total_other_opearting_expense"},
|
||||||
|
{"indicator": "p_total_cost"},
|
||||||
|
{"indicator": "operating_profit"},
|
||||||
|
{"indicator": "total_gal"},
|
||||||
|
{"indicator": "interest_income"},
|
||||||
|
{"indicator": "interest_net_pay"},
|
||||||
|
{"indicator": "interest_expense"},
|
||||||
|
{"indicator": "income_from_asso_and_joint"},
|
||||||
|
{"indicator": "other_gal_effct_profit_pre_tax"},
|
||||||
|
{"indicator": "conti_op_before_tax"},
|
||||||
|
{"indicator": "profit_before_noncurrent_items"},
|
||||||
|
{"indicator": "profit_and_loss_of_noncurrent_items"},
|
||||||
|
{"indicator": "profit_before_tax"},
|
||||||
|
{"indicator": "income_tax"},
|
||||||
|
{"indicator": "profit_after_tax"},
|
||||||
|
{"indicator": "minoritygal"},
|
||||||
|
{"indicator": "continue_operate_net_profit"},
|
||||||
|
{"indicator": "noncontinue_operate_net_profit"},
|
||||||
|
{"indicator": "other_special_items"},
|
||||||
|
{"indicator": "ni_attr_to_cs"},
|
||||||
|
{"indicator": "np_atms"},
|
||||||
|
{"indicator": "preferred_divid_and_other_adjust"},
|
||||||
|
{"indicator": "oci"},
|
||||||
|
{"indicator": "total_oci"},
|
||||||
|
{"indicator": "oci_from_parent"},
|
||||||
|
{"indicator": "oci_from_minority"},
|
||||||
|
{"indicator": "invest_property_fv_chg"},
|
||||||
|
{"indicator": "operating_amt"},
|
||||||
|
{"indicator": "oi_si"},
|
||||||
|
{"indicator": "operating_premium_profit_si"},
|
||||||
|
{"indicator": "to_toallied_corp_perf"},
|
||||||
|
{"indicator": "to_joint_control_entity_perf"},
|
||||||
|
{"indicator": "pre_tax_profit_si"},
|
||||||
|
{"indicator": "after_tax_profit_si"},
|
||||||
|
{"indicator": "profit_attrbt_to_nonholders"},
|
||||||
|
{"indicator": "total_income_atncs"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
# Backend assumption: no manual raw file saving.
|
||||||
|
|
||||||
|
# Save Wide Table
|
||||||
|
df['code'] = code # Ensure Primary Key part 1
|
||||||
|
df['symbol'] = symbol
|
||||||
|
# Primary Key: code + end_date
|
||||||
|
self._save_df_to_wide_table("ifind_hk_income_statement", df, ["code", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'total_oi': 'revenue',
|
||||||
|
'operating_amt': 'turnover',
|
||||||
|
'gross_profit': 'gross_profit',
|
||||||
|
'sales_ad_and_ga': 'sga_exp',
|
||||||
|
'sales_fee': 'selling_marketing_exp',
|
||||||
|
'manage_fee': 'ga_exp',
|
||||||
|
'rad_cost': 'rd_exp',
|
||||||
|
'income_tax': 'income_tax',
|
||||||
|
'ni_attr_to_cs': 'net_income',
|
||||||
|
'operating_profit': 'operating_profit',
|
||||||
|
'depreciation': 'depreciation',
|
||||||
|
'deprec_and_amorti': 'depreciation',
|
||||||
|
'p_depreciation_and_amortization': 'depreciation'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
if 'ebit' not in df_filtered.columns and 'operating_profit' in df_filtered.columns:
|
||||||
|
df_filtered['ebit'] = df_filtered['operating_profit']
|
||||||
|
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "cce"},
|
||||||
|
{"indicator": "st_investment"},
|
||||||
|
{"indicator": "total_cash"},
|
||||||
|
{"indicator": "account_receivable"},
|
||||||
|
{"indicator": "tradable_fnncl_asset"},
|
||||||
|
{"indicator": "derivative_fnncl_assets"},
|
||||||
|
{"indicator": "restriv_fund"},
|
||||||
|
{"indicator": "other_short_term_investment"},
|
||||||
|
{"indicator": "ar_nr"},
|
||||||
|
{"indicator": "total_ar"},
|
||||||
|
{"indicator": "or"},
|
||||||
|
{"indicator": "inventory"},
|
||||||
|
{"indicator": "flow_assets_dit"},
|
||||||
|
{"indicator": "pre_payment"},
|
||||||
|
{"indicator": "other_cunrrent_assets_si"},
|
||||||
|
{"indicator": "other_ca"},
|
||||||
|
{"indicator": "total_ca"},
|
||||||
|
{"indicator": "receivables_from_allied_corp"},
|
||||||
|
{"indicator": "current_assets_si"},
|
||||||
|
{"indicator": "prepay_deposits_etc"},
|
||||||
|
{"indicator": "receivables_from_jce"},
|
||||||
|
{"indicator": "receivables_from_ac"},
|
||||||
|
{"indicator": "recoverable_tax"},
|
||||||
|
{"indicator": "total_fixed_assets"},
|
||||||
|
{"indicator": "depreciation"},
|
||||||
|
{"indicator": "equity_and_lt_invest"},
|
||||||
|
{"indicator": "net_fixed_assets"},
|
||||||
|
{"indicator": "invest_property"},
|
||||||
|
{"indicator": "equity_investment"},
|
||||||
|
{"indicator": "investment_in_associate"},
|
||||||
|
{"indicator": "investment_in_joints"},
|
||||||
|
{"indicator": "held_to_maturity_invest"},
|
||||||
|
{"indicator": "goodwill_and_intangible_asset"},
|
||||||
|
{"indicator": "intangible_assets"},
|
||||||
|
{"indicator": "accum_amortized"},
|
||||||
|
{"indicator": "noncurrent_assets_dit"},
|
||||||
|
{"indicator": "other_noncurrent_assets_si"},
|
||||||
|
{"indicator": "dt_assets"},
|
||||||
|
{"indicator": "total_noncurrent_assets"},
|
||||||
|
{"indicator": "total_assets"},
|
||||||
|
{"indicator": "ac_equity"},
|
||||||
|
{"indicator": "lease_prepay"},
|
||||||
|
{"indicator": "noncurrent_assets_si"},
|
||||||
|
{"indicator": "st_lt_current_loan"},
|
||||||
|
{"indicator": "trade_financial_lia"},
|
||||||
|
{"indicator": "derivative_financial_lia"},
|
||||||
|
{"indicator": "ap_np"},
|
||||||
|
{"indicator": "accounts_payable"},
|
||||||
|
{"indicator": "advance_payment"},
|
||||||
|
{"indicator": "st_debt"},
|
||||||
|
{"indicator": "contra_liab"},
|
||||||
|
{"indicator": "tax_payable"},
|
||||||
|
{"indicator": "accrued_liab"},
|
||||||
|
{"indicator": "flow_debt_deferred_income"},
|
||||||
|
{"indicator": "other_cl"},
|
||||||
|
{"indicator": "other_cunrrent_liab_si"},
|
||||||
|
{"indicator": "total_cl"},
|
||||||
|
{"indicator": "accrued_expenses_etc"},
|
||||||
|
{"indicator": "money_payable_toac"},
|
||||||
|
{"indicator": "joint_control_entity_payable"},
|
||||||
|
{"indicator": "payable_to_associated_corp"},
|
||||||
|
{"indicator": "lt_debt"},
|
||||||
|
{"indicator": "long_term_loan"},
|
||||||
|
{"indicator": "other_noncurrent_liabi"},
|
||||||
|
{"indicator": "deferred_tax_liability"},
|
||||||
|
{"indicator": "ncl_deferred_income"},
|
||||||
|
{"indicator": "other_noncurrent_liab_si"},
|
||||||
|
{"indicator": "noncurrent_liab_si"},
|
||||||
|
{"indicator": "total_noncurrent_liab"},
|
||||||
|
{"indicator": "total_liab"},
|
||||||
|
{"indicator": "common_shares"},
|
||||||
|
{"indicator": "capital_reserve"},
|
||||||
|
{"indicator": "equity_premium"},
|
||||||
|
{"indicator": "treasury_stock"},
|
||||||
|
{"indicator": "accumgal"},
|
||||||
|
{"indicator": "equity_atsopc_sbi"},
|
||||||
|
{"indicator": "preferred_stock"},
|
||||||
|
{"indicator": "perpetual_debt"},
|
||||||
|
{"indicator": "reserve"},
|
||||||
|
{"indicator": "other_reserves"},
|
||||||
|
{"indicator": "retained_earnings"},
|
||||||
|
{"indicator": "oci_bs"},
|
||||||
|
{"indicator": "total_common_equity"},
|
||||||
|
{"indicator": "equity_belong_to_parent"},
|
||||||
|
{"indicator": "minority_interests"},
|
||||||
|
{"indicator": "other_equity_si"},
|
||||||
|
{"indicator": "total_equity"},
|
||||||
|
{"indicator": "total_lib_and_equity"},
|
||||||
|
{"indicator": "equity_si"},
|
||||||
|
{"indicator": "equity_atncs"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
|
||||||
|
df['code'] = code
|
||||||
|
df['symbol'] = symbol
|
||||||
|
self._save_df_to_wide_table("ifind_hk_balance_sheet", df, ["code", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'cce': 'cash',
|
||||||
|
'ar_nr': 'receivables',
|
||||||
|
'inventory': 'inventory',
|
||||||
|
'net_fixed_assets': 'fixed_assets',
|
||||||
|
'equity_and_lt_invest': 'long_term_investments',
|
||||||
|
'goodwill_and_intangible_asset': 'goodwill',
|
||||||
|
'st_debt': 'short_term_debt',
|
||||||
|
'st_lt_current_loan': 'short_term_borrowings',
|
||||||
|
'ap_np': 'accounts_payable',
|
||||||
|
'contra_liab': 'contract_liabilities',
|
||||||
|
'advance_payment': 'advances_from_customers',
|
||||||
|
'flow_debt_deferred_income': 'deferred_revenue',
|
||||||
|
'lt_debt': 'long_term_debt',
|
||||||
|
'long_term_loan': 'long_term_borrowings',
|
||||||
|
'total_assets': 'total_assets',
|
||||||
|
'equity_belong_to_parent': 'total_equity',
|
||||||
|
'pre_payment': 'prepayment'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
if 'total_liabilities' not in df_filtered.columns or df_filtered['total_liabilities'].isnull().all():
|
||||||
|
if 'total_liab' in df_filtered.columns:
|
||||||
|
df_filtered['total_liabilities'] = df_filtered['total_liab']
|
||||||
|
elif 'total_assets' in df_filtered.columns and 'total_equity' in df_filtered.columns:
|
||||||
|
df_filtered['total_liabilities'] = df_filtered['total_assets'] - df_filtered['total_equity']
|
||||||
|
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "ni"},
|
||||||
|
{"indicator": "depreciation_and_amortization"},
|
||||||
|
{"indicator": "operating_capital_change"},
|
||||||
|
{"indicator": "ncf_from_oa"},
|
||||||
|
{"indicator": "capital_cost"},
|
||||||
|
{"indicator": "invest_buy"},
|
||||||
|
{"indicator": "ncf_from_ia"},
|
||||||
|
{"indicator": "increase_in_share_capital"},
|
||||||
|
{"indicator": "decrease_in_share_capital"},
|
||||||
|
{"indicator": "total_dividends_paid"},
|
||||||
|
{"indicator": "ncf_from_fa"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
|
||||||
|
df['code'] = code
|
||||||
|
df['symbol'] = symbol
|
||||||
|
self._save_df_to_wide_table("ifind_hk_cash_flow", df, ["code", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'ncf_from_oa': 'ocf',
|
||||||
|
'capital_cost': 'capex',
|
||||||
|
'total_dividends_paid': 'dividends'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
if 'capex' in df_filtered.columns:
|
||||||
|
df_filtered['capex'] = df_filtered['capex'].abs()
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str, code: str) -> dict:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
|
||||||
|
metrics = {
|
||||||
|
"name": basic_info.get("name", ""),
|
||||||
|
"list_date": basic_info.get("ipo_date", ""),
|
||||||
|
"accounting_date": basic_info.get("accounting_date", ""),
|
||||||
|
"price": 0,
|
||||||
|
"market_cap": 0,
|
||||||
|
"pe": 0,
|
||||||
|
"pb": 0,
|
||||||
|
"dividend_yield": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# In backend logic we cannot easily read file.
|
||||||
|
# But we can query DB for income statement dates!
|
||||||
|
# Or just fallback to 'active_years' logic.
|
||||||
|
# For simplicity in migration, let's use the DB query if possible, or just the fallback logic.
|
||||||
|
|
||||||
|
report_dates = []
|
||||||
|
# Try to get dates from active_years_cache first (populated by get_income_statement call in flow)
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years = self._active_years_cache[code]
|
||||||
|
report_dates = [f"{y}1231" for y in years]
|
||||||
|
else:
|
||||||
|
# Fallback
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
report_dates = [f"{current_year - i}1231" for i in range(5)]
|
||||||
|
|
||||||
|
# Fetch daily_basic data for each report date
|
||||||
|
all_daily_basic = []
|
||||||
|
for date_str in report_dates:
|
||||||
|
if len(str(date_str)) == 8:
|
||||||
|
formatted_date = f"{str(date_str)[:4]}-{str(date_str)[4:6]}-{str(date_str)[6:]}"
|
||||||
|
else:
|
||||||
|
formatted_date = str(date_str)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"functionpara": {"date_sequence": formatted_date},
|
||||||
|
"startdate": "",
|
||||||
|
"enddate": "",
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "close_price", "indiparams": ["", "0", "BB"]},
|
||||||
|
{"indicator": "market_value", "indiparams": ["", "BB"]},
|
||||||
|
{"indicator": "pb_latest", "indiparams": ["", "100"]},
|
||||||
|
{"indicator": "dividend_yield_ttm_ex_sd", "indiparams": [""]},
|
||||||
|
{"indicator": "pe_ttm", "indiparams": ["", "100"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("date_sequence", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
df['code'] = code
|
||||||
|
df['end_date'] = str(date_str).replace('-', '')
|
||||||
|
all_daily_basic.append(df)
|
||||||
|
|
||||||
|
# Save to DB
|
||||||
|
if all_daily_basic:
|
||||||
|
combined_df = pd.concat(all_daily_basic, ignore_index=True)
|
||||||
|
self._save_df_to_wide_table("ifind_hk_daily_basic", combined_df, ["code", "end_date"])
|
||||||
|
|
||||||
|
# Use the first (most recent) data for metrics dict
|
||||||
|
latest_df = all_daily_basic[0]
|
||||||
|
if not latest_df.empty:
|
||||||
|
row = latest_df.iloc[0]
|
||||||
|
metrics["price"] = float(row.get("close_price") or 0)
|
||||||
|
metrics["market_cap"] = float(row.get("market_value") or 0)
|
||||||
|
metrics["pe"] = float(row.get("pe_ttm") or 0)
|
||||||
|
metrics["pb"] = float(row.get("pb_latest") or 0)
|
||||||
|
metrics["dividend_yield"] = float(row.get("dividend_yield_ttm_ex_sd") or 0)
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
years_to_fetch = [current_year - i for i in range(5)]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for year_int in years_to_fetch:
|
||||||
|
year_str = str(year_int)
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "annual_cum_dividend", "indiparams": [year_str, "CNY"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty and 'annual_cum_dividend' in df.columns:
|
||||||
|
df['code'] = code
|
||||||
|
end_date = f"{year_str}1231"
|
||||||
|
df['end_date'] = end_date
|
||||||
|
self._save_df_to_wide_table("ifind_hk_dividend", df, ["code", "end_date"])
|
||||||
|
|
||||||
|
val = df['annual_cum_dividend'].iloc[0]
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
results.append({
|
||||||
|
'date_str': end_date,
|
||||||
|
'dividends': float(val)
|
||||||
|
})
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_div = pd.DataFrame(results)
|
||||||
|
return df_div
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
years_to_fetch = [current_year - i for i in range(5)]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for target_year in years_to_fetch:
|
||||||
|
start_date = f"{target_year - 1}-12-31"
|
||||||
|
end_date = f"{target_year}-12-31"
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "repurchase_volume_interval", "indiparams": [start_date, end_date]},
|
||||||
|
{"indicator": "repurchase_amount_interval", "indiparams": [start_date, end_date]},
|
||||||
|
{"indicator": "repurchase_low_price", "indiparams": [start_date, end_date]},
|
||||||
|
{"indicator": "repurchase_high_price", "indiparams": [start_date, end_date]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
valid_row = False
|
||||||
|
for col in df.columns:
|
||||||
|
val = df[col].iloc[0]
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
valid_row = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if valid_row:
|
||||||
|
df['code'] = code
|
||||||
|
df['end_date'] = end_date.replace('-', '')
|
||||||
|
self._save_df_to_wide_table("ifind_hk_repurchase", df, ["code", "end_date"])
|
||||||
755
backend/app/clients/ifind_int_client.py
Normal file
755
backend/app/clients/ifind_int_client.py
Normal file
@ -0,0 +1,755 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
import numpy as np
|
||||||
|
from typing import List, Union
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
from .ifind_client import IFindClient
|
||||||
|
|
||||||
|
# Get logger
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Explicitly load .env from project root
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
class IFindIntClient:
|
||||||
|
"""
|
||||||
|
Generic iFinD Client for International Markets (JP, VN, US) - Backend Version.
|
||||||
|
Uses 'OAS' (Original Accounting Standards) standardized indicators.
|
||||||
|
Implements generic wide-table persistence (Side-Channel) for background task compatibility.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str, market: str):
|
||||||
|
self.cli = IFindClient(refresh_token=api_key)
|
||||||
|
self.market = market
|
||||||
|
self._basic_info_cache = {}
|
||||||
|
self._active_years_cache = {}
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""Create a database connection."""
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
conn.set_client_encoding('UTF8')
|
||||||
|
return conn
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"DB Connection Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _map_dtype_to_sql(self, dtype):
|
||||||
|
"""Map pandas dtype to PostgreSQL type."""
|
||||||
|
if pd.api.types.is_integer_dtype(dtype):
|
||||||
|
return "BIGINT"
|
||||||
|
elif pd.api.types.is_float_dtype(dtype):
|
||||||
|
return "NUMERIC"
|
||||||
|
elif pd.api.types.is_bool_dtype(dtype):
|
||||||
|
return "BOOLEAN"
|
||||||
|
elif pd.api.types.is_datetime64_any_dtype(dtype):
|
||||||
|
return "TIMESTAMP"
|
||||||
|
else:
|
||||||
|
return "TEXT"
|
||||||
|
|
||||||
|
def _save_df_to_wide_table(self, table_name: str, df: pd.DataFrame, pk_cols: List[str]):
|
||||||
|
"""
|
||||||
|
Save DataFrame to a specific wide table using direct psycopg2 connection.
|
||||||
|
Creates table if not exists using DF columns.
|
||||||
|
Performs incremental UPSERT.
|
||||||
|
"""
|
||||||
|
if df is None or df.empty:
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Clean Data
|
||||||
|
df_clean = df.replace({np.nan: None})
|
||||||
|
|
||||||
|
# Convert date columns
|
||||||
|
for col in df_clean.columns:
|
||||||
|
if 'date' in col.lower() and df_clean[col].dtype == 'object':
|
||||||
|
try:
|
||||||
|
sample = df_clean[col].dropna().astype(str).iloc[0] if not df_clean[col].dropna().empty else ""
|
||||||
|
if len(sample) == 8 and sample.isdigit():
|
||||||
|
df_clean[col] = df_clean[col].astype(str).apply(
|
||||||
|
lambda x: f"{x[:4]}-{x[4:6]}-{x[6:]}" if x and len(str(x))==8 else x
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
columns = list(df_clean.columns)
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# 2. Check/Create Table
|
||||||
|
cur.execute("SELECT to_regclass(%s)", (f"public.{table_name}",))
|
||||||
|
table_exists = cur.fetchone()[0] is not None
|
||||||
|
|
||||||
|
if not table_exists:
|
||||||
|
logger.info(f"🆕 [Database] Creating table {table_name}...")
|
||||||
|
col_defs = ['"id" SERIAL PRIMARY KEY']
|
||||||
|
for col in columns:
|
||||||
|
sql_type = self._map_dtype_to_sql(df_clean[col].dtype)
|
||||||
|
col_defs.append(f'"{col}" {sql_type}')
|
||||||
|
|
||||||
|
col_defs.append('"update_date" TIMESTAMP DEFAULT CURRENT_TIMESTAMP')
|
||||||
|
pk_str = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
constraint_name = f"uq_{table_name}"
|
||||||
|
|
||||||
|
create_sql = f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS {table_name} (
|
||||||
|
{', '.join(col_defs)},
|
||||||
|
CONSTRAINT {constraint_name} UNIQUE ({pk_str})
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
cur.execute(create_sql)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# 3. Get existing columns definition
|
||||||
|
cur.execute("""
|
||||||
|
SELECT column_name
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = %s
|
||||||
|
""", (table_name,))
|
||||||
|
db_cols = {row[0] for row in cur.fetchall()}
|
||||||
|
|
||||||
|
# Check if 'id' column exists, if not add it
|
||||||
|
if 'id' not in db_cols:
|
||||||
|
try:
|
||||||
|
cur.execute(f'ALTER TABLE "{table_name}" ADD COLUMN "id" SERIAL')
|
||||||
|
conn.commit()
|
||||||
|
db_cols.add('id')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error adding id column to {table_name}: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
valid_cols = [c for c in columns if c in db_cols]
|
||||||
|
if not valid_cols: return
|
||||||
|
|
||||||
|
# 4. Upsert
|
||||||
|
cols_str = ", ".join([f'"{c}"' for c in valid_cols])
|
||||||
|
vals_str = ", ".join(["%s"] * len(valid_cols))
|
||||||
|
updates = [f'"{c}" = EXCLUDED."{c}"' for c in valid_cols if c not in pk_cols]
|
||||||
|
if 'update_date' in db_cols:
|
||||||
|
updates.append('"update_date" = CURRENT_TIMESTAMP')
|
||||||
|
update_clause = f"DO UPDATE SET {', '.join(updates)}" if updates else "DO NOTHING"
|
||||||
|
pk_conflict = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
|
||||||
|
insert_sql = f"""
|
||||||
|
INSERT INTO {table_name} ({cols_str})
|
||||||
|
VALUES ({vals_str})
|
||||||
|
ON CONFLICT ({pk_conflict})
|
||||||
|
{update_clause}
|
||||||
|
"""
|
||||||
|
|
||||||
|
data_tuples = [tuple(x) for x in df_clean[valid_cols].to_numpy()]
|
||||||
|
cur.executemany(insert_sql, data_tuples)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error saving to {table_name}: {e}", exc_info=True)
|
||||||
|
conn.rollback()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def _parse_ifind_tables(self, res: dict) -> pd.DataFrame:
|
||||||
|
if not res:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
if res.get("errorcode") != 0:
|
||||||
|
logger.error(f"iFinD API Error: {res.get('errmsg')} (code: {res.get('errorcode')})")
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
tables = res.get("tables", [])
|
||||||
|
if not tables:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
table_info = tables[0]
|
||||||
|
table_data = table_info.get("table", {})
|
||||||
|
times = table_info.get("time", [])
|
||||||
|
|
||||||
|
if not table_data:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
processed_table_data = {}
|
||||||
|
for k, v in table_data.items():
|
||||||
|
if not isinstance(v, list):
|
||||||
|
processed_table_data[k] = [v]
|
||||||
|
else:
|
||||||
|
processed_table_data[k] = v
|
||||||
|
|
||||||
|
df = pd.DataFrame(processed_table_data)
|
||||||
|
if times and len(times) == len(df):
|
||||||
|
df['end_date'] = [str(t).replace('-', '').replace('/', '').split(' ')[0] for t in times]
|
||||||
|
elif times and len(df) == 1:
|
||||||
|
df['end_date'] = str(times[0]).replace('-', '').replace('/', '').split(' ')[0]
|
||||||
|
|
||||||
|
if 'end_date' not in df.columns:
|
||||||
|
for col in ['time', 'date', 'trade_date', 'REPORT_DATE']:
|
||||||
|
if col in df.columns:
|
||||||
|
df['end_date'] = df[col].astype(str).str.replace('-', '').str.replace('/', '').str.split(' ').str[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
def _filter_data(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
if df.empty or 'end_date' not in df.columns:
|
||||||
|
return df
|
||||||
|
|
||||||
|
df = df.sort_values(by='end_date', ascending=False)
|
||||||
|
df = df.drop_duplicates(subset=['end_date'], keep='first')
|
||||||
|
|
||||||
|
if df.empty:
|
||||||
|
return df
|
||||||
|
|
||||||
|
latest_record = df.iloc[[0]]
|
||||||
|
try:
|
||||||
|
latest_date_str = str(latest_record['end_date'].values[0])
|
||||||
|
last_year_date_str = str(int(latest_date_str) - 10000)
|
||||||
|
comparable_record = df[df['end_date'].astype(str) == last_year_date_str]
|
||||||
|
except:
|
||||||
|
comparable_record = pd.DataFrame()
|
||||||
|
|
||||||
|
is_annual = df['end_date'].astype(str).str.endswith('1231') | df['end_date'].astype(str).str.endswith('0331')
|
||||||
|
annual_records = df[is_annual]
|
||||||
|
|
||||||
|
combined = pd.concat([latest_record, comparable_record, annual_records])
|
||||||
|
combined = combined.drop_duplicates(subset=['end_date'])
|
||||||
|
combined = combined.sort_values(by='end_date', ascending=False)
|
||||||
|
return combined
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str, code: str) -> dict:
|
||||||
|
if code in self._basic_info_cache:
|
||||||
|
return self._basic_info_cache[code]
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "corp_cn_name", "indiparams": []},
|
||||||
|
{"indicator": "accounting_date", "indiparams": []},
|
||||||
|
{"indicator": "ipo_date", "indiparams": []}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
if not df.empty:
|
||||||
|
df['code'] = code # Inject ID
|
||||||
|
# self._save_raw_data(df, symbol, "basic_info_raw")
|
||||||
|
# Usually generic international doesn't save stock_basic table, but we can if needed.
|
||||||
|
# Keeping consistent with original logic which only saved raw file.
|
||||||
|
pass
|
||||||
|
|
||||||
|
info = {
|
||||||
|
"name": "",
|
||||||
|
"accounting_date": "1231",
|
||||||
|
"ipo_date": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
row = df.iloc[0]
|
||||||
|
info["name"] = str(row.get("corp_cn_name", ""))
|
||||||
|
acc_date = str(row.get("accounting_date", "1231")).replace("-", "").replace("/", "")
|
||||||
|
if acc_date:
|
||||||
|
info["accounting_date"] = acc_date
|
||||||
|
info["ipo_date"] = str(row.get("ipo_date", "")).replace("-", "").replace("/", "")
|
||||||
|
|
||||||
|
self._basic_info_cache[code] = info
|
||||||
|
return info
|
||||||
|
|
||||||
|
def _fetch_financial_data_annual(self, symbol: str, code: str, indicator_configs: list) -> pd.DataFrame:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
acc_date = basic_info.get("accounting_date", "1231")
|
||||||
|
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
last_valid_year = None
|
||||||
|
|
||||||
|
# 1. Determine most recent valid year
|
||||||
|
for offset in range(3):
|
||||||
|
test_year = current_year - offset
|
||||||
|
test_date = f"{test_year}{acc_date}"
|
||||||
|
first_indicator = indicator_configs[0]
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": first_indicator["indicator"], "indiparams": [test_date, first_indicator.get("type", "1"), "CNY"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
valid_val = df.iloc[0, 0] if not df.empty and df.shape[1] > 0 else None
|
||||||
|
if pd.notna(valid_val) and valid_val != 0:
|
||||||
|
last_valid_year = test_year
|
||||||
|
break
|
||||||
|
|
||||||
|
if last_valid_year is None:
|
||||||
|
last_valid_year = current_year
|
||||||
|
|
||||||
|
all_dfs = []
|
||||||
|
for i in range(5):
|
||||||
|
target_year = last_valid_year - i
|
||||||
|
target_date = f"{target_year}{acc_date}"
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": item["indicator"], "indiparams": [target_date, item.get("type", "1"), "CNY"]}
|
||||||
|
for item in indicator_configs
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
df['end_date'] = target_date
|
||||||
|
all_dfs.append(df)
|
||||||
|
|
||||||
|
# Filter and concat
|
||||||
|
all_dfs = [d for d in all_dfs if not d.empty and not d.isna().all().all()]
|
||||||
|
|
||||||
|
if not all_dfs:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
# Cache the actual years found in financial statements
|
||||||
|
try:
|
||||||
|
years = sorted([int(str(d)[:4]) for d in pd.concat(all_dfs)['end_date'].unique() if str(d)[:4].isdigit()])
|
||||||
|
if years:
|
||||||
|
self._active_years_cache[code] = years
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error caching years: {e}")
|
||||||
|
|
||||||
|
return pd.concat(all_dfs, ignore_index=True)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "revenue_oas"},
|
||||||
|
{"indicator": "gross_profit_oas"},
|
||||||
|
{"indicator": "sga_expenses_oas"},
|
||||||
|
{"indicator": "selling_marketing_expenses_oas"},
|
||||||
|
{"indicator": "ga_expenses_oas"},
|
||||||
|
{"indicator": "rd_expenses_oas"},
|
||||||
|
{"indicator": "income_tax_expense_oas"},
|
||||||
|
{"indicator": "net_income_attri_to_common_sh_oas"},
|
||||||
|
{"indicator": "operating_income_oas"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
# Backend assumption: no file save
|
||||||
|
|
||||||
|
# DB Save
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market # Inject Market
|
||||||
|
df['symbol'] = symbol
|
||||||
|
self._save_df_to_wide_table("ifind_int_income_statement", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'revenue_oas': 'revenue',
|
||||||
|
'gross_profit_oas': 'gross_profit',
|
||||||
|
'sga_expenses_oas': 'sga_exp',
|
||||||
|
'selling_marketing_expenses_oas': 'selling_marketing_exp',
|
||||||
|
'ga_expenses_oas': 'ga_exp',
|
||||||
|
'rd_expenses_oas': 'rd_exp',
|
||||||
|
'income_tax_expense_oas': 'income_tax',
|
||||||
|
'net_income_attri_to_common_sh_oas': 'net_income',
|
||||||
|
'operating_income_oas': 'operating_profit'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol', 'market']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "cash_equi_short_term_inve_oas"},
|
||||||
|
{"indicator": "accou_and_notes_recei_oas"},
|
||||||
|
{"indicator": "inventories_oas"},
|
||||||
|
{"indicator": "ppe_net_oas"},
|
||||||
|
{"indicator": "long_term_inv_and_receiv_oas"},
|
||||||
|
{"indicator": "goodwill_and_intasset_oas"},
|
||||||
|
{"indicator": "short_term_debt_oas"},
|
||||||
|
{"indicator": "short_term_borrowings_oas"},
|
||||||
|
{"indicator": "account_and_note_payable_oas"},
|
||||||
|
{"indicator": "contra_liabilities_current_oas"},
|
||||||
|
{"indicator": "advance_from_cust_current_oas"},
|
||||||
|
{"indicator": "defer_revenue_current_oas"},
|
||||||
|
{"indicator": "long_term_debt_oas"},
|
||||||
|
{"indicator": "long_term_borrowings_oas"},
|
||||||
|
{"indicator": "total_assets_oas"},
|
||||||
|
{"indicator": "equity_attri_to_companyowner_oas"},
|
||||||
|
{"indicator": "prepaid_expenses_current_oas"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['symbol'] = symbol
|
||||||
|
self._save_df_to_wide_table("ifind_int_balance_sheet", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'cash_equi_short_term_inve_oas': 'cash',
|
||||||
|
'accou_and_notes_recei_oas': 'receivables',
|
||||||
|
'inventories_oas': 'inventory',
|
||||||
|
'ppe_net_oas': 'fixed_assets',
|
||||||
|
'long_term_inv_and_receiv_oas': 'long_term_investments',
|
||||||
|
'goodwill_and_intasset_oas': 'goodwill',
|
||||||
|
'short_term_debt_oas': 'short_term_debt',
|
||||||
|
'short_term_borrowings_oas': 'short_term_borrowings',
|
||||||
|
'account_and_note_payable_oas': 'accounts_payable',
|
||||||
|
'contra_liabilities_current_oas': 'contract_liabilities',
|
||||||
|
'advance_from_cust_current_oas': 'advances_from_customers',
|
||||||
|
'defer_revenue_current_oas': 'deferred_revenue',
|
||||||
|
'long_term_debt_oas': 'long_term_debt',
|
||||||
|
'long_term_borrowings_oas': 'long_term_borrowings',
|
||||||
|
'total_assets_oas': 'total_assets',
|
||||||
|
'equity_attri_to_companyowner_oas': 'total_equity',
|
||||||
|
'prepaid_expenses_current_oas': 'prepayment'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
if 'total_liabilities' not in df_filtered.columns or df_filtered['total_liabilities'].isnull().all():
|
||||||
|
if 'total_assets' in df_filtered.columns and 'total_equity' in df_filtered.columns:
|
||||||
|
df_filtered['total_liabilities'] = df_filtered['total_assets'] - df_filtered['total_equity']
|
||||||
|
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol', 'market']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
indicators = [
|
||||||
|
{"indicator": "net_cash_flows_from_oa_oas"},
|
||||||
|
{"indicator": "purchase_of_ppe_and_ia_oas"},
|
||||||
|
{"indicator": "dividends_paid_oas"}
|
||||||
|
]
|
||||||
|
|
||||||
|
df = self._fetch_financial_data_annual(symbol, code, indicators)
|
||||||
|
if df.empty: return df
|
||||||
|
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['symbol'] = symbol
|
||||||
|
self._save_df_to_wide_table("ifind_int_cash_flow", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'net_cash_flows_from_oa_oas': 'ocf',
|
||||||
|
'purchase_of_ppe_and_ia_oas': 'capex',
|
||||||
|
'dividends_paid_oas': 'dividends'
|
||||||
|
}
|
||||||
|
|
||||||
|
df_filtered = df.rename(columns=rename_map)
|
||||||
|
df_filtered = df_filtered.loc[:, ~df_filtered.columns.duplicated()]
|
||||||
|
|
||||||
|
for col in df_filtered.columns:
|
||||||
|
if col not in ['date', 'end_date', 'code', 'symbol', 'market']:
|
||||||
|
df_filtered[col] = pd.to_numeric(df_filtered[col], errors='coerce')
|
||||||
|
|
||||||
|
if 'capex' in df_filtered.columns:
|
||||||
|
df_filtered['capex'] = df_filtered['capex'].abs()
|
||||||
|
|
||||||
|
return self._filter_data(df_filtered)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str, code: str) -> dict:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
metrics = {
|
||||||
|
"name": basic_info.get("name", ""),
|
||||||
|
"list_date": basic_info.get("ipo_date", ""),
|
||||||
|
"price": 0,
|
||||||
|
"market_cap": 0,
|
||||||
|
"pe": 0,
|
||||||
|
"pb": 0,
|
||||||
|
"dividend_yield": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# In backend, rely on DB query or fallbacks
|
||||||
|
report_dates = []
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years = self._active_years_cache[code]
|
||||||
|
report_dates = [f"{y}1231" for y in years]
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
report_dates = [f"{current_year - i}1231" for i in range(5)]
|
||||||
|
|
||||||
|
# Fetch daily_basic data for each report date
|
||||||
|
all_daily_basic = []
|
||||||
|
for date_str in report_dates:
|
||||||
|
if len(str(date_str)) == 8:
|
||||||
|
formatted_date = f"{str(date_str)[:4]}-{str(date_str)[4:6]}-{str(date_str)[6:]}"
|
||||||
|
else:
|
||||||
|
formatted_date = str(date_str)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"functionpara": {"date_sequence": formatted_date},
|
||||||
|
"startdate": "",
|
||||||
|
"enddate": "",
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "close_price", "indiparams": ["", "0", "BB"]},
|
||||||
|
{"indicator": "market_value", "indiparams": ["", "BB"]},
|
||||||
|
{"indicator": "pb_latest", "indiparams": ["", "100"]},
|
||||||
|
{"indicator": "dividend_yield_ttm_ex_sd", "indiparams": [""]},
|
||||||
|
{"indicator": "pe_ttm", "indiparams": ["", "100"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("date_sequence", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['end_date'] = str(date_str).replace('-', '')
|
||||||
|
all_daily_basic.append(df)
|
||||||
|
|
||||||
|
# Save to DB
|
||||||
|
if all_daily_basic:
|
||||||
|
combined_df = pd.concat(all_daily_basic, ignore_index=True)
|
||||||
|
self._save_df_to_wide_table("ifind_int_daily_basic", combined_df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
# Use the first (most recent) data for metrics dict
|
||||||
|
latest_df = all_daily_basic[0]
|
||||||
|
if not latest_df.empty:
|
||||||
|
row = latest_df.iloc[0]
|
||||||
|
metrics["price"] = float(row.get("close_price") or 0)
|
||||||
|
metrics["market_cap"] = float(row.get("market_value") or 0)
|
||||||
|
metrics["pe"] = float(row.get("pe_ttm") or 0)
|
||||||
|
metrics["pb"] = float(row.get("pb_latest") or 0)
|
||||||
|
metrics["dividend_yield"] = float(row.get("dividend_yield_ttm_ex_sd") or 0)
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
acc_date = basic_info.get("accounting_date", "1231")
|
||||||
|
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
years_to_fetch = [current_year - i for i in range(5)]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for year in years_to_fetch:
|
||||||
|
year_str = str(year)
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "annual_cum_dividend", "indiparams": [year_str, "CNY"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty and 'annual_cum_dividend' in df.columns:
|
||||||
|
end_date = f"{year_str}{acc_date}"
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['end_date'] = end_date
|
||||||
|
self._save_df_to_wide_table("ifind_int_dividend", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
val = df['annual_cum_dividend'].iloc[0]
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
results.append({
|
||||||
|
'date_str': end_date,
|
||||||
|
'dividends': float(val)
|
||||||
|
})
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_div = pd.DataFrame(results)
|
||||||
|
return df_div
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
acc_date = basic_info.get("accounting_date", "1231")
|
||||||
|
|
||||||
|
mm = acc_date[:2]
|
||||||
|
dd = acc_date[2:]
|
||||||
|
fmt_mm_dd = f"{mm}-{dd}"
|
||||||
|
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
years_to_fetch = [current_year - i for i in range(5)]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for target_year in years_to_fetch:
|
||||||
|
start_date = f"{target_year - 1}-{fmt_mm_dd}"
|
||||||
|
end_date = f"{target_year}-{fmt_mm_dd}"
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "repur_num_new", "indiparams": [start_date, end_date, "1"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty and 'repur_num_new' in df.columns:
|
||||||
|
target_date = f"{target_year}{acc_date}"
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['end_date'] = target_date
|
||||||
|
self._save_df_to_wide_table("ifind_int_repurchase", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
val = df['repur_num_new'].iloc[0]
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
results.append({
|
||||||
|
'date_str': target_date,
|
||||||
|
'repurchases': float(val)
|
||||||
|
})
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_repur = pd.DataFrame(results)
|
||||||
|
return df_repur
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
acc_date = basic_info.get("accounting_date", "1231")
|
||||||
|
mm = acc_date[:2]
|
||||||
|
dd = acc_date[2:]
|
||||||
|
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
years_to_fetch = [current_year - i for i in range(5)]
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for target_year in years_to_fetch:
|
||||||
|
target_date = f"{target_year}-{mm}-{dd}"
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [
|
||||||
|
{"indicator": "staff_num", "indiparams": [target_date]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty and 'staff_num' in df.columns:
|
||||||
|
df['code'] = code
|
||||||
|
df['market'] = self.market
|
||||||
|
df['end_date'] = f"{target_year}{acc_date}"
|
||||||
|
self._save_df_to_wide_table("ifind_int_employee", df, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
val = df['staff_num'].iloc[0]
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
results.append({
|
||||||
|
'date_str': f"{target_year}{acc_date}",
|
||||||
|
'employee_count': float(val)
|
||||||
|
})
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_emp = pd.DataFrame(results)
|
||||||
|
return df_emp
|
||||||
|
|
||||||
|
def get_financial_ratios(self, symbol: str, code: str) -> pd.DataFrame:
|
||||||
|
current_year = int(time.strftime("%Y"))
|
||||||
|
basic_info = self._fetch_basic_info(symbol, code)
|
||||||
|
acc_date = basic_info.get("accounting_date", "1231")
|
||||||
|
|
||||||
|
last_valid_year = None
|
||||||
|
for offset in range(3):
|
||||||
|
test_year = current_year - offset
|
||||||
|
test_date = f"{test_year}{acc_date}"
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": [{"indicator": "roe", "indiparams": [test_date]}]
|
||||||
|
}
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
if not df.empty:
|
||||||
|
val = df.iloc[0, 0] if not df.empty and df.shape[1] > 0 else None
|
||||||
|
if pd.notna(val) and val != 0:
|
||||||
|
last_valid_year = test_year
|
||||||
|
break
|
||||||
|
|
||||||
|
if last_valid_year is None:
|
||||||
|
last_valid_year = current_year
|
||||||
|
|
||||||
|
all_dfs = []
|
||||||
|
|
||||||
|
# Use cached years from financial statements
|
||||||
|
if code in self._active_years_cache:
|
||||||
|
years_to_fetch = sorted(self._active_years_cache[code], reverse=True)
|
||||||
|
else:
|
||||||
|
# Fallback to last_valid_year approach
|
||||||
|
years_to_fetch = [last_valid_year - i for i in range(5)]
|
||||||
|
|
||||||
|
for target_year in years_to_fetch:
|
||||||
|
date_str = f"{target_year}{acc_date}"
|
||||||
|
year_str = str(target_year)
|
||||||
|
|
||||||
|
indipara = []
|
||||||
|
for key in ["salary_pp", "revenue_pp", "profit_pp"]:
|
||||||
|
indipara.append({"indicator": key, "indiparams": [year_str, "100"]})
|
||||||
|
|
||||||
|
ratio_keys = [
|
||||||
|
"roe", "roa", "roic",
|
||||||
|
"sales_fee_to_or", "manage_fee_to_revenue", "rad_expense_to_total_income",
|
||||||
|
"operating_revenue_yoy", "np_atsopc_yoy",
|
||||||
|
"ibdebt_ratio_asset_base",
|
||||||
|
"inventory_turnover_days", "receivable_turnover_days", "accounts_payable_turnover_days",
|
||||||
|
"fixed_asset_turnover_ratio", "total_capital_turnover"
|
||||||
|
]
|
||||||
|
for key in ratio_keys:
|
||||||
|
indipara.append({"indicator": key, "indiparams": [date_str]})
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"codes": code,
|
||||||
|
"indipara": indipara
|
||||||
|
}
|
||||||
|
|
||||||
|
res = self.cli.post("basic_data_service", params)
|
||||||
|
# Use 'params' to debug if needed, but logging is inside _parse in client base
|
||||||
|
df = self._parse_ifind_tables(res)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
if 'end_date' not in df.columns:
|
||||||
|
df['end_date'] = date_str
|
||||||
|
df = df.dropna(axis=1, how='all')
|
||||||
|
all_dfs.append(df)
|
||||||
|
|
||||||
|
if not all_dfs:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
combined = pd.concat(all_dfs, ignore_index=True)
|
||||||
|
# Ratio table save
|
||||||
|
combined['code'] = code
|
||||||
|
combined['market'] = self.market
|
||||||
|
self._save_df_to_wide_table("ifind_int_financial_ratios", combined, ["code", "market", "end_date"])
|
||||||
|
|
||||||
|
return combined
|
||||||
|
|
||||||
468
backend/app/clients/tushare_cn_client.py
Normal file
468
backend/app/clients/tushare_cn_client.py
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
"""
|
||||||
|
Tushare CN Client for Backend API
|
||||||
|
Direct port from src/fetchers/tushare_cn_client.py
|
||||||
|
Removed storage.file_io dependency, only uses PostgreSQL
|
||||||
|
"""
|
||||||
|
import tushare as ts
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
from datetime import datetime
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from typing import Union, List, Dict, Any
|
||||||
|
import numpy as np
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
# 获取logger (不再配置basicConfig,由main.py统一配置)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Explicitly load .env from project root
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
class TushareCnClient:
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
ts.set_token(api_key)
|
||||||
|
self.pro = ts.pro_api()
|
||||||
|
self.api_key = api_key
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""Create a database connection."""
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
return conn
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DB Connection Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _map_dtype_to_sql(self, dtype):
|
||||||
|
"""Map pandas dtype to PostgreSQL type."""
|
||||||
|
if pd.api.types.is_integer_dtype(dtype):
|
||||||
|
return "BIGINT"
|
||||||
|
elif pd.api.types.is_float_dtype(dtype):
|
||||||
|
return "NUMERIC"
|
||||||
|
elif pd.api.types.is_bool_dtype(dtype):
|
||||||
|
return "BOOLEAN"
|
||||||
|
elif pd.api.types.is_datetime64_any_dtype(dtype):
|
||||||
|
return "TIMESTAMP"
|
||||||
|
else:
|
||||||
|
return "TEXT"
|
||||||
|
|
||||||
|
def _save_df_to_wide_table(self, table_name: str, df: pd.DataFrame, pk_cols: List[str]):
|
||||||
|
"""
|
||||||
|
Save DataFrame to a specific wide table.
|
||||||
|
Creates table if not exists using DF columns.
|
||||||
|
Performs incremental save: checks existing records and only inserts new ones.
|
||||||
|
"""
|
||||||
|
if df is None or df.empty:
|
||||||
|
return
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
# 1. Clean Data
|
||||||
|
df_clean = df.replace({np.nan: None})
|
||||||
|
|
||||||
|
# Convert date columns to YYYY-MM-DD format
|
||||||
|
for col in df_clean.columns:
|
||||||
|
if 'date' in col.lower() and df_clean[col].dtype == 'object':
|
||||||
|
try:
|
||||||
|
sample = df_clean[col].dropna().astype(str).iloc[0] if not df_clean[col].dropna().empty else ""
|
||||||
|
if len(sample) == 8 and sample.isdigit():
|
||||||
|
df_clean[col] = df_clean[col].astype(str).apply(
|
||||||
|
lambda x: f"{x[:4]}-{x[4:6]}-{x[6:]}" if x and len(str(x))==8 else x
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# 2. Check if table exists
|
||||||
|
cur.execute("SELECT to_regclass(%s)", (f"public.{table_name}",))
|
||||||
|
table_exists = cur.fetchone()[0] is not None
|
||||||
|
|
||||||
|
columns = list(df_clean.columns)
|
||||||
|
|
||||||
|
if not table_exists:
|
||||||
|
# Create table if not exists
|
||||||
|
logger.info(f"🆕 [数据库] 表 {table_name} 不存在,正在创建...")
|
||||||
|
col_defs = ['"id" SERIAL PRIMARY KEY']
|
||||||
|
for col in columns:
|
||||||
|
sql_type = self._map_dtype_to_sql(df_clean[col].dtype)
|
||||||
|
col_defs.append(f'"{col}" {sql_type}')
|
||||||
|
|
||||||
|
col_defs.append('"update_date" TIMESTAMP DEFAULT CURRENT_TIMESTAMP')
|
||||||
|
|
||||||
|
pk_str = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
constraint_name = f"uq_{table_name}"
|
||||||
|
create_sql = f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS {table_name} (
|
||||||
|
{', '.join(col_defs)},
|
||||||
|
CONSTRAINT {constraint_name} UNIQUE ({pk_str})
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
cur.execute(create_sql)
|
||||||
|
conn.commit()
|
||||||
|
# No existing data, insert all
|
||||||
|
df_to_insert = df_clean
|
||||||
|
else:
|
||||||
|
# 3. Incremental Logic: Filter out existing records
|
||||||
|
# We assume 'ts_code' is always in pk_cols and present in df
|
||||||
|
if 'ts_code' in df_clean.columns and 'ts_code' in pk_cols:
|
||||||
|
ts_code_val = df_clean['ts_code'].iloc[0]
|
||||||
|
|
||||||
|
# Build query to fetch existing PKs for this stock
|
||||||
|
# We only select the PK columns to minimize data transfer
|
||||||
|
pk_select = ", ".join([f'"{c}"' for c in pk_cols])
|
||||||
|
|
||||||
|
header_sql = f"SELECT {pk_select} FROM {table_name} WHERE \"ts_code\" = %s"
|
||||||
|
cur.execute(header_sql, (ts_code_val,))
|
||||||
|
existing_rows = cur.fetchall()
|
||||||
|
|
||||||
|
if existing_rows:
|
||||||
|
# Create a set of existing PK tuples for fast lookup
|
||||||
|
# Ensure types match (convert to string if necessary/consistent with df)
|
||||||
|
existing_keys = set(existing_rows)
|
||||||
|
|
||||||
|
# Filter df
|
||||||
|
# We need to construct a tuple from df rows corresponding to pk_cols
|
||||||
|
# Note: DB returns tuples in order of pk_colsQuery
|
||||||
|
|
||||||
|
def row_to_key(row):
|
||||||
|
return tuple(row[col] for col in pk_cols)
|
||||||
|
|
||||||
|
# Identify rows to keep
|
||||||
|
# This is a bit slow for very large DFs, but usually we have < 1000 rows
|
||||||
|
is_new_list = []
|
||||||
|
for _, row in df_clean.iterrows():
|
||||||
|
key = row_to_key(row)
|
||||||
|
# DB driver might return dates as datetime.date, df has strings or timestamps
|
||||||
|
# Let's try simple comparison first, if issues arise we might need normalization
|
||||||
|
# For now, assuming string matching for dates if they were converted above
|
||||||
|
is_new = key not in existing_keys
|
||||||
|
is_new_list.append(is_new)
|
||||||
|
|
||||||
|
df_to_insert = df_clean[is_new_list]
|
||||||
|
skipped_count = len(df_clean) - len(df_to_insert)
|
||||||
|
if skipped_count > 0:
|
||||||
|
logger.info(f"⏭️ [数据库] 表 {table_name}: 跳过 {skipped_count} 条已存在的数据, 准备插入 {len(df_to_insert)} 条")
|
||||||
|
else:
|
||||||
|
df_to_insert = df_clean
|
||||||
|
else:
|
||||||
|
# Fallback for tables without ts_code (rare in this context)
|
||||||
|
# Identify existing PKs? Or just try insert all with ON CONFLICT DO NOTHING
|
||||||
|
# User specifically asked for 'code and end date' logic
|
||||||
|
df_to_insert = df_clean
|
||||||
|
|
||||||
|
if df_to_insert.empty:
|
||||||
|
logger.info(f"✅ [数据库] 表 {table_name}: 所有数据已存在,无需更新。")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 4. Get existing columns from DB to ensure schema match
|
||||||
|
cur.execute("""
|
||||||
|
SELECT column_name
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = %s
|
||||||
|
""", (table_name,))
|
||||||
|
db_cols = {row[0] for row in cur.fetchall()}
|
||||||
|
|
||||||
|
# Add auto-columns (id) if missing
|
||||||
|
if 'id' not in db_cols:
|
||||||
|
try:
|
||||||
|
cur.execute(f'ALTER TABLE "{table_name}" ADD COLUMN "id" SERIAL')
|
||||||
|
conn.commit()
|
||||||
|
db_cols.add('id')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error adding id column to {table_name}: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
valid_cols = [c for c in columns if c in db_cols]
|
||||||
|
|
||||||
|
# 5. Construct INSERT statement
|
||||||
|
cols_str = ", ".join([f'"{c}"' for c in valid_cols])
|
||||||
|
vals_str = ", ".join(["%s"] * len(valid_cols))
|
||||||
|
|
||||||
|
# Since we filtered, we can use INSERT directly,
|
||||||
|
# but ON CONFLICT DO NOTHING is safer for race conditions
|
||||||
|
# The user wanted to avoid updating if exists.
|
||||||
|
|
||||||
|
insert_sql = f"""
|
||||||
|
INSERT INTO {table_name} ({cols_str})
|
||||||
|
VALUES ({vals_str})
|
||||||
|
ON CONFLICT ({", ".join([f'"{c}"' for c in pk_cols])})
|
||||||
|
DO NOTHING
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 6. Execute Batch Insert
|
||||||
|
logger.info(f"📥 [数据库] 正在保存 {len(df_to_insert)} 条新数据到 {table_name}...")
|
||||||
|
data_tuples = [tuple(x) for x in df_to_insert[valid_cols].to_numpy()]
|
||||||
|
cur.executemany(insert_sql, data_tuples)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [数据库] {table_name}: 成功插入 {len(data_tuples)} 条数据, 耗时: {elapsed:.2f}秒")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ [数据库] 保存 {table_name} 失败: {e}")
|
||||||
|
conn.rollback()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def _get_ts_code(self, symbol: str) -> str:
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
def _filter_data(self, df: pd.DataFrame) -> pd.DataFrame:
|
||||||
|
if df.empty or 'end_date' not in df.columns:
|
||||||
|
return df
|
||||||
|
df = df.sort_values(by='end_date', ascending=False)
|
||||||
|
df = df.drop_duplicates(subset=['end_date'], keep='first')
|
||||||
|
return df
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
logger.info(f"🐛 [DEBUG] get_income_statement called with symbol: '{symbol}'")
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
logger.info(f"🔍 [Tushare API] 调用 income() 获取利润表, symbol={ts_code}")
|
||||||
|
start_time = time.time()
|
||||||
|
df = self.pro.income(ts_code=ts_code)
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [Tushare API] income() 完成, 返回 {len(df)} 行, 耗时: {elapsed:.2f}秒")
|
||||||
|
|
||||||
|
# Save to DB (Wide Table)
|
||||||
|
if not df.empty and {'ts_code', 'end_date', 'report_type'}.issubset(df.columns):
|
||||||
|
self._save_df_to_wide_table('tushare_income_statement', df, ['ts_code', 'end_date', 'report_type'])
|
||||||
|
|
||||||
|
# Legacy Rename for Frontend compatibility
|
||||||
|
rename_map = {
|
||||||
|
'end_date': 'date',
|
||||||
|
'revenue': 'revenue',
|
||||||
|
'n_income_attr_p': 'net_income'
|
||||||
|
}
|
||||||
|
df_processed = self._filter_data(df)
|
||||||
|
df_processed = df_processed.rename(columns=rename_map)
|
||||||
|
|
||||||
|
return df_processed
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
logger.info(f"🔍 [Tushare API] 调用 balancesheet() 获取资产负债表, symbol={ts_code}")
|
||||||
|
start_time = time.time()
|
||||||
|
df = self.pro.balancesheet(ts_code=ts_code)
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [Tushare API] balancesheet() 完成, 返回 {len(df)} 行, 耗时: {elapsed:.2f}秒")
|
||||||
|
|
||||||
|
# Save to DB
|
||||||
|
if not df.empty and {'ts_code', 'end_date', 'report_type'}.issubset(df.columns):
|
||||||
|
self._save_df_to_wide_table('tushare_balance_sheet', df, ['ts_code', 'end_date', 'report_type'])
|
||||||
|
|
||||||
|
rename_map = {
|
||||||
|
'end_date': 'date',
|
||||||
|
'total_hldr_eqy_exc_min_int': 'total_equity',
|
||||||
|
'total_liab': 'total_liabilities',
|
||||||
|
'total_cur_assets': 'current_assets',
|
||||||
|
'total_cur_liab': 'current_liabilities'
|
||||||
|
}
|
||||||
|
df_processed = self._filter_data(df)
|
||||||
|
df_processed = df_processed.rename(columns=rename_map)
|
||||||
|
|
||||||
|
return df_processed
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
logger.info(f"🔍 [Tushare API] 调用 cashflow() 获取现金流量表, symbol={ts_code}")
|
||||||
|
start_time = time.time()
|
||||||
|
df = self.pro.cashflow(ts_code=ts_code)
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [Tushare API] cashflow() 完成, 返回 {len(df)} 行, 耗时: {elapsed:.2f}秒")
|
||||||
|
|
||||||
|
# Save to DB
|
||||||
|
if not df.empty and {'ts_code', 'end_date', 'report_type'}.issubset(df.columns):
|
||||||
|
self._save_df_to_wide_table('tushare_cash_flow', df, ['ts_code', 'end_date', 'report_type'])
|
||||||
|
|
||||||
|
df_processed = self._filter_data(df)
|
||||||
|
df_processed = df_processed.rename(columns={
|
||||||
|
'end_date': 'date',
|
||||||
|
'n_cashflow_act': 'net_cash_flow',
|
||||||
|
'depr_fa_coga_dpba': 'depreciation'
|
||||||
|
})
|
||||||
|
|
||||||
|
return df_processed
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
metrics = {
|
||||||
|
"price": 0.0,
|
||||||
|
"market_cap": 0.0,
|
||||||
|
"pe": 0.0,
|
||||||
|
"pb": 0.0,
|
||||||
|
"total_share_holders": 0,
|
||||||
|
"employee_count": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Daily Basic
|
||||||
|
df_daily = self.pro.daily_basic(ts_code=ts_code, limit=1)
|
||||||
|
if not df_daily.empty:
|
||||||
|
row = df_daily.iloc[0]
|
||||||
|
metrics["price"] = row.get('close', 0.0)
|
||||||
|
metrics["pe"] = row.get('pe', 0.0)
|
||||||
|
metrics["pb"] = row.get('pb', 0.0)
|
||||||
|
metrics["market_cap"] = row.get('total_mv', 0.0) * 10000
|
||||||
|
metrics["dividend_yield"] = row.get('dv_ttm', 0.0)
|
||||||
|
# Save to DB
|
||||||
|
if 'trade_date' in df_daily.columns:
|
||||||
|
self._save_df_to_wide_table('tushare_daily_basic', df_daily, ['ts_code', 'trade_date'])
|
||||||
|
|
||||||
|
# 2. Stock Basic
|
||||||
|
df_basic = self.pro.stock_basic(ts_code=ts_code, fields='ts_code,symbol,name,area,industry,list_date')
|
||||||
|
if not df_basic.empty:
|
||||||
|
metrics['name'] = df_basic.iloc[0]['name']
|
||||||
|
metrics['list_date'] = df_basic.iloc[0]['list_date']
|
||||||
|
# Save to DB
|
||||||
|
self._save_df_to_wide_table('tushare_stock_basic', df_basic, ['ts_code'])
|
||||||
|
|
||||||
|
# 3. Company Info
|
||||||
|
df_comp = self.pro.stock_company(ts_code=ts_code)
|
||||||
|
if not df_comp.empty:
|
||||||
|
metrics["employee_count"] = int(df_comp.iloc[0].get('employees', 0) or 0)
|
||||||
|
|
||||||
|
# 4. Shareholder Number
|
||||||
|
df_holder = self.pro.stk_holdernumber(ts_code=ts_code, limit=1)
|
||||||
|
if not df_holder.empty:
|
||||||
|
metrics["total_share_holders"] = int(df_holder.iloc[0].get('holder_num', 0) or 0)
|
||||||
|
# Save to DB.
|
||||||
|
if 'end_date' in df_holder.columns:
|
||||||
|
self._save_df_to_wide_table('tushare_stk_holdernumber', df_holder, ['ts_code', 'end_date'])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching market metrics for {symbol}: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
|
||||||
|
def get_historical_metrics(self, symbol: str, dates: list) -> pd.DataFrame:
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
results = []
|
||||||
|
|
||||||
|
if not dates:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
unique_dates = sorted(list(set([str(d).replace('-', '') for d in dates])), reverse=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
min_date = min(unique_dates)
|
||||||
|
max_date = max(unique_dates)
|
||||||
|
|
||||||
|
# Fetch and Save Daily Basic
|
||||||
|
df_daily = self.pro.daily_basic(ts_code=ts_code, start_date=min_date, end_date=max_date)
|
||||||
|
if not df_daily.empty:
|
||||||
|
self._save_df_to_wide_table('tushare_daily_basic', df_daily, ['ts_code', 'trade_date'])
|
||||||
|
df_daily = df_daily.sort_values('trade_date', ascending=False)
|
||||||
|
|
||||||
|
# Fetch and Save Shareholder Number
|
||||||
|
df_holder = self.pro.stk_holdernumber(ts_code=ts_code, start_date=min_date, end_date=max_date)
|
||||||
|
if not df_holder.empty:
|
||||||
|
self._save_df_to_wide_table('tushare_stk_holdernumber', df_holder, ['ts_code', 'end_date'])
|
||||||
|
df_holder = df_holder.sort_values('end_date', ascending=False)
|
||||||
|
|
||||||
|
# Build legacy results DataFrame for internal return
|
||||||
|
for date_str in unique_dates:
|
||||||
|
metrics = {'date': date_str}
|
||||||
|
|
||||||
|
if not df_daily.empty:
|
||||||
|
closest_daily = df_daily[df_daily['trade_date'] <= date_str]
|
||||||
|
if not closest_daily.empty:
|
||||||
|
row = closest_daily.iloc[0]
|
||||||
|
metrics['Price'] = row.get('close')
|
||||||
|
metrics['PE'] = row.get('pe')
|
||||||
|
metrics['PB'] = row.get('pb')
|
||||||
|
metrics['MarketCap'] = row.get('total_mv', 0) * 10000
|
||||||
|
|
||||||
|
if not df_holder.empty:
|
||||||
|
closest_holder = df_holder[df_holder['end_date'] <= date_str]
|
||||||
|
if not closest_holder.empty:
|
||||||
|
metrics['Shareholders'] = closest_holder.iloc[0].get('holder_num')
|
||||||
|
|
||||||
|
results.append(metrics)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching historical metrics for {symbol}: {e}")
|
||||||
|
|
||||||
|
return pd.DataFrame(results)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
import time
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
df_div = self.pro.dividend(ts_code=ts_code, fields='ts_code,end_date,ann_date,div_proc,stk_div,cash_div_tax,cash_div,record_date,ex_date,pay_date,div_listdate,imp_ann_date')
|
||||||
|
|
||||||
|
if not df_div.empty:
|
||||||
|
# Save to DB
|
||||||
|
self._save_df_to_wide_table('tushare_dividend', df_div, ['ts_code', 'end_date', 'ann_date'])
|
||||||
|
|
||||||
|
if df_div.empty:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
# Legacy processing for return
|
||||||
|
df_div = df_div[(df_div['div_proc'] == '实施') & (df_div['cash_div'] > 0)]
|
||||||
|
if df_div.empty:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df_div['total_cash_div'] = 0.0
|
||||||
|
|
||||||
|
calced_divs = []
|
||||||
|
for index, row in df_div.iterrows():
|
||||||
|
ex_date = row['ex_date']
|
||||||
|
if not ex_date or pd.isna(ex_date): continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
time.sleep(0.1)
|
||||||
|
df_daily = self.pro.daily_basic(ts_code=ts_code, trade_date=ex_date, fields='total_share')
|
||||||
|
if not df_daily.empty:
|
||||||
|
total_share = df_daily.iloc[0]['total_share']
|
||||||
|
total_cash_dividend = (row['cash_div'] * total_share * 10000)
|
||||||
|
calced_divs.append({
|
||||||
|
'year': int(str(row['end_date'])[:4]),
|
||||||
|
'dividends': total_cash_dividend
|
||||||
|
})
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
if calced_divs:
|
||||||
|
df_calc = pd.DataFrame(calced_divs)
|
||||||
|
dividends_by_year = df_calc.groupby('year')['dividends'].sum().reset_index()
|
||||||
|
dividends_by_year['date'] = dividends_by_year['year'].astype(str) + '1231'
|
||||||
|
return dividends_by_year[['date', 'dividends']]
|
||||||
|
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
ts_code = self._get_ts_code(symbol)
|
||||||
|
df = self.pro.repurchase(ts_code=ts_code)
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
if 'ann_date' in df.columns and 'end_date' in df.columns:
|
||||||
|
self._save_df_to_wide_table('tushare_repurchase', df, ['ts_code', 'ann_date', 'end_date'])
|
||||||
|
|
||||||
|
if df.empty or 'ann_date' not in df.columns or 'amount' not in df.columns:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
# Legacy processing
|
||||||
|
df = df[df['amount'] > 0]
|
||||||
|
if df.empty: return pd.DataFrame()
|
||||||
|
|
||||||
|
df['year'] = pd.to_datetime(df['ann_date']).dt.year
|
||||||
|
repurchases_by_year = df.groupby('year')['amount'].sum().reset_index()
|
||||||
|
repurchases_by_year['date_str'] = repurchases_by_year['year'].astype(str) + '1231'
|
||||||
|
repurchases_by_year.rename(columns={'amount': 'repurchases', 'date_str': 'date'}, inplace=True)
|
||||||
|
|
||||||
|
return repurchases_by_year[['date', 'repurchases']]
|
||||||
@ -1,47 +1,33 @@
|
|||||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
"""
|
||||||
from sqlalchemy import text
|
数据库连接配置 (新架构)
|
||||||
from app.models import Base
|
使用 AsyncSession 支持异步操作
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
|
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./stock_analysis.db")
|
# 数据库连接 URL
|
||||||
|
DATABASE_URL = f"postgresql+asyncpg://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL, echo=True)
|
# 创建异步引擎
|
||||||
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
|
engine = create_async_engine(
|
||||||
|
DATABASE_URL,
|
||||||
|
echo=False, # 设置为 True 可以看到 SQL 日志
|
||||||
|
future=True
|
||||||
|
)
|
||||||
|
|
||||||
async def init_db():
|
# 创建异步 Session 工厂
|
||||||
async with engine.begin() as conn:
|
SessionLocal = async_sessionmaker(
|
||||||
await conn.run_sync(Base.metadata.create_all)
|
engine,
|
||||||
|
class_=AsyncSession,
|
||||||
# Migration: Add ai_model column if it doesn't exist (for SQLite)
|
expire_on_commit=False
|
||||||
try:
|
)
|
||||||
await conn.execute(
|
|
||||||
text("ALTER TABLE reports ADD COLUMN ai_model VARCHAR(100) DEFAULT 'gemini-2.0-flash-exp'")
|
|
||||||
)
|
|
||||||
print("Migration: Added ai_model column to reports table")
|
|
||||||
except Exception as e:
|
|
||||||
# Column already exists or other error
|
|
||||||
if "duplicate column" not in str(e).lower() and "already exists" not in str(e).lower():
|
|
||||||
print(f"Migration check: {e}")
|
|
||||||
|
|
||||||
# Migration: Add token columns to report_sections
|
|
||||||
columns_to_add = [
|
|
||||||
("prompt_tokens", "INTEGER DEFAULT 0"),
|
|
||||||
("completion_tokens", "INTEGER DEFAULT 0"),
|
|
||||||
("total_tokens", "INTEGER DEFAULT 0")
|
|
||||||
]
|
|
||||||
|
|
||||||
for col_name, col_type in columns_to_add:
|
|
||||||
try:
|
|
||||||
await conn.execute(text(f"ALTER TABLE report_sections ADD COLUMN {col_name} {col_type}"))
|
|
||||||
print(f"Migration: Added {col_name} to report_sections table")
|
|
||||||
except Exception as e:
|
|
||||||
# SQLite error for duplicate column usually contains "duplicate column name"
|
|
||||||
if "duplicate column" not in str(e).lower() and "already exists" not in str(e).lower():
|
|
||||||
print(f"Migration check for {col_name}: {e}")
|
|
||||||
|
|
||||||
|
# Dependency
|
||||||
async def get_db():
|
async def get_db():
|
||||||
async with AsyncSessionLocal() as session:
|
"""获取数据库会话"""
|
||||||
|
async with SessionLocal() as session:
|
||||||
yield session
|
yield session
|
||||||
|
|||||||
3
backend/app/fetchers/__init__.py
Normal file
3
backend/app/fetchers/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Fetchers package initialization
|
||||||
|
"""
|
||||||
41
backend/app/fetchers/base.py
Normal file
41
backend/app/fetchers/base.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
Base Fetcher class
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
class DataFetcher(ABC):
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
self.api_key = api_key
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_historical_metrics(self, symbol: str, dates: list) -> pd.DataFrame:
|
||||||
|
"""Optional method, not all fetchers need to implement"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""Optional method"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""Optional method"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""Optional method"""
|
||||||
|
return pd.DataFrame()
|
||||||
145
backend/app/fetchers/bloomberg_fetcher.py
Normal file
145
backend/app/fetchers/bloomberg_fetcher.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import psycopg2
|
||||||
|
from .base import DataFetcher
|
||||||
|
from app.clients.bloomberg_client import BloombergClient
|
||||||
|
|
||||||
|
class BloombergFetcher(DataFetcher):
|
||||||
|
"""
|
||||||
|
Bloomberg Data Fetcher.
|
||||||
|
Fetches data via BloombergClient (Remote Jupyter) into 'stockcard' table.
|
||||||
|
Reads 'stockcard' table to provide standard DataFrames.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str = None, market: str = "US"):
|
||||||
|
super().__init__(api_key) # api_key unused for Bloomberg usually (password based)
|
||||||
|
self.market = market
|
||||||
|
self.client = BloombergClient() # Uses env vars
|
||||||
|
self._fetched_symbols = set() # Track symbols we've already fetched
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""Create a database connection."""
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
return conn
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DB Connection Error: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_company_code(self, symbol: str) -> str:
|
||||||
|
# Match logic in Client
|
||||||
|
if "Equity" in symbol:
|
||||||
|
return symbol
|
||||||
|
return f"{symbol} {self.market} Equity"
|
||||||
|
|
||||||
|
def _get_data_from_db(self, symbol: str, indicators: list) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Query 'stockcard' for specific indicators and return pivoted DataFrame.
|
||||||
|
"""
|
||||||
|
company_code = self._get_company_code(symbol)
|
||||||
|
conn = self._get_db_connection()
|
||||||
|
if not conn: return pd.DataFrame()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# placeholders for 'IN' clause
|
||||||
|
placeholders = ','.join(['%s'] * len(indicators))
|
||||||
|
query = f"""
|
||||||
|
SELECT indicator, value, value_date
|
||||||
|
FROM stockcard
|
||||||
|
WHERE Company_code = %s AND indicator IN ({placeholders})
|
||||||
|
ORDER BY value_date DESC
|
||||||
|
"""
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(query, (company_code, *indicators))
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
df = pd.DataFrame(rows, columns=['indicator', 'value', 'value_date'])
|
||||||
|
|
||||||
|
# Pivot
|
||||||
|
# Index: value_date
|
||||||
|
# Columns: indicator
|
||||||
|
# Values: value
|
||||||
|
df_pivot = df.pivot(index='value_date', columns='indicator', values='value').reset_index()
|
||||||
|
df_pivot.rename(columns={'value_date': 'end_date'}, inplace=True)
|
||||||
|
|
||||||
|
# Clean columns? No, they are standard from config.
|
||||||
|
return df_pivot
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error querying stockcard: {e}")
|
||||||
|
return pd.DataFrame()
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def _ensure_data_fetched(self, symbol: str, progress_callback=None):
|
||||||
|
"""
|
||||||
|
Trigger fetch if needed. Only fetch once per symbol per instance.
|
||||||
|
"""
|
||||||
|
if symbol in self._fetched_symbols:
|
||||||
|
return # Already fetched for this symbol
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check if fetch_company supports progress_callback
|
||||||
|
import inspect
|
||||||
|
sig = inspect.signature(self.client.fetch_company)
|
||||||
|
if 'progress_callback' in sig.parameters:
|
||||||
|
self.client.fetch_company(self.market, symbol, progress_callback=progress_callback)
|
||||||
|
else:
|
||||||
|
self.client.fetch_company(self.market, symbol)
|
||||||
|
|
||||||
|
self._fetched_symbols.add(symbol)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Bloomberg fetch failed (ignoring, checking DB): {e}")
|
||||||
|
|
||||||
|
def sync_all_data(self, symbol: str, progress_callback=None) -> None:
|
||||||
|
"""
|
||||||
|
全量同步 Bloomberg 数据
|
||||||
|
|
||||||
|
触发一次全量抓取即可,不需要分别抓取各个报表。
|
||||||
|
数据会自动存储到数据库。
|
||||||
|
"""
|
||||||
|
self._ensure_data_fetched(symbol, progress_callback=progress_callback)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
def get_financial_ratios(self, symbol: str) -> pd.DataFrame:
|
||||||
|
"""兼容性空方法"""
|
||||||
|
return pd.DataFrame()
|
||||||
41
backend/app/fetchers/cn_fetcher.py
Normal file
41
backend/app/fetchers/cn_fetcher.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
CN (China) Market Data Fetcher
|
||||||
|
"""
|
||||||
|
import pandas as pd
|
||||||
|
from .base import DataFetcher
|
||||||
|
|
||||||
|
class CnFetcher(DataFetcher):
|
||||||
|
def __init__(self, api_key: str, data_source: str = 'Tushare'):
|
||||||
|
super().__init__(api_key)
|
||||||
|
self.data_source = data_source
|
||||||
|
|
||||||
|
if self.data_source == 'Tushare':
|
||||||
|
from app.clients.tushare_cn_client import TushareCnClient
|
||||||
|
self.client = TushareCnClient(api_key)
|
||||||
|
else:
|
||||||
|
# Default to Tushare
|
||||||
|
if self.data_source == 'Akshare':
|
||||||
|
raise NotImplementedError("Akshare client not yet implemented")
|
||||||
|
from app.clients.tushare_cn_client import TushareCnClient
|
||||||
|
self.client = TushareCnClient(api_key)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
return self.client.get_income_statement(symbol)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
return self.client.get_balance_sheet(symbol)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
return self.client.get_cash_flow(symbol)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
return self.client.get_market_metrics(symbol)
|
||||||
|
|
||||||
|
def get_historical_metrics(self, symbol: str, dates: list) -> pd.DataFrame:
|
||||||
|
return self.client.get_historical_metrics(symbol, dates)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
return self.client.get_dividends(symbol)
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
return self.client.get_repurchases(symbol)
|
||||||
106
backend/app/fetchers/factory.py
Normal file
106
backend/app/fetchers/factory.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
"""
|
||||||
|
Fetcher Factory - Backend Version
|
||||||
|
Currently supports CN market with Tushare
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class FetcherFactory:
|
||||||
|
"""
|
||||||
|
数据获取工厂类 (Backend版本)
|
||||||
|
|
||||||
|
当前支持的数据源:
|
||||||
|
- Tushare: CN (中国A股)
|
||||||
|
- iFinD: HK, JP, US, VN
|
||||||
|
- Bloomberg: CN, HK, JP, US, VN
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_fetcher(market: str, data_source: str = None, **kwargs):
|
||||||
|
"""
|
||||||
|
获取对应市场和数据源的 Fetcher
|
||||||
|
|
||||||
|
Args:
|
||||||
|
market: 市场代码 (CN, HK, JP, US, VN)
|
||||||
|
data_source: 数据源名称 (iFinD, Tushare, Bloomberg)
|
||||||
|
**kwargs: 额外参数(如 API tokens)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Fetcher 实例
|
||||||
|
"""
|
||||||
|
market = market.upper()
|
||||||
|
|
||||||
|
# 如果未指定数据源,使用默认值
|
||||||
|
if not data_source:
|
||||||
|
data_source = FetcherFactory._get_default_source(market)
|
||||||
|
|
||||||
|
elif data_source == 'iFinD':
|
||||||
|
return FetcherFactory._get_ifind_fetcher(market, **kwargs)
|
||||||
|
elif data_source == 'Bloomberg':
|
||||||
|
return FetcherFactory._get_bloomberg_fetcher(market, **kwargs)
|
||||||
|
else:
|
||||||
|
# 其他数据源暂未迁移
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"Data source '{data_source}' not supported in backend."
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_default_source(market: str) -> str:
|
||||||
|
"""获取市场的默认数据源"""
|
||||||
|
defaults = {
|
||||||
|
'CN': 'Tushare',
|
||||||
|
'HK': 'iFinD',
|
||||||
|
'JP': 'iFinD',
|
||||||
|
'US': 'iFinD',
|
||||||
|
'VN': 'iFinD'
|
||||||
|
}
|
||||||
|
return defaults.get(market, 'iFinD')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_tushare_fetcher(market: str, **kwargs):
|
||||||
|
"""获取 Tushare Fetcher"""
|
||||||
|
if market != 'CN':
|
||||||
|
raise ValueError("Tushare only supports CN market")
|
||||||
|
|
||||||
|
# 获取 Tushare token
|
||||||
|
tushare_token = kwargs.get('tushare_token') or os.getenv('TUSHARE_TOKEN')
|
||||||
|
|
||||||
|
if not tushare_token:
|
||||||
|
raise ValueError("Tushare token is required for CN market")
|
||||||
|
|
||||||
|
from app.fetchers.cn_fetcher import CnFetcher
|
||||||
|
return CnFetcher(tushare_token)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_ifind_fetcher(market: str, **kwargs):
|
||||||
|
"""Get iFinD Fetcher"""
|
||||||
|
ifind_token = kwargs.get('ifind_token') or os.getenv('IFIND_REFRESH_TOKEN')
|
||||||
|
if not ifind_token:
|
||||||
|
# Try legacy env var name if needed, but IFIND_REFRESH_TOKEN is standard
|
||||||
|
ifind_token = os.getenv('IFIND_REFRESH_TOKEN')
|
||||||
|
|
||||||
|
if not ifind_token:
|
||||||
|
raise ValueError("iFinD refresh token is required (IFIND_REFRESH_TOKEN)")
|
||||||
|
|
||||||
|
if market == 'HK':
|
||||||
|
from app.fetchers.hk_fetcher import HkFetcher
|
||||||
|
return HkFetcher(ifind_token)
|
||||||
|
elif market == 'JP':
|
||||||
|
from app.fetchers.jp_fetcher import JpFetcher
|
||||||
|
return JpFetcher(ifind_token)
|
||||||
|
elif market == 'VN':
|
||||||
|
from app.fetchers.vn_fetcher import VnFetcher
|
||||||
|
return VnFetcher(ifind_token)
|
||||||
|
elif market == 'US':
|
||||||
|
from app.fetchers.us_fetcher import UsFetcher
|
||||||
|
return UsFetcher(ifind_token)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"iFinD fetcher for market {market} not yet migrated to backend.")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_bloomberg_fetcher(market: str, **kwargs):
|
||||||
|
"""Get Bloomberg Fetcher"""
|
||||||
|
# Bloomberg client typically uses internal auth (password based) or default keys.
|
||||||
|
# We can pass kwargs but default init handles env vars.
|
||||||
|
from app.fetchers.bloomberg_fetcher import BloombergFetcher
|
||||||
|
return BloombergFetcher(market=market)
|
||||||
49
backend/app/fetchers/hk_fetcher.py
Normal file
49
backend/app/fetchers/hk_fetcher.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from .base import DataFetcher
|
||||||
|
from app.clients.ifind_hk_client import IFindHKClient
|
||||||
|
|
||||||
|
class HkFetcher(DataFetcher):
|
||||||
|
"""
|
||||||
|
Hong Kong Market Fetcher using iFinD.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
super().__init__(api_key)
|
||||||
|
self.data_source = 'iFinD'
|
||||||
|
self.client = IFindHKClient(api_key)
|
||||||
|
|
||||||
|
def _get_ifind_code(self, symbol: str) -> str:
|
||||||
|
# HK stock codes are 4-5 digits, often 0 padded to 5 or 4 in other systems
|
||||||
|
# iFinD usually expects 4 digits like '0700.HK', '0005.HK'
|
||||||
|
if symbol.isdigit():
|
||||||
|
padded = symbol.zfill(4)
|
||||||
|
return f"{padded}.HK"
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str):
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client._fetch_basic_info(symbol, code)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_income_statement(symbol, code)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_balance_sheet(symbol, code)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_cash_flow(symbol, code)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_market_metrics(symbol, code)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_dividends(symbol, code)
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_repurchases(symbol, code)
|
||||||
56
backend/app/fetchers/jp_fetcher.py
Normal file
56
backend/app/fetchers/jp_fetcher.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from .base import DataFetcher
|
||||||
|
from app.clients.ifind_int_client import IFindIntClient
|
||||||
|
|
||||||
|
class JpFetcher(DataFetcher):
|
||||||
|
"""
|
||||||
|
Japan Market Fetcher using iFinD International Client.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
super().__init__(api_key)
|
||||||
|
self.data_source = 'iFinD'
|
||||||
|
self.client = IFindIntClient(api_key, 'JP')
|
||||||
|
|
||||||
|
def _get_ifind_code(self, symbol: str) -> str:
|
||||||
|
# Simple logic: if pure digits, append .T (Tokyo SE).
|
||||||
|
# Otherwise assume it's already a code or handled.
|
||||||
|
if symbol.isdigit():
|
||||||
|
return f"{symbol}.T"
|
||||||
|
return symbol
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str):
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client._fetch_basic_info(symbol, code)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_income_statement(symbol, code)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_balance_sheet(symbol, code)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_cash_flow(symbol, code)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_market_metrics(symbol, code)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_dividends(symbol, code)
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_repurchases(symbol, code)
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_employee_count(symbol, code)
|
||||||
|
|
||||||
|
def get_financial_ratios(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_financial_ratios(symbol, code)
|
||||||
58
backend/app/fetchers/us_fetcher.py
Normal file
58
backend/app/fetchers/us_fetcher.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from .base import DataFetcher
|
||||||
|
from app.clients.ifind_int_client import IFindIntClient
|
||||||
|
# Note: UsFetcher typically used AlphaVantage in legacy, but Factory defaults 'US' to 'iFinD' now.
|
||||||
|
# Implementation plan says "US market supported by iFinD International Client".
|
||||||
|
|
||||||
|
class UsFetcher(DataFetcher):
|
||||||
|
"""
|
||||||
|
US Market Fetcher using iFinD International Client.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
super().__init__(api_key)
|
||||||
|
self.data_source = 'iFinD'
|
||||||
|
self.client = IFindIntClient(api_key, 'US')
|
||||||
|
|
||||||
|
def _get_ifind_code(self, symbol: str) -> str:
|
||||||
|
# US symbols usually just ticker, maybe suffix .N or .O
|
||||||
|
# Legacy system often handled this or client handled it.
|
||||||
|
# iFinD US symbols often need no suffix if unique, or specific exchange suffix.
|
||||||
|
# Let's assume input is correct for now or just upper.
|
||||||
|
return symbol.upper()
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str):
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client._fetch_basic_info(symbol, code)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_income_statement(symbol, code)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_balance_sheet(symbol, code)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_cash_flow(symbol, code)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_market_metrics(symbol, code)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_dividends(symbol, code)
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_repurchases(symbol, code)
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_employee_count(symbol, code)
|
||||||
|
|
||||||
|
def get_financial_ratios(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_financial_ratios(symbol, code)
|
||||||
57
backend/app/fetchers/vn_fetcher.py
Normal file
57
backend/app/fetchers/vn_fetcher.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from .base import DataFetcher
|
||||||
|
from app.clients.ifind_int_client import IFindIntClient
|
||||||
|
|
||||||
|
class VnFetcher(DataFetcher):
|
||||||
|
"""
|
||||||
|
Vietnam Market Fetcher using iFinD International Client.
|
||||||
|
"""
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
super().__init__(api_key)
|
||||||
|
self.data_source = 'iFinD'
|
||||||
|
self.client = IFindIntClient(api_key, 'VN')
|
||||||
|
|
||||||
|
def _get_ifind_code(self, symbol: str) -> str:
|
||||||
|
# Vietnam symbols are usually just uppercase tickers like 'VIC'
|
||||||
|
# iFinD might need a suffix like .VN or .HO depending on exchange
|
||||||
|
# Legacy VnFetcher didn't append suffix, assumes user provides full or iFinD smart match
|
||||||
|
# But wait, let's checking legacy code might be safer.
|
||||||
|
# Assuming simple uppercase for now as per previous knowledge.
|
||||||
|
return symbol.upper()
|
||||||
|
|
||||||
|
def _fetch_basic_info(self, symbol: str):
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client._fetch_basic_info(symbol, code)
|
||||||
|
|
||||||
|
def get_income_statement(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_income_statement(symbol, code)
|
||||||
|
|
||||||
|
def get_balance_sheet(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_balance_sheet(symbol, code)
|
||||||
|
|
||||||
|
def get_cash_flow(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_cash_flow(symbol, code)
|
||||||
|
|
||||||
|
def get_market_metrics(self, symbol: str) -> dict:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_market_metrics(symbol, code)
|
||||||
|
|
||||||
|
def get_dividends(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_dividends(symbol, code)
|
||||||
|
|
||||||
|
def get_repurchases(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_repurchases(symbol, code)
|
||||||
|
|
||||||
|
def get_employee_count(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_employee_count(symbol, code)
|
||||||
|
|
||||||
|
def get_financial_ratios(self, symbol: str) -> pd.DataFrame:
|
||||||
|
code = self._get_ifind_code(symbol)
|
||||||
|
return self.client.get_financial_ratios(symbol, code)
|
||||||
1
backend/app/legacy/__init__.py
Normal file
1
backend/app/legacy/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Legacy module for backward compatibility"""
|
||||||
68
backend/app/legacy/database_old.py
Normal file
68
backend/app/legacy/database_old.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
"""
|
||||||
|
DEPRECATED: This file is deprecated and will be removed in future versions.
|
||||||
|
|
||||||
|
This module uses SQLite and the old database schema.
|
||||||
|
Please use `database.py` for the new PostgreSQL-based architecture.
|
||||||
|
|
||||||
|
Migration path:
|
||||||
|
- Old: SQLite + CSV files + HTML reports
|
||||||
|
- New: PostgreSQL + JSON API + Frontend rendering
|
||||||
|
|
||||||
|
See QUICKSTART.md for usage of the new architecture.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||||
|
from sqlalchemy import text
|
||||||
|
from app.models import Base
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
# Issue deprecation warning
|
||||||
|
warnings.warn(
|
||||||
|
"database_old.py is deprecated. Use database.py for the new architecture.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./stock_analysis.db")
|
||||||
|
|
||||||
|
engine = create_async_engine(DATABASE_URL, echo=True)
|
||||||
|
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
async def init_db():
|
||||||
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
|
||||||
|
# Migration: Add ai_model column if it doesn't exist (for SQLite)
|
||||||
|
try:
|
||||||
|
await conn.execute(
|
||||||
|
text("ALTER TABLE reports ADD COLUMN ai_model VARCHAR(100) DEFAULT 'gemini-2.0-flash-exp'")
|
||||||
|
)
|
||||||
|
print("Migration: Added ai_model column to reports table")
|
||||||
|
except Exception as e:
|
||||||
|
# Column already exists or other error
|
||||||
|
if "duplicate column" not in str(e).lower() and "already exists" not in str(e).lower():
|
||||||
|
print(f"Migration check: {e}")
|
||||||
|
|
||||||
|
# Migration: Add token columns to report_sections
|
||||||
|
columns_to_add = [
|
||||||
|
("prompt_tokens", "INTEGER DEFAULT 0"),
|
||||||
|
("completion_tokens", "INTEGER DEFAULT 0"),
|
||||||
|
("total_tokens", "INTEGER DEFAULT 0")
|
||||||
|
]
|
||||||
|
|
||||||
|
for col_name, col_type in columns_to_add:
|
||||||
|
try:
|
||||||
|
await conn.execute(text(f"ALTER TABLE report_sections ADD COLUMN {col_name} {col_type}"))
|
||||||
|
print(f"Migration: Added {col_name} to report_sections table")
|
||||||
|
except Exception as e:
|
||||||
|
# SQLite error for duplicate column usually contains "duplicate column name"
|
||||||
|
if "duplicate column" not in str(e).lower() and "already exists" not in str(e).lower():
|
||||||
|
print(f"Migration check for {col_name}: {e}")
|
||||||
|
|
||||||
|
async def get_db():
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
yield session
|
||||||
61
backend/app/legacy/models_old.py
Normal file
61
backend/app/legacy/models_old.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""
|
||||||
|
DEPRECATED: This file is deprecated. Use models.py instead.
|
||||||
|
|
||||||
|
This module contains the old SQLite-based ORM models.
|
||||||
|
The new architecture uses PostgreSQL with updated models in models.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum
|
||||||
|
from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
import enum
|
||||||
|
import datetime
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"models_old.py is deprecated. Use models.py for the new architecture.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AnalysisStatus(str, enum.Enum):
|
||||||
|
PENDING = "pending"
|
||||||
|
IN_PROGRESS = "in_progress"
|
||||||
|
COMPLETED = "completed"
|
||||||
|
FAILED = "failed"
|
||||||
|
|
||||||
|
class Report(Base):
|
||||||
|
__tablename__ = "reports"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
||||||
|
market: Mapped[str] = mapped_column(String(10), index=True)
|
||||||
|
symbol: Mapped[str] = mapped_column(String(20), index=True)
|
||||||
|
company_name: Mapped[str] = mapped_column(String(200))
|
||||||
|
status: Mapped[AnalysisStatus] = mapped_column(Enum(AnalysisStatus), default=AnalysisStatus.PENDING)
|
||||||
|
ai_model: Mapped[str] = mapped_column(String(100), nullable=True, default="gemini-2.0-flash")
|
||||||
|
created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
||||||
|
sections: Mapped[list["ReportSection"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
class ReportSection(Base):
|
||||||
|
__tablename__ = "report_sections"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
||||||
|
report_id: Mapped[int] = mapped_column(ForeignKey("reports.id"))
|
||||||
|
section_name: Mapped[str] = mapped_column(String(50)) # e.g. company_profile, fundamental_analysis
|
||||||
|
content: Mapped[str] = mapped_column(Text) # Markdown content
|
||||||
|
total_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
||||||
|
prompt_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
||||||
|
completion_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
||||||
|
created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
||||||
|
report: Mapped["Report"] = relationship(back_populates="sections")
|
||||||
|
|
||||||
|
class Setting(Base):
|
||||||
|
__tablename__ = "settings"
|
||||||
|
|
||||||
|
key: Mapped[str] = mapped_column(String(50), primary_key=True)
|
||||||
|
value: Mapped[str] = mapped_column(Text)
|
||||||
57
backend/app/legacy/schemas.py
Normal file
57
backend/app/legacy/schemas.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"""
|
||||||
|
Legacy Schemas - 用于向后兼容
|
||||||
|
|
||||||
|
这些是旧架构的 Pydantic 模型,仅用于 legacy API routes。
|
||||||
|
新代码请使用 schemas.py 中的模型。
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import Optional, List
|
||||||
|
from datetime import datetime
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class AnalysisStatus(str, Enum):
|
||||||
|
PENDING = "pending"
|
||||||
|
IN_PROGRESS = "in_progress"
|
||||||
|
COMPLETED = "completed"
|
||||||
|
FAILED = "failed"
|
||||||
|
|
||||||
|
class StockSearchRequest(BaseModel):
|
||||||
|
query: str
|
||||||
|
|
||||||
|
class StockSearchResponse(BaseModel):
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
company_name: str
|
||||||
|
|
||||||
|
class AnalysisRequest(BaseModel):
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
company_name: str
|
||||||
|
model: Optional[str] = None
|
||||||
|
data_source: Optional[str] = None
|
||||||
|
|
||||||
|
class ReportSectionSchema(BaseModel):
|
||||||
|
section_name: str
|
||||||
|
content: str
|
||||||
|
created_at: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
class ReportResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
company_name: str
|
||||||
|
status: AnalysisStatus
|
||||||
|
ai_model: Optional[str] = None
|
||||||
|
created_at: datetime
|
||||||
|
sections: List[ReportSectionSchema] = []
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
class ConfigUpdateRequest(BaseModel):
|
||||||
|
key: str
|
||||||
|
value: str
|
||||||
@ -1,27 +1,47 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from app.api import routes
|
|
||||||
import os
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from app.database import init_db
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 配置日志系统 - 在最开始配置,确保所有模块都能使用
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.StreamHandler(sys.stdout),
|
||||||
|
logging.FileHandler("server.log", encoding='utf-8')
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure 'src' directory is in python path for 'storage' module imports
|
||||||
|
# This is required because fetchers use 'from storage.file_io import ...'
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
SRC_DIR = ROOT_DIR / "src"
|
||||||
|
if str(SRC_DIR) not in sys.path:
|
||||||
|
sys.path.insert(0, str(SRC_DIR))
|
||||||
|
|
||||||
|
# 导入新路由
|
||||||
|
from app.api import data_routes, analysis_routes
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
# Initialize DB on startup
|
# 新架构使用 AsyncSession,不需要显式初始化
|
||||||
await init_db()
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
app = FastAPI(title="Stock Analysis API", lifespan=lifespan)
|
app = FastAPI(
|
||||||
|
title="FA3 Stock Analysis API",
|
||||||
|
version="2.0.0",
|
||||||
|
description="架构重构后的股票分析 API",
|
||||||
|
lifespan=lifespan
|
||||||
|
)
|
||||||
|
|
||||||
# Configure CORS
|
# Configure CORS
|
||||||
origins = [
|
|
||||||
"http://localhost:3000",
|
|
||||||
"http://127.0.0.1:3000",
|
|
||||||
]
|
|
||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=["*"], # For development convenience
|
allow_origins=["*"], # For development convenience
|
||||||
@ -30,8 +50,186 @@ app.add_middleware(
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
app.include_router(routes.router, prefix="/api")
|
# 挂载新的 API 路由
|
||||||
|
app.include_router(data_routes.router, prefix="/api")
|
||||||
|
app.include_router(analysis_routes.router, prefix="/api")
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
def read_root():
|
def read_root():
|
||||||
return {"status": "ok", "message": "Stock Analysis API is running"}
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"message": "FA3 Stock Analysis API v2.0",
|
||||||
|
"architecture": "refactored",
|
||||||
|
"endpoints": {
|
||||||
|
"data": "/api/data/*",
|
||||||
|
"analysis": "/api/analysis/*",
|
||||||
|
"config": "/api/config"
|
||||||
|
},
|
||||||
|
"docs": "/docs"
|
||||||
|
}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health_check():
|
||||||
|
return {
|
||||||
|
"status": "healthy",
|
||||||
|
"database": "fa3",
|
||||||
|
"version": "2.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 配置端点
|
||||||
|
from fastapi import Request, Depends
|
||||||
|
from app.database import get_db
|
||||||
|
from app.models import Setting
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy import select
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class ConfigUpdateRequest(BaseModel):
|
||||||
|
key: str
|
||||||
|
value: str
|
||||||
|
|
||||||
|
@app.get("/api/config")
|
||||||
|
async def get_config_compat(db: AsyncSession = Depends(get_db)):
|
||||||
|
"""获取配置(从 PostgreSQL)"""
|
||||||
|
try:
|
||||||
|
result = await db.execute(select(Setting))
|
||||||
|
settings = result.scalars().all()
|
||||||
|
if settings:
|
||||||
|
return {setting.key: setting.value for setting in settings}
|
||||||
|
# 返回默认配置
|
||||||
|
return {
|
||||||
|
"ai_model": "gemini-2.0-flash",
|
||||||
|
"data_source_cn": "Tushare",
|
||||||
|
"data_source_hk": "iFinD",
|
||||||
|
"data_source_us": "iFinD",
|
||||||
|
"data_source_jp": "iFinD",
|
||||||
|
"data_source_vn": "iFinD"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
# 如果表不存在,返回默认配置
|
||||||
|
print(f"Config read error (using defaults): {e}")
|
||||||
|
return {
|
||||||
|
"ai_model": "gemini-2.0-flash",
|
||||||
|
"data_source_cn": "Tushare",
|
||||||
|
"data_source_hk": "iFinD",
|
||||||
|
"data_source_us": "iFinD",
|
||||||
|
"data_source_jp": "iFinD",
|
||||||
|
"data_source_vn": "iFinD"
|
||||||
|
}
|
||||||
|
|
||||||
|
@app.post("/api/config")
|
||||||
|
async def update_config_compat(
|
||||||
|
request: ConfigUpdateRequest,
|
||||||
|
db: AsyncSession = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""更新配置(到 PostgreSQL)"""
|
||||||
|
try:
|
||||||
|
result = await db.execute(
|
||||||
|
select(Setting).where(Setting.key == request.key)
|
||||||
|
)
|
||||||
|
setting = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if setting:
|
||||||
|
setting.value = request.value
|
||||||
|
else:
|
||||||
|
setting = Setting(key=request.key, value=request.value)
|
||||||
|
db.add(setting)
|
||||||
|
|
||||||
|
await db.commit()
|
||||||
|
return {"status": "ok", "key": request.key, "value": request.value}
|
||||||
|
except Exception as e:
|
||||||
|
# 如果数据库操作失败,至少返回成功状态(配置会保存在前端)
|
||||||
|
print(f"Config update error: {e}")
|
||||||
|
return {"status": "ok", "key": request.key, "value": request.value, "note": "saved in memory only"}
|
||||||
|
|
||||||
|
# 搜索端点
|
||||||
|
from app.services.analysis_service import get_genai_client
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class StockSearchRequest(BaseModel):
|
||||||
|
query: str
|
||||||
|
model: str = "gemini-2.0-flash" # 支持前端传入模型参数
|
||||||
|
|
||||||
|
class StockSearchResponse(BaseModel):
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
company_name: str
|
||||||
|
|
||||||
|
@app.post("/api/search", response_model=list[StockSearchResponse])
|
||||||
|
async def search_stock(request: StockSearchRequest):
|
||||||
|
"""使用 AI 搜索股票"""
|
||||||
|
logger.info(f"🔍 [搜索] 开始搜索股票: {request.query}")
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
try:
|
||||||
|
from google.genai import types
|
||||||
|
client = get_genai_client()
|
||||||
|
|
||||||
|
prompt = f"""请利用Google搜索查找 "{request.query}" 对应的上市股票信息。
|
||||||
|
|
||||||
|
返回最匹配的股票,优先返回准确匹配的公司。
|
||||||
|
|
||||||
|
返回格式必须是 JSON 数组,每个元素包含:
|
||||||
|
- market: 市场代码(CH/HK/US/JP/VN),例如:腾讯是 HK,茅台是 CH,英伟达是 US。
|
||||||
|
- symbol: 股票代码(如果是CH,通常是6位数字;HK是5位;US是字母)。
|
||||||
|
- company_name: 公司简称。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
[{{"market": "HK", "symbol": "00700", "company_name": "腾讯控股"}}]
|
||||||
|
|
||||||
|
请直接返回 JSON,不要添加任何其他文字。最多返回5个结果。"""
|
||||||
|
|
||||||
|
# 启用 Google Search Grounding
|
||||||
|
grounding_tool = types.Tool(google_search=types.GoogleSearch())
|
||||||
|
|
||||||
|
# 使用请求中的模型,默认为 gemini-2.5-flash
|
||||||
|
model_name = request.model or "gemini-2.5-flash"
|
||||||
|
|
||||||
|
logger.info(f"🤖 [搜索-LLM] 调用 {model_name} 进行股票搜索")
|
||||||
|
llm_start = time.time()
|
||||||
|
|
||||||
|
response = client.models.generate_content(
|
||||||
|
model=model_name,
|
||||||
|
contents=prompt,
|
||||||
|
config=types.GenerateContentConfig(
|
||||||
|
tools=[grounding_tool],
|
||||||
|
temperature=0.1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
llm_elapsed = time.time() - llm_start
|
||||||
|
usage = response.usage_metadata
|
||||||
|
prompt_tokens = usage.prompt_token_count if usage else 0
|
||||||
|
completion_tokens = usage.candidates_token_count if usage else 0
|
||||||
|
total_tokens = prompt_tokens + completion_tokens
|
||||||
|
|
||||||
|
logger.info(f"✅ [搜索-LLM] 模型响应完成, 耗时: {llm_elapsed:.2f}秒, Tokens: prompt={prompt_tokens}, completion={completion_tokens}, total={total_tokens}")
|
||||||
|
|
||||||
|
# 解析响应
|
||||||
|
text = response.text.strip()
|
||||||
|
# 移除可能的 markdown 代码块标记
|
||||||
|
if text.startswith("```json"):
|
||||||
|
text = text[7:]
|
||||||
|
if text.startswith("```"):
|
||||||
|
text = text[3:]
|
||||||
|
if text.endswith("```"):
|
||||||
|
text = text[:-3]
|
||||||
|
text = text.strip()
|
||||||
|
|
||||||
|
results = json.loads(text)
|
||||||
|
|
||||||
|
total_elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [搜索] 搜索完成, 找到 {len(results)} 个结果, 总耗时: {total_elapsed:.2f}秒")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.error(f"❌ [搜索] 搜索失败: {e}, 耗时: {elapsed:.2f}秒")
|
||||||
|
print(f"Search error: {e}")
|
||||||
|
# 返回空结果而不是错误,避免前端崩溃
|
||||||
|
return []
|
||||||
|
|||||||
@ -1,47 +1,121 @@
|
|||||||
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum
|
"""
|
||||||
from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
SQLAlchemy Models for FA3 Refactored Architecture
|
||||||
|
新架构的数据库 ORM 模型
|
||||||
|
"""
|
||||||
|
from sqlalchemy import Column, Integer, String, Text, TIMESTAMP, Boolean, JSON, ForeignKey
|
||||||
|
from sqlalchemy.orm import declarative_base, relationship
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
import enum
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
Base = declarative_base()
|
||||||
pass
|
|
||||||
|
|
||||||
class AnalysisStatus(str, enum.Enum):
|
class Company(Base):
|
||||||
PENDING = "pending"
|
"""公司元数据表"""
|
||||||
IN_PROGRESS = "in_progress"
|
__tablename__ = 'companies'
|
||||||
COMPLETED = "completed"
|
|
||||||
FAILED = "failed"
|
|
||||||
|
|
||||||
class Report(Base):
|
id = Column(Integer, primary_key=True)
|
||||||
__tablename__ = "reports"
|
market = Column(String(10), nullable=False)
|
||||||
|
symbol = Column(String(50), nullable=False)
|
||||||
|
company_name = Column(String(255), nullable=False)
|
||||||
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
# 关系
|
||||||
market: Mapped[str] = mapped_column(String(10), index=True)
|
data_updates = relationship("DataUpdate", back_populates="company", cascade="all, delete-orphan")
|
||||||
symbol: Mapped[str] = mapped_column(String(20), index=True)
|
ai_analyses = relationship("AIAnalysis", back_populates="company", cascade="all, delete-orphan")
|
||||||
company_name: Mapped[str] = mapped_column(String(200))
|
data_source_availability = relationship("DataSourceAvailability", back_populates="company", cascade="all, delete-orphan")
|
||||||
status: Mapped[AnalysisStatus] = mapped_column(Enum(AnalysisStatus), default=AnalysisStatus.PENDING)
|
|
||||||
ai_model: Mapped[str] = mapped_column(String(100), nullable=True, default="gemini-2.0-flash")
|
|
||||||
created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
||||||
|
|
||||||
sections: Mapped[list["ReportSection"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
def __repr__(self):
|
||||||
|
return f"<Company(id={self.id}, market={self.market}, symbol={self.symbol}, name={self.company_name})>"
|
||||||
|
|
||||||
class ReportSection(Base):
|
|
||||||
__tablename__ = "report_sections"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
class DataUpdate(Base):
|
||||||
report_id: Mapped[int] = mapped_column(ForeignKey("reports.id"))
|
"""数据更新记录表"""
|
||||||
section_name: Mapped[str] = mapped_column(String(50)) # e.g. company_profile, fundamental_analysis
|
__tablename__ = 'data_updates'
|
||||||
content: Mapped[str] = mapped_column(Text) # Markdown content
|
|
||||||
total_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
id = Column(Integer, primary_key=True)
|
||||||
prompt_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False)
|
||||||
completion_tokens: Mapped[int] = mapped_column(Integer, nullable=True, default=0)
|
data_source = Column(String(50), nullable=False)
|
||||||
created_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
update_type = Column(String(50), nullable=False)
|
||||||
|
status = Column(String(20), nullable=False)
|
||||||
|
started_at = Column(TIMESTAMP, server_default=func.now())
|
||||||
|
completed_at = Column(TIMESTAMP, nullable=True)
|
||||||
|
error_message = Column(Text, nullable=True)
|
||||||
|
|
||||||
|
# 数据覆盖范围
|
||||||
|
data_start_date = Column(String(8), nullable=True)
|
||||||
|
data_end_date = Column(String(8), nullable=True)
|
||||||
|
|
||||||
|
# 元数据 (JSONB)
|
||||||
|
fetched_tables = Column(JSON, nullable=True)
|
||||||
|
row_counts = Column(JSON, nullable=True)
|
||||||
|
|
||||||
|
# 进度跟踪
|
||||||
|
progress_message = Column(String(255), nullable=True)
|
||||||
|
progress_percentage = Column(Integer, default=0)
|
||||||
|
|
||||||
|
# 关系
|
||||||
|
company = relationship("Company", back_populates="data_updates")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<DataUpdate(id={self.id}, company_id={self.company_id}, source={self.data_source}, status={self.status})>"
|
||||||
|
|
||||||
|
|
||||||
|
class AIAnalysis(Base):
|
||||||
|
"""AI 分析报告表"""
|
||||||
|
__tablename__ = 'ai_analyses'
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False)
|
||||||
|
data_source = Column(String(50), nullable=False)
|
||||||
|
ai_model = Column(String(100), nullable=False)
|
||||||
|
status = Column(String(20), nullable=False)
|
||||||
|
|
||||||
|
# 分析内容 (Markdown 格式)
|
||||||
|
company_profile = Column(Text, nullable=True)
|
||||||
|
fundamental_analysis = Column(Text, nullable=True)
|
||||||
|
insider_analysis = Column(Text, nullable=True)
|
||||||
|
bullish_analysis = Column(Text, nullable=True)
|
||||||
|
bearish_analysis = Column(Text, nullable=True)
|
||||||
|
|
||||||
|
# Token 使用情况
|
||||||
|
total_tokens = Column(Integer, default=0)
|
||||||
|
tokens_by_section = Column(JSON, nullable=True)
|
||||||
|
|
||||||
|
created_at = Column(TIMESTAMP, server_default=func.now())
|
||||||
|
completed_at = Column(TIMESTAMP, nullable=True)
|
||||||
|
error_message = Column(Text, nullable=True)
|
||||||
|
|
||||||
|
# 关系
|
||||||
|
company = relationship("Company", back_populates="ai_analyses")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<AIAnalysis(id={self.id}, company_id={self.company_id}, source={self.data_source}, status={self.status})>"
|
||||||
|
|
||||||
|
|
||||||
|
class DataSourceAvailability(Base):
|
||||||
|
"""数据源可用性表"""
|
||||||
|
__tablename__ = 'data_source_availability'
|
||||||
|
|
||||||
|
company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), primary_key=True)
|
||||||
|
data_source = Column(String(50), primary_key=True)
|
||||||
|
has_data = Column(Boolean, default=False)
|
||||||
|
last_update = Column(TIMESTAMP, nullable=True)
|
||||||
|
row_count = Column(Integer, default=0)
|
||||||
|
|
||||||
|
# 关系
|
||||||
|
company = relationship("Company", back_populates="data_source_availability")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<DataSourceAvailability(company_id={self.company_id}, source={self.data_source}, has_data={self.has_data})>"
|
||||||
|
|
||||||
report: Mapped["Report"] = relationship(back_populates="sections")
|
|
||||||
|
|
||||||
class Setting(Base):
|
class Setting(Base):
|
||||||
__tablename__ = "settings"
|
"""系统配置表"""
|
||||||
|
__tablename__ = 'settings'
|
||||||
|
|
||||||
key: Mapped[str] = mapped_column(String(50), primary_key=True)
|
key = Column(String(100), primary_key=True)
|
||||||
value: Mapped[str] = mapped_column(Text)
|
value = Column(Text, nullable=False)
|
||||||
|
updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<Setting(key={self.key}, value={self.value[:50]})>"
|
||||||
|
|||||||
@ -1,50 +1,178 @@
|
|||||||
from pydantic import BaseModel
|
"""
|
||||||
from typing import Optional, List
|
Pydantic Schemas for FA3 Refactored Architecture
|
||||||
|
API 请求和响应的数据模型
|
||||||
|
"""
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Optional, Dict, List
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
class AnalysisStatus(str, Enum):
|
# =============================================================================
|
||||||
PENDING = "pending"
|
# Company Schemas
|
||||||
IN_PROGRESS = "in_progress"
|
# =============================================================================
|
||||||
COMPLETED = "completed"
|
class CompanyBase(BaseModel):
|
||||||
FAILED = "failed"
|
|
||||||
|
|
||||||
class StockSearchRequest(BaseModel):
|
|
||||||
query: str
|
|
||||||
|
|
||||||
class StockSearchResponse(BaseModel):
|
|
||||||
market: str
|
market: str
|
||||||
symbol: str
|
symbol: str
|
||||||
company_name: str
|
company_name: str
|
||||||
|
|
||||||
class AnalysisRequest(BaseModel):
|
class CompanyCreate(CompanyBase):
|
||||||
market: str
|
pass
|
||||||
symbol: str
|
|
||||||
company_name: str
|
|
||||||
model: Optional[str] = None
|
|
||||||
data_source: Optional[str] = None
|
|
||||||
|
|
||||||
class ReportSectionSchema(BaseModel):
|
class CompanyResponse(CompanyBase):
|
||||||
section_name: str
|
|
||||||
content: str
|
|
||||||
created_at: datetime
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
from_attributes = True
|
|
||||||
|
|
||||||
class ReportResponse(BaseModel):
|
|
||||||
id: int
|
id: int
|
||||||
market: str
|
|
||||||
symbol: str
|
|
||||||
company_name: str
|
|
||||||
status: AnalysisStatus
|
|
||||||
ai_model: Optional[str] = None
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
sections: List[ReportSectionSchema] = []
|
updated_at: datetime
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Data Check & Fetch Schemas
|
||||||
|
# =============================================================================
|
||||||
|
class DataCheckRequest(BaseModel):
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
data_source: str
|
||||||
|
|
||||||
|
class DataCheckResponse(BaseModel):
|
||||||
|
has_data: bool
|
||||||
|
company_id: Optional[int] = None
|
||||||
|
data_source: str
|
||||||
|
last_update: Optional[Dict] = None
|
||||||
|
message: Optional[str] = None
|
||||||
|
|
||||||
|
class FetchDataRequest(BaseModel):
|
||||||
|
market: str
|
||||||
|
symbol: str
|
||||||
|
company_name: str
|
||||||
|
data_source: str
|
||||||
|
force_refresh: bool = False
|
||||||
|
|
||||||
|
class FetchDataResponse(BaseModel):
|
||||||
|
update_id: int
|
||||||
|
data_source: str
|
||||||
|
status: str
|
||||||
|
message: str
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Data Update Schemas
|
||||||
|
# =============================================================================
|
||||||
|
class DataUpdateBase(BaseModel):
|
||||||
|
company_id: int
|
||||||
|
data_source: str
|
||||||
|
update_type: str
|
||||||
|
status: str
|
||||||
|
|
||||||
|
class DataUpdateCreate(DataUpdateBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DataUpdateResponse(DataUpdateBase):
|
||||||
|
id: int
|
||||||
|
started_at: datetime
|
||||||
|
completed_at: Optional[datetime] = None
|
||||||
|
error_message: Optional[str] = None
|
||||||
|
data_start_date: Optional[str] = None
|
||||||
|
data_end_date: Optional[str] = None
|
||||||
|
fetched_tables: Optional[List[str]] = None
|
||||||
|
row_counts: Optional[Dict[str, int]] = None
|
||||||
|
progress_message: Optional[str] = None
|
||||||
|
progress_percentage: Optional[int] = 0
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Financial Data Schemas
|
||||||
|
# =============================================================================
|
||||||
|
class FinancialDataResponse(BaseModel):
|
||||||
|
company: CompanyResponse
|
||||||
|
data_source: str
|
||||||
|
income_statement: List[Dict]
|
||||||
|
balance_sheet: List[Dict]
|
||||||
|
cash_flow: List[Dict]
|
||||||
|
daily_basic: List[Dict]
|
||||||
|
dividend: Optional[List[Dict]] = None
|
||||||
|
repurchase: Optional[List[Dict]] = None
|
||||||
|
employee: Optional[List[Dict]] = None
|
||||||
|
unified_data: Optional[List[Dict]] = None
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# AI Analysis Schemas
|
||||||
|
# =============================================================================
|
||||||
|
class AnalysisStartRequest(BaseModel):
|
||||||
|
company_id: int
|
||||||
|
data_source: str
|
||||||
|
model: Optional[str] = "gemini-2.0-flash"
|
||||||
|
|
||||||
|
class AnalysisStartResponse(BaseModel):
|
||||||
|
analysis_id: int
|
||||||
|
company_id: int
|
||||||
|
data_source: str
|
||||||
|
status: str
|
||||||
|
message: str
|
||||||
|
|
||||||
|
class AnalysisStatusResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
company_id: int
|
||||||
|
data_source: str
|
||||||
|
ai_model: str
|
||||||
|
status: str
|
||||||
|
created_at: datetime
|
||||||
|
completed_at: Optional[datetime] = None
|
||||||
|
error_message: Optional[str] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
class AnalysisResultResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
company_id: int
|
||||||
|
data_source: str
|
||||||
|
ai_model: str
|
||||||
|
status: str
|
||||||
|
company_profile: Optional[str] = None
|
||||||
|
fundamental_analysis: Optional[str] = None
|
||||||
|
insider_analysis: Optional[str] = None
|
||||||
|
bullish_analysis: Optional[str] = None
|
||||||
|
bearish_analysis: Optional[str] = None
|
||||||
|
total_tokens: int
|
||||||
|
tokens_by_section: Optional[Dict[str, int]] = None
|
||||||
|
created_at: datetime
|
||||||
|
completed_at: Optional[datetime] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Data Source Schemas
|
||||||
|
# =============================================================================
|
||||||
|
class DataSourceInfo(BaseModel):
|
||||||
|
source: str
|
||||||
|
available: bool
|
||||||
|
description: str
|
||||||
|
supported_markets: List[str]
|
||||||
|
|
||||||
|
class DataSourceListResponse(BaseModel):
|
||||||
|
market: str
|
||||||
|
sources: List[DataSourceInfo]
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Configuration Schemas
|
||||||
|
# =============================================================================
|
||||||
class ConfigUpdateRequest(BaseModel):
|
class ConfigUpdateRequest(BaseModel):
|
||||||
key: str
|
key: str
|
||||||
value: str
|
value: str
|
||||||
|
|
||||||
|
class ConfigResponse(BaseModel):
|
||||||
|
key: str
|
||||||
|
value: str
|
||||||
|
updated_at: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
|
|||||||
@ -1,185 +1,195 @@
|
|||||||
import sys
|
"""
|
||||||
|
LLM 分析服务 (新架构)
|
||||||
|
负责调用 LLM 生成分析报告
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import subprocess
|
from typing import Dict, Optional
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from app.models import Report, ReportSection, AnalysisStatus
|
from sqlalchemy import select
|
||||||
from app.services import llm_engine
|
from google import genai
|
||||||
from datetime import datetime
|
|
||||||
import google.genai as genai
|
|
||||||
from google.genai import types
|
from google.genai import types
|
||||||
|
|
||||||
async def search_stock(query: str, api_key: str, model: str = "gemini-2.0-flash"):
|
from app.models import Company
|
||||||
|
from app.services.data_fetcher_service import get_financial_data_from_db
|
||||||
|
|
||||||
|
# Gemini client(懒加载)
|
||||||
|
_client: Optional[genai.Client] = None
|
||||||
|
|
||||||
|
def get_genai_client() -> genai.Client:
|
||||||
|
"""获取 Gemini API 客户端(单例)"""
|
||||||
|
global _client
|
||||||
|
if _client is None:
|
||||||
|
api_key = os.getenv('GEMINI_API_KEY')
|
||||||
if not api_key:
|
if not api_key:
|
||||||
return {"error": "API Key not provided"}
|
raise ValueError("GEMINI_API_KEY environment variable is not set")
|
||||||
|
_client = genai.Client(api_key=api_key)
|
||||||
|
return _client
|
||||||
|
|
||||||
client = genai.Client(api_key=api_key)
|
|
||||||
prompt = f"""
|
|
||||||
你是一个专业的股票代码查询助手。请识别公司 '{query}' 的股票市场和代码。
|
|
||||||
|
|
||||||
**重要提示**:
|
async def run_llm_analysis(
|
||||||
1. 用户输入可能是公司全称、简称、别名或股票代码
|
company_id: int,
|
||||||
2. 请仔细匹配,优先完全匹配,避免返回不相关的公司
|
data_source: str,
|
||||||
3. 中国公司的简称经常省略"股份有限公司"等后缀
|
model: str,
|
||||||
4. 例如:"茅台" = "贵州茅台酒股份有限公司" (600519.SH)
|
db: AsyncSession
|
||||||
|
) -> Dict:
|
||||||
请返回一个 JSON 数组,包含所有匹配的公司。每个对象包含以下字段:
|
|
||||||
- 'market': 'CN' (中国), 'US' (美国), 'HK' (香港), 'JP' (日本), 或 'VN' (越南) 之一
|
|
||||||
- 'symbol': 完整的股票代码 (例如 'AAPL', '600519.SH', '00700.HK', '688778.SH', '2503.T', 'SAB.HM')
|
|
||||||
- 'company_name': 公司的中文简称(如果有的话,优先使用中文;如果只有英文名,则使用英文名)
|
|
||||||
|
|
||||||
**匹配规则**:
|
|
||||||
- 如果查询词与某公司简称、全称或股票代码完全匹配,返回该公司
|
|
||||||
- 如果有多个可能的匹配,返回所有相关公司
|
|
||||||
- 如果公司在中国但用户没有指定市场,默认为 CN(上海/深圳/北京交易所)
|
|
||||||
- **越南股票后缀规则(iFinD数据源)**:
|
|
||||||
- 胡志明交易所 (HOSE) -> 后缀 **.HM** (例如: VNM.HM, SAB.HM, VCB.HM)
|
|
||||||
- 河内交易所 (HNX) -> 后缀 **.HN** (例如: PVS.HN, SHS.HN)
|
|
||||||
- UPCoM 市场 -> iFinD 通常也使用 .HN 或 .HM,或者特定的 UPCoM 后缀,但绝不要使用 .VN (这是 Bloomberg 格式)
|
|
||||||
- 示例:MCH (Masan Consumer) -> MCH.HN 或 MCH.HM (UPCoM 在 iFinD 中可能归类不一,但 MCH.HN 是常见尝试,MCH.HM 也可以尝试。请根据搜索结果确认 iFinD 使用哪一个。**强烈倾向于使用 .HM 或 .HN,严禁使用 .VN**)
|
|
||||||
- MCH 具体案例:用户指出应为 MCH.HM (或 MCH.HN),绝非 MCH.VN。请只返回 .HM 或 .HN。
|
|
||||||
- 如果不确定是 HM 还是 HN,优先返回 .HM。
|
|
||||||
- 如果完全没找到匹配,返回 {{ "error": "未找到相关公司" }}
|
|
||||||
|
|
||||||
示例响应(单个结果):
|
|
||||||
[
|
|
||||||
{{
|
|
||||||
"market": "CN",
|
|
||||||
"symbol": "600519.SH",
|
|
||||||
"company_name": "贵州茅台"
|
|
||||||
}}
|
|
||||||
]
|
|
||||||
|
|
||||||
示例响应(多个结果):
|
|
||||||
[
|
|
||||||
{{
|
|
||||||
"market": "HK",
|
|
||||||
"symbol": "00700.HK",
|
|
||||||
"company_name": "腾讯控股"
|
|
||||||
}},
|
|
||||||
{{
|
|
||||||
"market": "VN",
|
|
||||||
"symbol": "VNM.HM",
|
|
||||||
"company_name": "Vinamilk"
|
|
||||||
}}
|
|
||||||
]
|
|
||||||
|
|
||||||
现在请处理查询: '{query}'
|
|
||||||
"""
|
"""
|
||||||
|
执行 LLM 分析
|
||||||
|
|
||||||
|
Args:
|
||||||
|
company_id: 公司ID
|
||||||
|
data_source: 数据源
|
||||||
|
model: LLM 模型名称
|
||||||
|
db: 数据库会话
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含所有分析内容和 token 使用情况的字典
|
||||||
|
"""
|
||||||
|
# 1. 获取公司信息
|
||||||
|
result = await db.execute(
|
||||||
|
select(Company).where(Company.id == company_id)
|
||||||
|
)
|
||||||
|
company = result.scalar_one()
|
||||||
|
|
||||||
|
# 2. 获取财务数据
|
||||||
|
financial_data = await get_financial_data_from_db(
|
||||||
|
company_id=company_id,
|
||||||
|
data_source=data_source,
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 准备数据上下文
|
||||||
|
context = format_financial_data_for_llm(financial_data)
|
||||||
|
|
||||||
|
# 4. 调用 LLM 生成各个部分
|
||||||
|
sections = {}
|
||||||
|
total_tokens = 0
|
||||||
|
tokens_by_section = {}
|
||||||
|
|
||||||
|
# 公司简介
|
||||||
|
profile_result = await generate_section(
|
||||||
|
model=model,
|
||||||
|
company=company,
|
||||||
|
section_name='company_profile',
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
sections['company_profile'] = profile_result['content']
|
||||||
|
tokens_by_section['company_profile'] = profile_result['tokens']
|
||||||
|
total_tokens += profile_result['tokens']
|
||||||
|
|
||||||
|
# 基本面分析
|
||||||
|
fundamental_result = await generate_section(
|
||||||
|
model=model,
|
||||||
|
company=company,
|
||||||
|
section_name='fundamental_analysis',
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
sections['fundamental_analysis'] = fundamental_result['content']
|
||||||
|
tokens_by_section['fundamental_analysis'] = fundamental_result['tokens']
|
||||||
|
total_tokens += fundamental_result['tokens']
|
||||||
|
|
||||||
|
# 内部人士分析
|
||||||
|
insider_result = await generate_section(
|
||||||
|
model=model,
|
||||||
|
company=company,
|
||||||
|
section_name='insider_analysis',
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
sections['insider_analysis'] = insider_result['content']
|
||||||
|
tokens_by_section['insider_analysis'] = insider_result['tokens']
|
||||||
|
total_tokens += insider_result['tokens']
|
||||||
|
|
||||||
|
# 看涨分析
|
||||||
|
bullish_result = await generate_section(
|
||||||
|
model=model,
|
||||||
|
company=company,
|
||||||
|
section_name='bullish_analysis',
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
sections['bullish_analysis'] = bullish_result['content']
|
||||||
|
tokens_by_section['bullish_analysis'] = bullish_result['tokens']
|
||||||
|
total_tokens += bullish_result['tokens']
|
||||||
|
|
||||||
|
# 看跌分析
|
||||||
|
bearish_result = await generate_section(
|
||||||
|
model=model,
|
||||||
|
company=company,
|
||||||
|
section_name='bearish_analysis',
|
||||||
|
context=context
|
||||||
|
)
|
||||||
|
sections['bearish_analysis'] = bearish_result['content']
|
||||||
|
tokens_by_section['bearish_analysis'] = bearish_result['tokens']
|
||||||
|
total_tokens += bearish_result['tokens']
|
||||||
|
|
||||||
|
return {
|
||||||
|
**sections,
|
||||||
|
'total_tokens': total_tokens,
|
||||||
|
'tokens_by_section': tokens_by_section
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def format_financial_data_for_llm(financial_data: Dict) -> str:
|
||||||
|
"""将财务数据格式化为 LLM 上下文"""
|
||||||
|
# 简化版本,实际应该更详细地格式化数据
|
||||||
|
context = f"""
|
||||||
|
公司: {financial_data['company']['company_name']}
|
||||||
|
市场: {financial_data['company']['market']}
|
||||||
|
代码: {financial_data['company']['symbol']}
|
||||||
|
数据源: {financial_data['data_source']}
|
||||||
|
|
||||||
|
财务数据:
|
||||||
|
- 利润表记录数: {len(financial_data.get('income_statement', []))}
|
||||||
|
- 资产负债表记录数: {len(financial_data.get('balance_sheet', []))}
|
||||||
|
- 现金流量表记录数: {len(financial_data.get('cash_flow', []))}
|
||||||
|
- 估值数据记录数: {len(financial_data.get('daily_basic', []))}
|
||||||
|
"""
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_section(
|
||||||
|
model: str,
|
||||||
|
company: Company,
|
||||||
|
section_name: str,
|
||||||
|
context: str
|
||||||
|
) -> Dict:
|
||||||
|
"""
|
||||||
|
生成报告的一个部分
|
||||||
|
"""
|
||||||
|
# 设置 prompt
|
||||||
|
prompts = {
|
||||||
|
'company_profile': f"请为 {company.company_name} ({company.symbol}) 生成公司简介,包括主营业务、市场地位等。\n\n财务数据:\n{context}",
|
||||||
|
'fundamental_analysis': f"请为 {company.company_name} 进行基本面分析,包括财务指标、盈利能力、成长性等。\n\n财务数据:\n{context}",
|
||||||
|
'insider_analysis': f"请分析 {company.company_name} 的内部人士交易情况、股权结构等。\n\n财务数据:\n{context}",
|
||||||
|
'bullish_analysis': f"请分析 {company.company_name} 的看涨因素和投资亮点。\n\n财务数据:\n{context}",
|
||||||
|
'bearish_analysis': f"请分析 {company.company_name} 的风险因素和潜在问题。\n\n财务数据:\n{context}"
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt = prompts.get(section_name, f"请分析 {company.company_name}。\n\n{context}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Enable Google Search for more accurate results
|
# 获取 Gemini client
|
||||||
grounding_tool = types.Tool(google_search=types.GoogleSearch())
|
client = get_genai_client()
|
||||||
# Note: Cannot use response_mime_type with tools
|
|
||||||
config = types.GenerateContentConfig(tools=[grounding_tool])
|
|
||||||
|
|
||||||
|
# 调用新的 genai API
|
||||||
response = client.models.generate_content(
|
response = client.models.generate_content(
|
||||||
model=model,
|
model=model,
|
||||||
contents=prompt,
|
contents=prompt
|
||||||
config=config
|
|
||||||
)
|
)
|
||||||
|
|
||||||
response_text = response.text.strip()
|
# 提取内容和 token 信息
|
||||||
print(f"Search API raw response: {response_text[:500]}")
|
content = response.text
|
||||||
|
|
||||||
# Extract JSON from response (may be wrapped in markdown code blocks)
|
# 获取 token 使用情况(新 API 的方式)
|
||||||
if "```json" in response_text:
|
tokens = 0
|
||||||
# Extract JSON from code block
|
if hasattr(response, 'usage_metadata'):
|
||||||
start = response_text.find("```json") + 7
|
tokens = response.usage_metadata.total_token_count
|
||||||
end = response_text.find("```", start)
|
|
||||||
json_str = response_text[start:end].strip()
|
|
||||||
elif "```" in response_text:
|
|
||||||
# Extract from generic code block
|
|
||||||
start = response_text.find("```") + 3
|
|
||||||
end = response_text.find("```", start)
|
|
||||||
json_str = response_text[start:end].strip()
|
|
||||||
else:
|
|
||||||
json_str = response_text
|
|
||||||
|
|
||||||
result = json.loads(json_str)
|
return {
|
||||||
|
'content': content,
|
||||||
# Ensure result is always an array for consistent handling
|
'tokens': tokens
|
||||||
if not isinstance(result, list):
|
}
|
||||||
if isinstance(result, dict) and "error" in result:
|
|
||||||
return result # Return error as-is
|
|
||||||
result = [result] # Wrap single object in array
|
|
||||||
|
|
||||||
return result
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"JSON decode error: {e}, Response text: {response_text}")
|
|
||||||
return {"error": f"无法解析搜索结果: {str(e)}"}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Search error: {e}")
|
# 如果 LLM 调用失败,返回错误信息
|
||||||
return {"error": f"搜索失败: {str(e)}"}
|
return {
|
||||||
|
'content': f"分析生成失败: {str(e)}",
|
||||||
async def run_analysis_task(report_id: int, market: str, symbol: str, api_key: str, data_source: str = None):
|
'tokens': 0
|
||||||
"""
|
}
|
||||||
Background task to run the full analysis pipeline.
|
|
||||||
Creates its own DB session.
|
|
||||||
"""
|
|
||||||
print(f"Starting analysis for report {report_id}: {market} {symbol} (Source: {data_source})")
|
|
||||||
|
|
||||||
# Create new session
|
|
||||||
from app.database import AsyncSessionLocal
|
|
||||||
|
|
||||||
async with AsyncSessionLocal() as session:
|
|
||||||
try:
|
|
||||||
report = await session.get(Report, report_id)
|
|
||||||
if not report:
|
|
||||||
print(f"Report {report_id} not found in background task")
|
|
||||||
return
|
|
||||||
|
|
||||||
report.status = AnalysisStatus.IN_PROGRESS
|
|
||||||
await session.commit()
|
|
||||||
|
|
||||||
company_name_for_prompt = report.company_name
|
|
||||||
|
|
||||||
# 2. Run Main Data Fetching Script (run_fetcher.py)
|
|
||||||
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../"))
|
|
||||||
cmd = [sys.executable, "run_fetcher.py", market, symbol]
|
|
||||||
if data_source:
|
|
||||||
cmd.extend(["--data-source", data_source])
|
|
||||||
|
|
||||||
print(f"Executing data fetch command: {cmd} in {root_dir}")
|
|
||||||
process = await asyncio.create_subprocess_exec(
|
|
||||||
*cmd,
|
|
||||||
cwd=root_dir,
|
|
||||||
stdout=asyncio.subprocess.PIPE,
|
|
||||||
stderr=asyncio.subprocess.PIPE
|
|
||||||
)
|
|
||||||
stdout, stderr = await process.communicate()
|
|
||||||
|
|
||||||
if process.returncode != 0:
|
|
||||||
error_msg = stderr.decode()
|
|
||||||
print(f"Data fetch failed: {error_msg}")
|
|
||||||
report.status = AnalysisStatus.FAILED
|
|
||||||
await session.commit()
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Data fetch successful.")
|
|
||||||
|
|
||||||
# 3. Perform Analysis Logic
|
|
||||||
await llm_engine.process_analysis_steps(
|
|
||||||
report_id=report_id,
|
|
||||||
company_name=company_name_for_prompt,
|
|
||||||
symbol=symbol,
|
|
||||||
market=market,
|
|
||||||
db=session,
|
|
||||||
api_key=api_key
|
|
||||||
)
|
|
||||||
|
|
||||||
# 4. Finalize
|
|
||||||
report.status = AnalysisStatus.COMPLETED
|
|
||||||
await session.commit()
|
|
||||||
print(f"Analysis for report {report_id} completed.")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Analysis task exception: {e}")
|
|
||||||
try:
|
|
||||||
report = await session.get(Report, report_id)
|
|
||||||
if report:
|
|
||||||
report.status = AnalysisStatus.FAILED
|
|
||||||
await session.commit()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|||||||
108
backend/app/services/bloomberg_service.py
Normal file
108
backend/app/services/bloomberg_service.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
"""
|
||||||
|
Bloomberg 数据服务
|
||||||
|
|
||||||
|
负责处理 Bloomberg 特有的数据读取逻辑
|
||||||
|
从 stockcard 表中提取数据并转换为统一格式
|
||||||
|
"""
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy import text
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from app.models import Company
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
async def get_bloomberg_data(
|
||||||
|
company: Company,
|
||||||
|
db: AsyncSession
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
获取指定公司的 Bloomberg 财务数据
|
||||||
|
|
||||||
|
Args:
|
||||||
|
company: 公司对象
|
||||||
|
db: 数据库会话
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Dict]: 统一格式的财务数据列表
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 1. 查找对应的 Company_code
|
||||||
|
# stockcard 中存储的是 "AAPL US Equity" 而 symbol 是 "AAPL"
|
||||||
|
target_code = None
|
||||||
|
|
||||||
|
# 优先尝试最可能的后缀
|
||||||
|
suffixes = [" US Equity", " HK Equity", " JP Equity", " CH Equity", " VN Equity"]
|
||||||
|
possible_codes = [f"{company.symbol}{s}" for s in suffixes]
|
||||||
|
|
||||||
|
# 检查哪个存在
|
||||||
|
for code in possible_codes:
|
||||||
|
check_sql = text("SELECT 1 FROM stockcard WHERE Company_code = :code LIMIT 1")
|
||||||
|
exists = await db.execute(check_sql, {"code": code})
|
||||||
|
if exists.scalar():
|
||||||
|
target_code = code
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果没找到,尝试模糊匹配 (作为兜底)
|
||||||
|
if not target_code:
|
||||||
|
fuzzy_sql = text("SELECT Company_code FROM stockcard WHERE Company_code LIKE :symbol LIMIT 1")
|
||||||
|
fuzzy_res = await db.execute(fuzzy_sql, {"symbol": f"%{company.symbol}%"})
|
||||||
|
row = fuzzy_res.fetchone()
|
||||||
|
if row:
|
||||||
|
target_code = row[0]
|
||||||
|
|
||||||
|
if not target_code:
|
||||||
|
logger.warning(f"No Bloomberg data found for symbol: {company.symbol}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 2. 获取该公司的所有数据
|
||||||
|
# schema: indicator, value, value_date (作为报告期)
|
||||||
|
query = text("""
|
||||||
|
SELECT indicator, value, value_date, currency
|
||||||
|
FROM stockcard
|
||||||
|
WHERE Company_code = :code
|
||||||
|
""")
|
||||||
|
result = await db.execute(query, {"code": target_code})
|
||||||
|
|
||||||
|
# 3. 数据透视 (Pivot)
|
||||||
|
data_by_date = {}
|
||||||
|
|
||||||
|
for row in result:
|
||||||
|
indicator = row.indicator
|
||||||
|
val = row.value
|
||||||
|
v_date = row.value_date
|
||||||
|
curr = row.currency
|
||||||
|
|
||||||
|
if not v_date:
|
||||||
|
continue
|
||||||
|
|
||||||
|
date_str = v_date.isoformat() if hasattr(v_date, 'isoformat') else str(v_date)
|
||||||
|
|
||||||
|
if date_str not in data_by_date:
|
||||||
|
data_by_date[date_str] = {
|
||||||
|
"end_date": date_str,
|
||||||
|
"currency": curr
|
||||||
|
}
|
||||||
|
elif data_by_date[date_str].get("currency") is None and curr:
|
||||||
|
# If existing entry has no currency, but we have one now, update it
|
||||||
|
data_by_date[date_str]["currency"] = curr
|
||||||
|
|
||||||
|
# Normalize key to match frontend expectation (mostly lowercase)
|
||||||
|
# e.g. "ROE" -> "roe", "PE" -> "pe"
|
||||||
|
norm_indicator = indicator.lower()
|
||||||
|
|
||||||
|
# Special case mapping if needed, but lowercase covers most
|
||||||
|
# frontend uses: net_income, revenue, etc.
|
||||||
|
|
||||||
|
data_by_date[date_str][norm_indicator] = val
|
||||||
|
|
||||||
|
# 4. 转换为列表并排序
|
||||||
|
full_list = list(data_by_date.values())
|
||||||
|
full_list.sort(key=lambda x: x['end_date'], reverse=True)
|
||||||
|
|
||||||
|
return full_list
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error fetching Bloomberg data from stockcard: {e}", exc_info=True)
|
||||||
|
return []
|
||||||
528
backend/app/services/data_fetcher_service.py
Normal file
528
backend/app/services/data_fetcher_service.py
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
"""
|
||||||
|
数据获取服务层
|
||||||
|
负责从不同数据源获取财务数据并存储到数据库
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
import pandas as pd
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy import select, and_, text
|
||||||
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
|
from app.models import Company, DataUpdate, DataSourceAvailability
|
||||||
|
from app.schemas import DataCheckResponse, FetchDataRequest
|
||||||
|
from app.fetchers.factory import FetcherFactory
|
||||||
|
from app.services.bloomberg_service import get_bloomberg_data
|
||||||
|
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def update_progress_sync(update_id: int, message: str, percentage: int):
|
||||||
|
"""同步更新数据获取进度 - 使用psycopg2直连避免event loop冲突"""
|
||||||
|
import psycopg2
|
||||||
|
import os
|
||||||
|
|
||||||
|
logger.info(f"🔄 [进度更新] ID={update_id}, Msg={message}, Progress={percentage}%")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=os.getenv('DB_HOST', '192.168.3.195'),
|
||||||
|
user=os.getenv('DB_USER', 'value'),
|
||||||
|
password=os.getenv('DB_PASSWORD', 'Value609!'),
|
||||||
|
dbname=os.getenv('DB_NAME', 'fa3'),
|
||||||
|
port=os.getenv('DB_PORT', '5432')
|
||||||
|
)
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
UPDATE data_updates
|
||||||
|
SET progress_message = %s, progress_percentage = %s
|
||||||
|
WHERE id = %s
|
||||||
|
""",
|
||||||
|
(message, percentage, update_id)
|
||||||
|
)
|
||||||
|
if cur.rowcount == 0:
|
||||||
|
logger.warning(f"⚠️ [进度更新] ID={update_id} 未找到记录!")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ [进度更新失败] ID={update_id}: {e}", exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def check_data_status(
|
||||||
|
market: str,
|
||||||
|
symbol: str,
|
||||||
|
data_source: str,
|
||||||
|
db: AsyncSession
|
||||||
|
) -> DataCheckResponse:
|
||||||
|
"""
|
||||||
|
检查指定公司和数据源的数据状态
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
DataCheckResponse: 包含数据状态信息
|
||||||
|
"""
|
||||||
|
# 1. 查询或创建公司记录
|
||||||
|
result = await db.execute(
|
||||||
|
select(Company).where(
|
||||||
|
and_(Company.market == market, Company.symbol == symbol)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
company = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not company:
|
||||||
|
# 没有找到公司记录
|
||||||
|
return DataCheckResponse(
|
||||||
|
has_data=False,
|
||||||
|
company_id=None,
|
||||||
|
data_source=data_source,
|
||||||
|
message=f"该数据源暂无该公司数据"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2. 查询最近一次成功的数据更新
|
||||||
|
result = await db.execute(
|
||||||
|
select(DataUpdate)
|
||||||
|
.where(
|
||||||
|
and_(
|
||||||
|
DataUpdate.company_id == company.id,
|
||||||
|
DataUpdate.data_source == data_source,
|
||||||
|
DataUpdate.status == 'completed'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.order_by(DataUpdate.completed_at.desc())
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
latest_update = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not latest_update:
|
||||||
|
return DataCheckResponse(
|
||||||
|
has_data=False,
|
||||||
|
company_id=company.id,
|
||||||
|
data_source=data_source,
|
||||||
|
message="该数据源暂无该公司数据"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 构建响应
|
||||||
|
return DataCheckResponse(
|
||||||
|
has_data=True,
|
||||||
|
company_id=company.id,
|
||||||
|
data_source=data_source,
|
||||||
|
last_update={
|
||||||
|
"date": latest_update.completed_at.isoformat(),
|
||||||
|
"data_start_date": latest_update.data_start_date,
|
||||||
|
"data_end_date": latest_update.data_end_date,
|
||||||
|
"table_counts": latest_update.row_counts or {}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def create_or_get_company(
|
||||||
|
market: str,
|
||||||
|
symbol: str,
|
||||||
|
company_name: str,
|
||||||
|
db: AsyncSession
|
||||||
|
) -> Company:
|
||||||
|
"""创建或获取公司记录"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(Company).where(
|
||||||
|
and_(Company.market == market, Company.symbol == symbol)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
company = result.scalar_one_or_none()
|
||||||
|
|
||||||
|
if not company:
|
||||||
|
company = Company(
|
||||||
|
market=market,
|
||||||
|
symbol=symbol,
|
||||||
|
company_name=company_name
|
||||||
|
)
|
||||||
|
db.add(company)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(company)
|
||||||
|
|
||||||
|
return company
|
||||||
|
|
||||||
|
|
||||||
|
async def create_data_update_record(
|
||||||
|
company_id: int,
|
||||||
|
data_source: str,
|
||||||
|
update_type: str,
|
||||||
|
db: AsyncSession
|
||||||
|
) -> DataUpdate:
|
||||||
|
"""创建数据更新记录"""
|
||||||
|
data_update = DataUpdate(
|
||||||
|
company_id=company_id,
|
||||||
|
data_source=data_source,
|
||||||
|
update_type=update_type,
|
||||||
|
status='in_progress'
|
||||||
|
)
|
||||||
|
db.add(data_update)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(data_update)
|
||||||
|
return data_update
|
||||||
|
|
||||||
|
|
||||||
|
async def update_data_update_record(
|
||||||
|
update_id: int,
|
||||||
|
status: str,
|
||||||
|
db: AsyncSession,
|
||||||
|
completed_at: Optional[datetime] = None,
|
||||||
|
error_message: Optional[str] = None,
|
||||||
|
data_start_date: Optional[str] = None,
|
||||||
|
data_end_date: Optional[str] = None,
|
||||||
|
fetched_tables: Optional[List[str]] = None,
|
||||||
|
row_counts: Optional[Dict[str, int]] = None
|
||||||
|
):
|
||||||
|
"""更新数据更新记录"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(DataUpdate).where(DataUpdate.id == update_id)
|
||||||
|
)
|
||||||
|
data_update = result.scalar_one()
|
||||||
|
|
||||||
|
data_update.status = status
|
||||||
|
if completed_at:
|
||||||
|
data_update.completed_at = completed_at
|
||||||
|
if error_message:
|
||||||
|
data_update.error_message = error_message
|
||||||
|
if data_start_date:
|
||||||
|
data_update.data_start_date = data_start_date
|
||||||
|
if data_end_date:
|
||||||
|
data_update.data_end_date = data_end_date
|
||||||
|
if fetched_tables:
|
||||||
|
data_update.fetched_tables = fetched_tables
|
||||||
|
if row_counts:
|
||||||
|
data_update.row_counts = row_counts
|
||||||
|
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(data_update)
|
||||||
|
return data_update
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_financial_data_sync(
|
||||||
|
company_id: int,
|
||||||
|
market: str,
|
||||||
|
symbol: str,
|
||||||
|
data_source: str,
|
||||||
|
update_id: int
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
同步方式获取财务数据(在后台任务中调用)
|
||||||
|
|
||||||
|
此函数实际执行数据获取,使用同步的 Fetcher
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 0. 初始化
|
||||||
|
update_progress_sync(update_id, "正在初始化数据获取...", 0)
|
||||||
|
|
||||||
|
# 格式化股票代码 - CN市场需要添加.SH或.SZ后缀
|
||||||
|
formatted_symbol = symbol
|
||||||
|
if market.upper() == 'CN' and data_source == 'Tushare':
|
||||||
|
if '.' not in symbol:
|
||||||
|
# 判断是上海还是深圳
|
||||||
|
if symbol.startswith('6'):
|
||||||
|
formatted_symbol = f"{symbol}.SH"
|
||||||
|
elif symbol.startswith(('0', '3', '2')):
|
||||||
|
formatted_symbol = f"{symbol}.SZ"
|
||||||
|
else:
|
||||||
|
formatted_symbol = f"{symbol}.SH" # 默认上海
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.info(f"📝 [数据获取] 股票代码格式化: {symbol} -> {formatted_symbol}")
|
||||||
|
|
||||||
|
# 1. 获取对应的 Fetcher
|
||||||
|
# 1. 获取对应的 Fetcher
|
||||||
|
fetcher = FetcherFactory.get_fetcher(market, data_source)
|
||||||
|
update_progress_sync(update_id, "数据源连接成功", 10)
|
||||||
|
|
||||||
|
# 2. 触发数据同步
|
||||||
|
# 对于 Bloomberg,我们只需要触发一次全量同步
|
||||||
|
if data_source == 'Bloomberg':
|
||||||
|
update_progress_sync(update_id, "正在连接 Bloomberg 终端...", 20)
|
||||||
|
|
||||||
|
# 定义进度回调
|
||||||
|
def progress_callback(msg, pct):
|
||||||
|
# 映射内部进度 (0-100) 到总体进度 (20-90)
|
||||||
|
mapped_pct = 20 + int(pct * 0.7)
|
||||||
|
update_progress_sync(update_id, msg, mapped_pct)
|
||||||
|
|
||||||
|
# 使用新的 sync_all_data 方法(将在 fetcher 中实现)
|
||||||
|
if hasattr(fetcher, 'sync_all_data'):
|
||||||
|
# 检查 sync_all_data 是否接受 progress_callback 参数
|
||||||
|
import inspect
|
||||||
|
sig = inspect.signature(fetcher.sync_all_data)
|
||||||
|
if 'progress_callback' in sig.parameters:
|
||||||
|
fetcher.sync_all_data(formatted_symbol, progress_callback=progress_callback)
|
||||||
|
else:
|
||||||
|
fetcher.sync_all_data(formatted_symbol)
|
||||||
|
else:
|
||||||
|
# 兼容旧代码,虽然有了 sync_all_data 后这部分应该不需要了
|
||||||
|
fetcher.get_income_statement(formatted_symbol)
|
||||||
|
|
||||||
|
update_progress_sync(update_id, "Bloomberg 数据同步完成", 100)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# 对于其他数据源,保持原有逻辑但简化日志
|
||||||
|
update_progress_sync(update_id, "正在获取财务报表数据...", 30)
|
||||||
|
fetcher.get_income_statement(formatted_symbol)
|
||||||
|
fetcher.get_balance_sheet(formatted_symbol)
|
||||||
|
fetcher.get_cash_flow(formatted_symbol)
|
||||||
|
fetcher.get_market_metrics(formatted_symbol)
|
||||||
|
|
||||||
|
# 尝试获取辅助数据
|
||||||
|
try:
|
||||||
|
fetcher.get_dividends(symbol)
|
||||||
|
fetcher.get_repurchases(symbol)
|
||||||
|
fetcher.get_employee_count(symbol)
|
||||||
|
except Exception:
|
||||||
|
pass # 忽略辅助数据获取错误
|
||||||
|
|
||||||
|
update_progress_sync(update_id, "数据同步完成", 100)
|
||||||
|
|
||||||
|
result_data = {
|
||||||
|
'status': 'completed',
|
||||||
|
'completed_at': datetime.now(),
|
||||||
|
'fetched_tables': ['unified_data'] if data_source == 'Bloomberg' else ['income_statement', 'balance_sheet', 'cash_flow', 'daily_basic'],
|
||||||
|
# 不再统计行数
|
||||||
|
'row_counts': {}
|
||||||
|
}
|
||||||
|
return result_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
update_progress_sync(update_id, f"数据获取失败: {str(e)}", 0)
|
||||||
|
return {
|
||||||
|
'status': 'failed',
|
||||||
|
'error_message': str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def get_financial_data_from_db(
|
||||||
|
company_id: int,
|
||||||
|
data_source: str,
|
||||||
|
db: AsyncSession
|
||||||
|
) -> Dict:
|
||||||
|
"""
|
||||||
|
从数据库读取财务数据
|
||||||
|
|
||||||
|
Args:
|
||||||
|
company_id: 公司ID
|
||||||
|
data_source: 数据源 (iFinD, Bloomberg, Tushare)
|
||||||
|
db: 数据库会话
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含所有财务数据的字典
|
||||||
|
"""
|
||||||
|
# 获取公司信息
|
||||||
|
result = await db.execute(
|
||||||
|
select(Company).where(Company.id == company_id)
|
||||||
|
)
|
||||||
|
company = result.scalar_one()
|
||||||
|
|
||||||
|
# 准备返回数据结构
|
||||||
|
response_data = {
|
||||||
|
"company": {
|
||||||
|
"id": company.id,
|
||||||
|
"market": company.market,
|
||||||
|
"symbol": company.symbol,
|
||||||
|
"company_name": company.company_name,
|
||||||
|
"created_at": company.created_at,
|
||||||
|
"updated_at": company.updated_at
|
||||||
|
},
|
||||||
|
"data_source": data_source,
|
||||||
|
"income_statement": [],
|
||||||
|
"balance_sheet": [],
|
||||||
|
"cash_flow": [],
|
||||||
|
"daily_basic": [],
|
||||||
|
"dividend": [],
|
||||||
|
"repurchase": [],
|
||||||
|
"employee": [],
|
||||||
|
"unified_data": []
|
||||||
|
}
|
||||||
|
|
||||||
|
# 根据数据源读取数据
|
||||||
|
if data_source == 'Tushare' and company.market == 'CN':
|
||||||
|
# 定义表映射
|
||||||
|
tables = {
|
||||||
|
"income_statement": "tushare_income_statement",
|
||||||
|
"balance_sheet": "tushare_balance_sheet",
|
||||||
|
"cash_flow": "tushare_cash_flow",
|
||||||
|
"daily_basic": "tushare_daily_basic",
|
||||||
|
"dividend": "tushare_dividend",
|
||||||
|
"repurchase": "tushare_repurchase",
|
||||||
|
"employee": "tushare_stock_company" # Tushare 员工信息通常在公司信息表中
|
||||||
|
}
|
||||||
|
|
||||||
|
# 辅助函数:读取表数据
|
||||||
|
# from sqlalchemy import text (moved to top)
|
||||||
|
|
||||||
|
async def fetch_table_data(table_name, symbol_code, order_by=None):
|
||||||
|
try:
|
||||||
|
# 检查表是否存在
|
||||||
|
check_sql = text("SELECT to_regclass(:table_name)")
|
||||||
|
exists = await db.execute(check_sql, {"table_name": f"public.{table_name}"})
|
||||||
|
if not exists.scalar():
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 查询数据
|
||||||
|
query = f"SELECT * FROM {table_name} WHERE ts_code = :ts_code"
|
||||||
|
if order_by:
|
||||||
|
query += f" ORDER BY {order_by} DESC"
|
||||||
|
query += " LIMIT 100" # 限制返回数量
|
||||||
|
|
||||||
|
result = await db.execute(text(query), {"ts_code": symbol_code})
|
||||||
|
|
||||||
|
# 转换为字典列表,处理日期格式
|
||||||
|
data = []
|
||||||
|
for row in result.mappings():
|
||||||
|
item = dict(row)
|
||||||
|
# 处理日期对象为字符串
|
||||||
|
for k, v in item.items():
|
||||||
|
if isinstance(v, datetime):
|
||||||
|
item[k] = v.isoformat()
|
||||||
|
data.append(item)
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching from {table_name}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Tushare 使用 ts_code (symbol)
|
||||||
|
ts_code = company.symbol # 假设 symbol 已经是 ts_code 格式 (e.g. 300750.SZ)
|
||||||
|
# 如果 symbol 只有数字,可能需要补充后缀,但这里先假设存储时已处理
|
||||||
|
# 实际上 TushareClient._get_ts_code 会处理,这里我们最好模糊匹配或确保一致性
|
||||||
|
# 在前端传递 symbol 时通常是 6 位数字,后端 TushareClient 用它去查询
|
||||||
|
# 这里尝试直接用 symbol 查询,如果为空,尝试添加后缀匹配(但这比较复杂)
|
||||||
|
# 简单起见,我们先用 symbol (假设数据库中存储的 ts_code 包含后缀,我们需要模糊查询或者假设 symbol 是一致的)
|
||||||
|
|
||||||
|
# 修正:Tushare 存储时用的是 ts_code (如 000001.SZ)。
|
||||||
|
# 但我们这里的 company.symbol 可能是没有后缀的 (000001)。
|
||||||
|
# 我们应该用 LIKE 查询或者获取存储时的 ts_code。
|
||||||
|
# 为简单起见,先尝试模糊匹配
|
||||||
|
|
||||||
|
async def fetch_table_data_fuzzy(table_name, symbol_code, order_by=None):
|
||||||
|
try:
|
||||||
|
check_sql = text("SELECT to_regclass(:table_name)")
|
||||||
|
exists = await db.execute(check_sql, {"table_name": f"public.{table_name}"})
|
||||||
|
if not exists.scalar(): return []
|
||||||
|
|
||||||
|
query = f"SELECT * FROM {table_name} WHERE ts_code LIKE :ts_code"
|
||||||
|
if order_by: query += f" ORDER BY {order_by} DESC"
|
||||||
|
query += " LIMIT 50"
|
||||||
|
|
||||||
|
# 尝试匹配 symbol% (如 300750%)
|
||||||
|
result = await db.execute(text(query), {"ts_code": f"{symbol_code}%"})
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for row in result.mappings():
|
||||||
|
item = dict(row)
|
||||||
|
for k, v in item.items():
|
||||||
|
if hasattr(v, 'isoformat'): item[k] = v.isoformat()
|
||||||
|
data.append(item)
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching from {table_name}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# 并行或串行获取数据
|
||||||
|
response_data["income_statement"] = await fetch_table_data_fuzzy(tables["income_statement"], company.symbol, "end_date")
|
||||||
|
response_data["balance_sheet"] = await fetch_table_data_fuzzy(tables["balance_sheet"], company.symbol, "end_date")
|
||||||
|
response_data["cash_flow"] = await fetch_table_data_fuzzy(tables["cash_flow"], company.symbol, "end_date")
|
||||||
|
|
||||||
|
# 日频数据
|
||||||
|
response_data["daily_basic"] = await fetch_table_data_fuzzy(tables["daily_basic"], company.symbol, "trade_date")
|
||||||
|
|
||||||
|
# 其他数据
|
||||||
|
response_data["dividend"] = await fetch_table_data_fuzzy(tables["dividend"], company.symbol, "end_date")
|
||||||
|
response_data["repurchase"] = await fetch_table_data_fuzzy(tables["repurchase"], company.symbol, "ann_date")
|
||||||
|
|
||||||
|
elif data_source == 'Bloomberg':
|
||||||
|
try:
|
||||||
|
# 使用独立的 Bloomberg 服务读取数据
|
||||||
|
unified_data = await get_bloomberg_data(company, db)
|
||||||
|
|
||||||
|
response_data["unified_data"] = unified_data
|
||||||
|
response_data["income_statement"] = []
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error fetching Bloomberg data from stockcard: {e}", exc_info=True)
|
||||||
|
|
||||||
|
return response_data
|
||||||
|
|
||||||
|
|
||||||
|
def get_available_data_sources(market: str) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
获取指定市场的可用数据源
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
数据源列表,每个包含 source, available, description, supported_markets
|
||||||
|
"""
|
||||||
|
all_sources = {
|
||||||
|
'iFinD': {
|
||||||
|
'description': 'iFinD (同花顺) 数据源',
|
||||||
|
'supported_markets': ['HK', 'JP', 'US', 'VN']
|
||||||
|
},
|
||||||
|
'Tushare': {
|
||||||
|
'description': 'Tushare 数据源',
|
||||||
|
'supported_markets': ['CN']
|
||||||
|
},
|
||||||
|
'Bloomberg': {
|
||||||
|
'description': 'Bloomberg 数据源',
|
||||||
|
'supported_markets': ['CN', 'HK', 'JP', 'US', 'VN']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
for source_name, info in all_sources.items():
|
||||||
|
sources.append({
|
||||||
|
'source': source_name,
|
||||||
|
'available': market in info['supported_markets'],
|
||||||
|
'description': info['description'],
|
||||||
|
'supported_markets': info['supported_markets']
|
||||||
|
})
|
||||||
|
|
||||||
|
return sources
|
||||||
|
|
||||||
|
async def get_recent_companies(
|
||||||
|
data_source: str,
|
||||||
|
db: AsyncSession,
|
||||||
|
limit: int = 20
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""获取指定数据源下最近更新的公司"""
|
||||||
|
query = (
|
||||||
|
select(Company, DataUpdate.completed_at)
|
||||||
|
.join(DataUpdate, Company.id == DataUpdate.company_id)
|
||||||
|
.where(
|
||||||
|
and_(
|
||||||
|
DataUpdate.data_source == data_source,
|
||||||
|
DataUpdate.status == 'completed'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.order_by(DataUpdate.completed_at.desc())
|
||||||
|
.limit(limit * 3) # Fetch more to handle duplicates
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await db.execute(query)
|
||||||
|
rows = result.all()
|
||||||
|
|
||||||
|
seen_ids = set()
|
||||||
|
companies = []
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
company, completed_at = row
|
||||||
|
if company.id not in seen_ids:
|
||||||
|
seen_ids.add(company.id)
|
||||||
|
companies.append({
|
||||||
|
"market": company.market,
|
||||||
|
"symbol": company.symbol,
|
||||||
|
"company_name": company.company_name,
|
||||||
|
"last_update": completed_at.strftime('%Y-%m-%d %H:%M') if completed_at else ""
|
||||||
|
})
|
||||||
|
if len(companies) >= limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
return companies
|
||||||
@ -7,6 +7,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from sqlalchemy.future import select
|
from sqlalchemy.future import select
|
||||||
from app.models import Report, ReportSection, Setting
|
from app.models import Report, ReportSection, Setting
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def load_prompts(db: AsyncSession, prompt_dir: str):
|
async def load_prompts(db: AsyncSession, prompt_dir: str):
|
||||||
prompts = {}
|
prompts = {}
|
||||||
@ -42,6 +45,9 @@ async def load_prompts(db: AsyncSession, prompt_dir: str):
|
|||||||
async def call_llm(api_key: str, model_name: str, system_prompt: str, user_prompt: str, context: str, enable_search: bool = True):
|
async def call_llm(api_key: str, model_name: str, system_prompt: str, user_prompt: str, context: str, enable_search: bool = True):
|
||||||
full_prompt = f"{system_prompt}\n\n{user_prompt}\n\nExisting Report Data for context:\n{context}"
|
full_prompt = f"{system_prompt}\n\n{user_prompt}\n\nExisting Report Data for context:\n{context}"
|
||||||
|
|
||||||
|
logger.info(f"🤖 [LLM] 开始调用模型: {model_name}, 启用搜索: {enable_search}")
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
client = genai.Client(api_key=api_key)
|
client = genai.Client(api_key=api_key)
|
||||||
|
|
||||||
config_params = {}
|
config_params = {}
|
||||||
@ -63,6 +69,10 @@ async def call_llm(api_key: str, model_name: str, system_prompt: str, user_promp
|
|||||||
usage = response.usage_metadata
|
usage = response.usage_metadata
|
||||||
prompt_tokens = usage.prompt_token_count if usage else 0
|
prompt_tokens = usage.prompt_token_count if usage else 0
|
||||||
completion_tokens = usage.candidates_token_count if usage else 0
|
completion_tokens = usage.candidates_token_count if usage else 0
|
||||||
|
total_tokens = prompt_tokens + completion_tokens
|
||||||
|
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
logger.info(f"✅ [LLM] 模型响应完成, 耗时: {elapsed:.2f}秒, Tokens: prompt={prompt_tokens}, completion={completion_tokens}, total={total_tokens}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"text": response.text,
|
"text": response.text,
|
||||||
@ -125,7 +135,9 @@ async def process_analysis_steps(report_id: int, company_name: str, symbol: str,
|
|||||||
|
|
||||||
# Prepare all API calls concurrently
|
# Prepare all API calls concurrently
|
||||||
async def process_section(key: str, name: str):
|
async def process_section(key: str, name: str):
|
||||||
print(f"Processing {name}...")
|
logger.info(f"📝 [LLM] 开始处理章节: {name}")
|
||||||
|
section_start = time.time()
|
||||||
|
|
||||||
prompt_template = prompts.get(key)
|
prompt_template = prompts.get(key)
|
||||||
if not prompt_template:
|
if not prompt_template:
|
||||||
return None
|
return None
|
||||||
@ -141,6 +153,9 @@ async def process_analysis_steps(report_id: int, company_name: str, symbol: str,
|
|||||||
|
|
||||||
result = await call_llm(api_key, model_name, system_content, user_content, current_data_context, enable_search=True)
|
result = await call_llm(api_key, model_name, system_content, user_content, current_data_context, enable_search=True)
|
||||||
|
|
||||||
|
section_elapsed = time.time() - section_start
|
||||||
|
logger.info(f"✅ [LLM] 章节 {name} 处理完成, 总耗时: {section_elapsed:.2f}秒")
|
||||||
|
|
||||||
return (key, result)
|
return (key, result)
|
||||||
|
|
||||||
# Run all sections concurrently
|
# Run all sections concurrently
|
||||||
|
|||||||
55
backend/scripts/fix_data_updates_schema.py
Normal file
55
backend/scripts/fix_data_updates_schema.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import psycopg2
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load .env
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
def get_db_connection():
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
return psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
|
||||||
|
def fix_schema():
|
||||||
|
print("🔧 Fixing data_updates table schema...")
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
conn.autocommit = True
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# 1. Alter status column to TEXT to avoid varchar(8) limits
|
||||||
|
print("Altering status column to TEXT...")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN status TYPE TEXT;")
|
||||||
|
|
||||||
|
# 2. Check if error_message needs widening too
|
||||||
|
print("Altering error_message column to TEXT...")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN error_message TYPE TEXT;")
|
||||||
|
|
||||||
|
# 3. Ensure other columns are safe
|
||||||
|
# fetched_tables and row_counts should be JSONB or TEXT
|
||||||
|
# Just in case they are restricted varchar
|
||||||
|
print("Altering fetched_tables and row_counts to TEXT...")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN fetched_tables TYPE TEXT;")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN row_counts TYPE TEXT;")
|
||||||
|
|
||||||
|
# 4. Fix date columns that might also be varchar(8)
|
||||||
|
print("Altering data_start_date and data_end_date to TEXT...")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN data_start_date TYPE TEXT;")
|
||||||
|
cur.execute("ALTER TABLE data_updates ALTER COLUMN data_end_date TYPE TEXT;")
|
||||||
|
|
||||||
|
print("✅ Schema fixed successfully.")
|
||||||
|
conn.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error fixing schema: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
fix_schema()
|
||||||
53
backend/scripts/reset_all_int_tables.py
Normal file
53
backend/scripts/reset_all_int_tables.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import psycopg2
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load .env
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
def get_db_connection():
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
return psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
|
||||||
|
def drop_tables():
|
||||||
|
tables = [
|
||||||
|
"ifind_int_income_statement",
|
||||||
|
"ifind_int_balance_sheet",
|
||||||
|
"ifind_int_cash_flow",
|
||||||
|
"ifind_int_daily_basic",
|
||||||
|
"ifind_int_financial_ratios",
|
||||||
|
"ifind_int_dividend",
|
||||||
|
"ifind_int_repurchase",
|
||||||
|
"ifind_int_employee"
|
||||||
|
]
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
conn.autocommit = True
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
print("🧹 Starting cleanup of iFinD International tables...")
|
||||||
|
try:
|
||||||
|
for table in tables:
|
||||||
|
print(f"Dropping {table}...")
|
||||||
|
cursor.execute(f"DROP TABLE IF EXISTS {table}")
|
||||||
|
print(f"✅ Dropped {table}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error during cleanup: {e}")
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print("🎉 Cleanup completed.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
drop_tables()
|
||||||
36
backend/scripts/reset_tables.py
Normal file
36
backend/scripts/reset_tables.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import psycopg2
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load .env
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
def get_db_connection():
|
||||||
|
db_host = os.getenv("DB_HOST", "192.168.3.195")
|
||||||
|
db_user = os.getenv("DB_USER", "value")
|
||||||
|
db_pass = os.getenv("DB_PASSWORD", "Value609!")
|
||||||
|
db_name = os.getenv("DB_NAME", "fa3")
|
||||||
|
db_port = os.getenv("DB_PORT", "5432")
|
||||||
|
|
||||||
|
return psycopg2.connect(
|
||||||
|
host=db_host, user=db_user, password=db_pass, dbname=db_name, port=db_port
|
||||||
|
)
|
||||||
|
|
||||||
|
def drop_table(table_name):
|
||||||
|
print(f"Dropping table {table_name}...")
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
conn.autocommit = True
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"DROP TABLE IF EXISTS {table_name}")
|
||||||
|
print(f"✅ Dropped {table_name}")
|
||||||
|
conn.close()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error dropping {table_name}: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
drop_table("ifind_int_daily_basic")
|
||||||
66
backend/scripts/verify_migration.py
Normal file
66
backend/scripts/verify_migration.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Add backend to path
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
|
||||||
|
from app.fetchers.factory import FetcherFactory
|
||||||
|
from app.clients.ifind_hk_client import IFindHKClient
|
||||||
|
|
||||||
|
# Load .env
|
||||||
|
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
|
load_dotenv(ROOT_DIR / ".env")
|
||||||
|
|
||||||
|
def verify_fetcher(market, symbol, source, method_name='get_market_metrics'):
|
||||||
|
print(f"\n--- Verifying {market} ({source}) for {symbol} ---")
|
||||||
|
try:
|
||||||
|
fetcher = FetcherFactory.get_fetcher(market, source)
|
||||||
|
print(f"✅ Fetcher instantiated: {type(fetcher).__name__}")
|
||||||
|
|
||||||
|
if method_name == 'get_market_metrics':
|
||||||
|
print(f"Calling {method_name}...")
|
||||||
|
data = fetcher.get_market_metrics(symbol)
|
||||||
|
print(f"Result: {data}")
|
||||||
|
if data and isinstance(data, dict) and data.get('price') != 0:
|
||||||
|
print("✅ Data looks valid (Price > 0)")
|
||||||
|
else:
|
||||||
|
print("⚠️ Data might be empty or zero (Market closed or invalid symbol?)")
|
||||||
|
|
||||||
|
elif method_name == 'get_income_statement':
|
||||||
|
print(f"Calling {method_name}...")
|
||||||
|
df = fetcher.get_income_statement(symbol)
|
||||||
|
if not df.empty:
|
||||||
|
print(f"✅ Got DataFrame with shape: {df.shape}")
|
||||||
|
print(df.head(2))
|
||||||
|
else:
|
||||||
|
print("⚠️ Returned empty DataFrame")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error: {e}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Start Verification...")
|
||||||
|
|
||||||
|
# 1. HK (iFinD) - Tencent
|
||||||
|
verify_fetcher('HK', '0700', 'iFinD', 'get_market_metrics')
|
||||||
|
|
||||||
|
# 2. JP (iFinD) - Toyota
|
||||||
|
verify_fetcher('JP', '7203', 'iFinD', 'get_market_metrics')
|
||||||
|
|
||||||
|
# 3. US (iFinD) - Apple
|
||||||
|
verify_fetcher('US', 'AAPL', 'iFinD', 'get_market_metrics')
|
||||||
|
|
||||||
|
# 4. VN (iFinD) - VIC? (Vingroup)
|
||||||
|
verify_fetcher('VN', 'VIC', 'iFinD', 'get_market_metrics')
|
||||||
|
|
||||||
|
# 5. Bloomberg - US - AAPL (Skip if no connection, but try)
|
||||||
|
# verify_fetcher('US', 'AAPL', 'Bloomberg', 'get_market_metrics') # Enabling for test
|
||||||
|
|
||||||
|
print("\nVerification Script Completed.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1398
backend/server.log
Normal file
1398
backend/server.log
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
|||||||
date_str,Price,PE,PB,MarketCap,Shareholders
|
|
||||||
20250930,402.0,36.1375,6.3157,1833784274046.0,226368.0
|
|
||||||
20241231,266.0,26.5478,4.9395,1171322077828.0,212061.0
|
|
||||||
20240930,251.89,25.1333,5.64,1108914407264.0,229043.0
|
|
||||||
20231231,163.26,23.3715,3.9816,718187472189.0,260992.0
|
|
||||||
20221231,393.42,60.3173,6.3972,960934064032.0,183317.0
|
|
||||||
20211231,588.0,245.4697,18.7433,1370540505600.0,141963.0
|
|
||||||
20201231,351.11,179.3523,13.3304,817901625971.0,133060.0
|
|
||||||
20191231,106.4,69.3745,6.3603,234973728079.99997,76710.0
|
|
||||||
20181231,73.8,41.7726,5.015,161992284120.0,82514.0
|
|
||||||
20171231,,,,,
|
|
||||||
20161231,,,,,
|
|
||||||
20151231,,,,,
|
|
||||||
20141231,,,,,
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,total_share,cap_rese,undistr_porfit,surplus_rese,special_rese,money_cap,trad_asset,notes_receiv,accounts_receiv,oth_receiv,prepayment,div_receiv,int_receiv,inventories,amor_exp,nca_within_1y,sett_rsrv,loanto_oth_bank_fi,premium_receiv,reinsur_receiv,reinsur_res_receiv,pur_resale_fa,oth_cur_assets,total_cur_assets,fa_avail_for_sale,htm_invest,lt_eqt_invest,invest_real_estate,time_deposits,oth_assets,lt_rec,fix_assets,cip,const_materials,fixed_assets_disp,produc_bio_assets,oil_and_gas_assets,intan_assets,r_and_d,goodwill,lt_amor_exp,defer_tax_assets,decr_in_disbur,oth_nca,total_nca,cash_reser_cb,depos_in_oth_bfi,prec_metals,deriv_assets,rr_reins_une_prem,rr_reins_outstd_cla,rr_reins_lins_liab,rr_reins_lthins_liab,refund_depos,ph_pledge_loans,refund_cap_depos,indep_acct_assets,client_depos,client_prov,transac_seat_fee,invest_as_receiv,total_assets,lt_borr,st_borr,cb_borr,depos_ib_deposits,loan_oth_bank,trading_fl,notes_payable,acct_payable,adv_receipts,sold_for_repur_fa,comm_payable,payroll_payable,taxes_payable,int_payable,div_payable,oth_payable,acc_exp,deferred_inc,st_bonds_payable,payable_to_reinsurer,rsrv_insur_cont,acting_trading_sec,acting_uw_sec,non_cur_liab_due_1y,oth_cur_liab,total_cur_liab,bond_payable,lt_payable,specific_payables,estimated_liab,defer_tax_liab,defer_inc_non_cur_liab,oth_ncl,total_ncl,depos_oth_bfi,deriv_liab,depos,agency_bus_liab,oth_liab,prem_receiv_adva,depos_received,ph_invest,reser_une_prem,reser_outstd_claims,reser_lins_liab,reser_lthins_liab,indept_acc_liab,pledge_borr,indem_payable,policy_div_payable,total_liab,treasury_share,ordin_risk_reser,forex_differ,invest_loss_unconf,minority_int,total_hldr_eqy_exc_min_int,total_hldr_eqy_inc_min_int,total_liab_hldr_eqy,lt_payroll_payable,oth_comp_income,oth_eqt_tools,oth_eqt_tools_p_shr,lending_funds,acc_receivable,st_fin_payable,payables,hfs_assets,hfs_sales,cost_fin_assets,fair_value_fin_assets,contract_assets,contract_liab,accounts_receiv_bill,accounts_pay,oth_rcv_total,fix_assets_total,cip_total,oth_pay_total,long_pay_total,debt_invest,oth_debt_invest,update_flag
|
|
||||||
300750.SZ,20251021,20251021,20250930,1,1,3,4562854001.0,156365576000.0,151715049000.0,2272701000.0,38434000.0,324241586000.0,43260528000.0,418837000.0,66481235000.0,,13557167000.0,75434000.0,,80211558000.0,,98616000.0,,,,,,,10578550000.0,574228137000.0,,,59831799000.0,,,,193099000.0,128622702000.0,37365635000.0,,,,,15025388000.0,,890939000.0,4908611000.0,28542552000.0,,23937431000.0,321853995000.0,,,,36492000.0,,,,,,,,,,,,,896082131000.0,78441925000.0,15314463000.0,,,,,82967668000.0,131958477000.0,,,,21821691000.0,8851546000.0,,98000000.0,,,,,,,,,25005358000.0,4985363000.0,340940328000.0,8422115000.0,,,85843047000.0,2261098000.0,25224182000.0,4739536000.0,208129732000.0,,,,,,,,,,,,,,,,,549070060000.0,7097993000.0,,,,32764095000.0,314247976000.0,347012071000.0,896082131000.0,,6391356000.0,,,,,,,,,,,398446000.0,40678197000.0,66900072000.0,214926145000.0,2862290000.0,128622702000.0,37365635000.0,9357565000.0,1519965000.0,,,1
|
|
||||||
300750.SZ,20251021,20251021,20250930,1,1,3,4562854000.0,156365576000.0,151715049000.0,2272701000.0,38434000.0,324241586000.0,43260528000.0,418837000.0,66481235000.0,,13557167000.0,75434000.0,,80211558000.0,,98616000.0,,,,,,,10578550000.0,574228137000.0,,,59831799000.0,,,,193099000.0,128622702000.0,37365635000.0,,,,,15025388000.0,,890939000.0,4908611000.0,28542552000.0,,23937431000.0,321853995000.0,,,,36492000.0,,,,,,,,,,,,,896082131000.0,78441925000.0,15314463000.0,,,,,82967668000.0,131958477000.0,,,,21821691000.0,8851546000.0,,98000000.0,,,,,,,,,25005358000.0,4985363000.0,340940328000.0,8422115000.0,,,85843047000.0,2261098000.0,25224182000.0,4739536000.0,208129732000.0,,,,,,,,,,,,,,,,,549070060000.0,7097993000.0,,,,32764095000.0,314247976000.0,347012071000.0,896082131000.0,,6391356000.0,,,,,,,,,,,398446000.0,40678197000.0,66900072000.0,214926145000.0,2862290000.0,128622702000.0,37365635000.0,9357565000.0,1519965000.0,,,0
|
|
||||||
300750.SZ,20250731,20250731,20250630,1,1,2,4559310311.0,154314344000.0,137146982000.0,2272701000.0,32301000.0,350577746000.0,22447277000.0,314830000.0,63800375000.0,2223575000.0,9752799000.0,78013000.0,0.0,72272139000.0,,88019000.0,,,,,,,9410883000.0,567700337000.0,,,57636957000.0,,,,136825000.0,118696651000.0,35086190000.0,,,,,14684829000.0,,892909000.0,4301351000.0,26965253000.0,,25414858000.0,299481094000.0,,,,,,,,,,,,,,,,,867181431000.0,82416083000.0,19009443000.0,,,,,76968647000.0,133420147000.0,,,,20115797000.0,8643847000.0,1000.0,1107999000.0,10373854000.0,,,,,,,,26031681000.0,3506536000.0,336005110000.0,11970602000.0,1640002000.0,0.0,80137122000.0,1140246000.0,23683078000.0,4976542000.0,206786909000.0,,185496000.0,,,,,,,,,,,,,,,542792019000.0,4262590000.0,,,,29466392000.0,294923020000.0,324389412000.0,867181431000.0,,859971000.0,,,,,,,,,,,346467000.0,36641662000.0,64115205000.0,210388794000.0,2301588000.0,118696651000.0,35086190000.0,11481854000.0,1640002000.0,,,0
|
|
||||||
300750.SZ,20250415,20250415,20250331,1,1,1,4403394911.0,116857798000.0,140632845000.0,2194779000.0,48242000.0,321323654000.0,21421660000.0,168477000.0,60182430000.0,,7417713000.0,65098000.0,,65639666000.0,,78040000.0,,,,,,,7769187000.0,530298544000.0,,,56483298000.0,,,,176608000.0,112142665000.0,35221700000.0,,,,,14496931000.0,,893898000.0,4373265000.0,25303240000.0,,25136769000.0,289798725000.0,,,,,,,,,,,,,,,,,820097269000.0,84826153000.0,15782433000.0,,,,,79844165000.0,128662495000.0,,,,20320028000.0,9561191000.0,,,,,,,,,,,23013434000.0,2866697000.0,328208754000.0,11914211000.0,,,73507580000.0,1209610000.0,23847636000.0,5215845000.0,202749160000.0,,899889000.0,,,,,,,,,,,,,,,530957915000.0,2711392000.0,,,,27581708000.0,261557647000.0,289139355000.0,820097269000.0,,131980000.0,,,,,,,,,,,261473000.0,37088532000.0,60350907000.0,208506660000.0,2125282000.0,112142665000.0,35221700000.0,10169890000.0,1656337000.0,,,1
|
|
||||||
300750.SZ,20250315,20250315,20241231,1,1,4,4403466458.0,116756136000.0,126601541000.0,2194779000.0,35551000.0,303511993000.0,14282253000.0,130403000.0,64135510000.0,2141729000.0,5969685000.0,65217000.0,1000.0,59835533000.0,,72972000.0,,,,,,,6286465000.0,510142089000.0,,,54791525000.0,,,,151342000.0,112589053000.0,29754703000.0,,,,,14419804000.0,,894757000.0,4593980000.0,24118834000.0,,19275483000.0,276516035000.0,,,,,,,,,,,,,,,,,786658123000.0,81238456000.0,19696282000.0,,,,,67356323000.0,130977408000.0,,,,18653079000.0,9436442000.0,0.0,5400161000.0,10761762000.0,,,,,,,,22881417000.0,2058196000.0,317171534000.0,11922623000.0,1606480000.0,0.0,71926943000.0,1231236000.0,22041069000.0,5400795000.0,196030416000.0,,2116017000.0,,,,,,,,,,,,,,,513201949000.0,2712804000.0,,,,26526141000.0,246930033000.0,273456174000.0,786658123000.0,,-348637000.0,,,,,,,,,,,400626000.0,27834446000.0,64265913000.0,198333731000.0,2206947000.0,112589053000.0,29754703000.0,16161923000.0,1606480000.0,,,0
|
|
||||||
300750.SZ,20241019,20241019,20240930,1,1,3,4402375669.0,115137443600.0,117181223700.0,2192566200.0,33103400.0,264675795100.0,22002410300.0,292441400.0,66702709300.0,,6887337600.0,504261300.0,,55215275300.0,,200635500.0,,,,,,,6577524400.0,466764516700.0,,,54175331200.0,,,,128324700.0,110653484500.0,25200973600.0,,,,,14448153400.0,,883700900.0,4528856500.0,22121062800.0,,22428362600.0,271470487700.0,,,,,,,,,,,,,,,,,738235004400.0,85444436200.0,15239389800.0,,,,,63651540000.0,123140013700.0,,,,17368871900.0,8144202500.0,,22722000.0,,,,,,,,,16081511700.0,2926818100.0,281070698000.0,12104785500.0,,,65430208700.0,1180577400.0,21899574000.0,5492450500.0,193863663000.0,,2499377200.0,,,,,,,,,,,,,,,474934361000.0,2776131700.0,,,,26344412200.0,236956231200.0,263300643400.0,738235004400.0,,785650400.0,,,,,,,,,,,363142300.0,22651661600.0,66995150700.0,186791553700.0,3444015600.0,110653484500.0,25200973600.0,9367311600.0,1594834100.0,,,0
|
|
||||||
300750.SZ,20240727,20240727,20240630,1,1,2,4398807222.0,88643885800.0,104031988700.0,2192566200.0,21079900.0,255002207100.0,17300865500.0,228380300.0,58099476000.0,2869209400.0,7826466800.0,1246594600.0,,48050676200.0,,230227700.0,,,,,,,7030728600.0,442116937300.0,,,52121325000.0,,,,145385900.0,113142792200.0,27257067100.0,,,,,15718068700.0,,890937400.0,5000170700.0,20892871600.0,,21694056900.0,273134951500.0,,,,,,,,,,,,,,,,,715251888900.0,88819915800.0,18048659700.0,,,,,66052159100.0,116979636700.0,,,,16596608800.0,6093742000.0,,24643100.0,10590190600.0,,,,,,,,7123836300.0,2496093000.0,270831777000.0,19414874600.0,1651515800.0,,59165819700.0,1090238200.0,21242202400.0,32547613200.0,224580485000.0,,4363213700.0,,,,,,,,,,,,,,,495412262100.0,2511358500.0,,,,23608483400.0,196231143400.0,219839626800.0,715251888900.0,,-545826100.0,,,,,,,,,,,284662400.0,22462994100.0,58327856300.0,183031795800.0,4115804000.0,113142792200.0,27257067100.0,10614833600.0,1651515800.0,,,0
|
|
||||||
300750.SZ,20240416,20240416,20240331,1,1,1,4399041236.0,88213595700.0,113775363800.0,2192566200.0,12724600.0,288572136900.0,166802200.0,817044100.0,51186897200.0,,7886550900.0,426713900.0,,43979311300.0,,251362300.0,,,,,,,7332498400.0,459955986900.0,,,50586279900.0,,,,191694400.0,114498533800.0,26216109200.0,,,,,15581536000.0,,887894800.0,4958130700.0,19434638000.0,,22482818500.0,271330494700.0,,,,,,,,,,,,,,,,,731286481500.0,88444675700.0,16535118900.0,,,,,72631731700.0,112507178900.0,,,,16630284100.0,12277242700.0,,6975500.0,,,,,,,,,8263102400.0,2669102500.0,278962389700.0,19236444600.0,,,57296406400.0,1241289000.0,21767081900.0,31866021200.0,221855700200.0,,4754753700.0,,,,,,,,,,,,,,,500818089800.0,1966347800.0,,,,22738517700.0,207729874000.0,230468391700.0,731286481500.0,,1102930300.0,,,,,,,,,,,261354300.0,20599513300.0,52003941300.0,185138910600.0,3240165600.0,114498533800.0,26216109200.0,12094361500.0,1670358000.0,,,1
|
|
||||||
300750.SZ,20240416,20240416,20240331,1,1,1,4399041200.0,88213595700.0,113775363800.0,2192566200.0,12724600.0,288572136900.0,166802200.0,817044100.0,51186897200.0,,7886550900.0,426713900.0,,43979311300.0,,251362300.0,,,,,,,7332498400.0,459955986900.0,,,50586279900.0,,,,191694400.0,114498533800.0,26216109200.0,,,,,15581536000.0,,887894800.0,4958130700.0,19434638000.0,,22482818500.0,271330494700.0,,,,,,,,,,,,,,,,,731286481500.0,88444675700.0,16535118900.0,,,,,72631731700.0,112507178900.0,,,,16630284100.0,12277242700.0,,6975500.0,,,,,,,,,8263102400.0,2669102500.0,278962389700.0,19236444600.0,,,57296406400.0,1241289000.0,21767081900.0,31866021200.0,221855700200.0,,4754753700.0,,,,,,,,,,,,,,,500818089800.0,1966347800.0,,,,22738517700.0,207729874000.0,230468391700.0,731286481500.0,,1102930300.0,,,,,,,,,,,261354300.0,20599513300.0,52003941300.0,185138910600.0,3240165600.0,114498533800.0,26216109200.0,12094361500.0,1670358000.0,,,0
|
|
||||||
300750.SZ,20240316,20240316,20231231,1,1,4,4399041236.0,87907212600.0,103244625900.0,2192566200.0,9355000.0,264306514700.0,7767200.0,1751724600.0,64020533400.0,3012579200.0,6962872600.0,425984800.0,0.0,45433890100.0,,56827500.0,,,,,,,8286024600.0,449788001700.0,,,50027694100.0,,,,9839600.0,115387960100.0,25011907100.0,,,,,15675876200.0,,707881700.0,4695780000.0,17395585300.0,,21145073300.0,267380039400.0,,,,,,,,,,,,,,,,,717168041100.0,83448981700.0,15181012100.0,,,,,77514940700.0,117038773600.0,,,,14846251200.0,11741826300.0,0.0,29915700.0,13624086000.0,,,,,,,,7008874200.0,2091627800.0,287001069100.0,19237014400.0,1520256200.0,0.0,51638913500.0,1364905800.0,21448987400.0,31341466200.0,210283821400.0,,3941409600.0,,,,,,,,,,,,,,,497284890500.0,1572971600.0,,,,22175098200.0,197708052400.0,219883150600.0,717168041100.0,,1528223100.0,,,,,,,,,,,233964100.0,23982351900.0,65772258000.0,194553714300.0,3438564000.0,115387960100.0,25011907100.0,13654001700.0,1520256200.0,,,1
|
|
||||||
300750.SZ,20240316,20240316,20231231,1,1,4,4399041236.0,87907212600.0,103244625900.0,2192566200.0,9355000.0,264306514700.0,7767200.0,1751724600.0,64020533400.0,3012579200.0,6962872600.0,425984800.0,0.0,45433890100.0,,56827500.0,,,,,,,8286024600.0,449788001700.0,,,50027694100.0,,,,9839600.0,115387960100.0,25011907100.0,,,,,15675876200.0,,707881700.0,4695780000.0,17395585300.0,,21145073300.0,267380039400.0,,,,,,,,,,,,,,,,,717168041100.0,83448981700.0,15181012100.0,,,,,77514940700.0,117038773600.0,,,,14846251200.0,11741826300.0,0.0,29915700.0,13624086000.0,,,,,,,,7008874200.0,2091627800.0,287001069100.0,19237014400.0,1520256200.0,0.0,51638913500.0,1364905800.0,21448987400.0,31341466200.0,210283821400.0,,3941409600.0,,,,,,,,,,,,,,,497284890500.0,1572971600.0,,,,22175098200.0,197708052400.0,219883150600.0,717168041100.0,,1528223100.0,,,,,,,,,,,233964100.0,23982351900.0,65772258000.0,194553714300.0,3438564000.0,115387960100.0,25011907100.0,13654001700.0,1520256200.0,,,0
|
|
||||||
300750.SZ,20231020,20231020,20230930,1,1,3,4397223887.0,80571445900.0,91164745400.0,1214302900.0,6874800.0,233760087400.0,7680800.0,1534828000.0,68726798500.0,,8921784800.0,1212700.0,,48884011700.0,,63996200.0,,,,,,,7217387400.0,411386685400.0,,,45348743500.0,,,,15454100.0,104274341100.0,30650096400.0,,,,,16556905600.0,,715271700.0,4499728200.0,14571656000.0,,25355284700.0,260445521900.0,,,,,,,,,,,,,,,,,671832207300.0,85435191100.0,11348919000.0,,,,,79081439500.0,110924701800.0,,,,14119318800.0,6267372700.0,,26099000.0,,,,,,,,,4637261500.0,1725438200.0,276198050800.0,19676311700.0,,,31814013600.0,1381740300.0,20047725100.0,33132589700.0,193577250000.0,,5727986000.0,,,,,,,,,,,,,,,469775300700.0,249411800.0,,,,21942486100.0,180114420500.0,202056906600.0,671832207300.0,,3009239400.0,,,,,,,,,,,152275500.0,26556925700.0,70261626500.0,190006141300.0,3793848000.0,104274341100.0,30650096400.0,15808687600.0,1539941700.0,,,1
|
|
||||||
300750.SZ,20230726,20230726,20230630,1,1,2,4396292935.0,79909614900.0,80942539200.0,1214302900.0,3891600.0,219582042500.0,371279300.0,4221345500.0,61516723600.0,4505322900.0,12745835100.0,469548100.0,0.0,48910488200.0,,66949700.0,,,,,,,9120136200.0,383061012800.0,,,42820900000.0,,,,28657300.0,102694335500.0,32670444000.0,,,,,15607433200.0,,715160700.0,4336921600.0,12593262700.0,,25735275400.0,257937771900.0,,,,,,,,,,,,,,,,,640998784700.0,74910430300.0,16656553000.0,,,,,86701317000.0,100932770200.0,,,,12255185700.0,5889655600.0,0.0,36599000.0,15647024600.0,,,,,,,,4103059100.0,1785485900.0,270904064900.0,19793296700.0,1200000000.0,0.0,26355789200.0,1464682000.0,20534650700.0,33613635200.0,178411544000.0,,4762003000.0,,,,,,,,,,,,,,,449315608900.0,249411800.0,,,,21464036400.0,170219139400.0,191683175800.0,640998784700.0,,4001909600.0,,,,,,,,,,,344170000.0,22134411900.0,65738069100.0,187634087200.0,4974871000.0,102694335500.0,32670444000.0,15683623600.0,1200000000.0,,,0
|
|
||||||
300750.SZ,20230726,20230726,20230630,1,1,2,4396292935.0,79909614900.0,80942539200.0,1214302900.0,3891600.0,219582042500.0,371279300.0,4221345500.0,61516723600.0,4505322900.0,12745835100.0,469548100.0,0.0,48910488200.0,,66949700.0,,,,,,,9120136200.0,383061012800.0,,,42820900000.0,,,,28657300.0,102694335500.0,32670444000.0,,,,,15607433200.0,,715160700.0,4336921600.0,12593262700.0,,25735275400.0,257937771900.0,,,,,,,,,,,,,,,,,640998784700.0,74910430300.0,16656553000.0,,,,,86701317000.0,100932770200.0,,,,12255185700.0,5889655600.0,0.0,36599000.0,15647024600.0,,,,,,,,4103059100.0,1785485900.0,270904064900.0,19793296700.0,1200000000.0,0.0,26355789200.0,1464682000.0,20534650700.0,33613635200.0,178411544000.0,,4762003000.0,,,,,,,,,,,,,,,449315608900.0,249411800.0,,,,21464036400.0,170219139400.0,191683175800.0,640998784700.0,,4001909600.0,,,,,,,,,,,344170000.0,22134411900.0,65738069100.0,187634087200.0,4974871000.0,102694335500.0,32670444000.0,15683623600.0,1200000000.0,,,1
|
|
||||||
300750.SZ,20230421,20230421,20230331,1,1,1,2442514524.0,108494320100.0,70047213300.0,1214302900.0,,210447048500.0,1496062900.0,4845153200.0,48606965200.0,,14877912400.0,,,64037677300.0,,407644900.0,,,,,,,12242046600.0,389446165900.0,,,44003247000.0,,,,42548700.0,96611233400.0,32354331800.0,,,,,17562949500.0,,715160700.0,3801140400.0,10370303200.0,,26375928900.0,250757411600.0,,,,462334400.0,,,,,,,,,,,,,640203577500.0,68376274800.0,14876987000.0,,,,,114125383600.0,92008949000.0,,,,10213306300.0,5239122700.0,,457812.2,,,,,,,,,3980597800.0,1769661400.0,290026712800.0,18969611400.0,,,21992362200.0,3206405500.0,20463130600.0,6685434300.0,141456422200.0,,,,,,,,,,,,,,,,,431483135000.0,249411800.0,,,,20813483100.0,187906959400.0,208720442500.0,640203577500.0,,5958150000.0,,,,,,,,,,,572681900.0,25872569200.0,53452118400.0,206134332600.0,4578122900.0,96611233400.0,32354331800.0,21940135700.0,1200000000.0,,,1
|
|
||||||
300750.SZ,20230421,20230421,20230331,1,1,1,2442514524.0,108494320100.0,70047213300.0,1214302900.0,,210447048500.0,1496062900.0,4845153200.0,48606965200.0,,14877912400.0,,,64037677300.0,,407644900.0,,,,,,,12242046600.0,389446165900.0,,,44003247000.0,,,,42548700.0,96611233400.0,32354331800.0,,,,,17562949500.0,,715160700.0,3801140400.0,10370303200.0,,26375928900.0,250757411600.0,,,,462334400.0,,,,,,,,,,,,,640203577500.0,68376274800.0,14876987000.0,,,,,114125383600.0,92008949000.0,,,,10213306300.0,5239122700.0,,457812.2,,,,,,,,,3980597800.0,1769661400.0,290026712800.0,18969611400.0,,,21992362200.0,3206405500.0,20463130600.0,6685434300.0,141456422200.0,,,,,,,,,,,,,,,,,431483135000.0,249411800.0,,,,20813483100.0,187906959400.0,208720442500.0,640203577500.0,,5958150000.0,,,,,,,,,,,572681900.0,25872569200.0,53452118400.0,206134332600.0,4578122900.0,96611233400.0,32354331800.0,21940135700.0,1200000000.0,,,0
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,2442514524.0,88904372100.0,63242753100.0,1214302900.0,,191043409500.0,1981328100.0,3526083700.0,57966516900.0,8678379900.0,15843284400.0,,,76668898800.0,,403711500.0,,,,,,,11907028600.0,387734857000.0,,,17595207400.0,,,,44316100.0,89070834700.0,35397650600.0,,,,,9539963200.0,,704065200.0,2294776000.0,9483660400.0,,25101316500.0,213217494900.0,,,,575638000.0,,,,,,,,,,,,,600952351900.0,59099358400.0,14415402500.0,,,,,126229468200.0,94534976000.0,,,,9476018400.0,4792441200.0,,8319600.0,15005751100.0,,,,,,,,7232224400.0,1622032600.0,295761419300.0,19177888600.0,1050000000.0,0.0,19697374600.0,1807813000.0,19966701700.0,6910284100.0,128281770600.0,,,,,,,,,,,,,,,,,424043189900.0,253991000.0,,,,12427910400.0,164481251600.0,176909162000.0,600952351900.0,,8931300000.0,,,,,,,,,,,174863000.0,22444785300.0,61492600600.0,220764444200.0,8678379900.0,89070834700.0,35397650600.0,15014070600.0,1050000000.0,,,0
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,2442514524.0,88904372100.0,63242753100.0,1214302900.0,,191043409500.0,1981328100.0,3526083700.0,57966516900.0,8678379900.0,15843284400.0,,,76668898800.0,,403711500.0,,,,,,,11907028600.0,387734857000.0,,,17595207400.0,,,,44316100.0,89070834700.0,35397650600.0,,,,,9539963200.0,,704065200.0,2294776000.0,9483660400.0,,25101316500.0,213217494900.0,,,,575638000.0,,,,,,,,,,,,,600952351900.0,59099358400.0,14415402500.0,,,,,126229468200.0,94534976000.0,,,,9476018400.0,4792441200.0,,8319600.0,15005751100.0,,,,,,,,7232224400.0,1622032600.0,295761419300.0,19177888600.0,1050000000.0,0.0,19697374600.0,1807813000.0,19966701700.0,6910284100.0,128281770600.0,,,,,,,,,,,,,,,,,424043189900.0,253991000.0,,,,12427910400.0,164481251600.0,176909162000.0,600952351900.0,,8931300000.0,,,,,,,,,,,174863000.0,22444785300.0,61492600600.0,220764444200.0,8678379900.0,89070834700.0,35397650600.0,15014070600.0,1050000000.0,,,1
|
|
||||||
300750.SZ,20221022,20221022,20220930,1,1,3,2440471000.0,88382735300.0,50106491500.0,1213281100.0,,158589590400.0,1872628100.0,2060935500.0,54126365500.0,,12283273500.0,,,79025040400.0,,117605400.0,,,,,,,8955878900.0,344885693500.0,,,16148787800.0,,,,206596500.0,74307767700.0,38870681700.0,,,,,7989903700.0,,1002941600.0,1809975400.0,7347010300.0,,29358395300.0,197055445300.0,,,,,,,,,,,,,,,,,541941138800.0,47507184100.0,14104703300.0,,,,,119432231200.0,90588434600.0,,,,7434024200.0,2611381800.0,,11281100.0,,,,,,,,,8295346800.0,1398400500.0,278220526000.0,14150246000.0,,,13670695200.0,1714036000.0,16308196300.0,7419759400.0,102435170100.0,,20427700.0,,,,,,,,,,,,,,,380655696200.0,253991000.0,,,,11571083300.0,149714359300.0,161285442600.0,541941138800.0,,7825371500.0,,,,,,,,,,,37896000.0,20919604000.0,56187301000.0,210020665800.0,4137737600.0,74307767700.0,38870681700.0,13415971900.0,1310000000.0,,,0
|
|
||||||
300750.SZ,20221022,20221022,20220930,1,1,3,2440471007.0,88382735300.0,50106491500.0,1213281100.0,,158589590400.0,1872628100.0,2060935500.0,54126365500.0,,12283273500.0,,,79025040400.0,,117605400.0,,,,,,,8955878900.0,344885693500.0,,,16148787800.0,,,,206596500.0,74307767700.0,38870681700.0,,,,,7989903700.0,,1002941600.0,1809975400.0,7347010300.0,,29358395300.0,197055445300.0,,,,,,,,,,,,,,,,,541941138800.0,47507184100.0,14104703300.0,,,,,119432231200.0,90588434600.0,,,,7434024200.0,2611381800.0,,11281100.0,,,,,,,,,8295346800.0,1398400500.0,278220526000.0,14150246000.0,,,13670695200.0,1714036000.0,16308196300.0,7419759400.0,102435170100.0,,20427700.0,,,,,,,,,,,,,,,380655696200.0,253991000.0,,,,11571083300.0,149714359300.0,161285442600.0,541941138800.0,,7825371500.0,,,,,,,,,,,37896000.0,20919604000.0,56187301000.0,210020665800.0,4137737600.0,74307767700.0,38870681700.0,13415971900.0,1310000000.0,,,1
|
|
||||||
300750.SZ,20220824,20220824,20220630,1,1,2,2330851200.0,88237358700.0,42177114000.0,1213281100.0,,154264447500.0,1243421300.0,2362856400.0,37454291700.0,3940219400.0,12117397900.0,,,75505395700.0,,117855500.0,,,,,,,7659618000.0,303347957300.0,,,14187663100.0,,,,220568200.0,62198685500.0,37463214300.0,,,,,6815918200.0,,1002941600.0,1666427600.0,6175703600.0,,29115145600.0,177885713700.0,,,,,,,,,,,,,,,,,481233671000.0,38872517900.0,14937309400.0,,,,,107701837000.0,72521038800.0,,,,5041659000.0,1703180400.0,100.0,6590800.0,11498403900.0,,,,,,,,8731818900.0,1320644900.0,243949152300.0,13434684300.0,1160000000.0,0.0,10989376900.0,1459589400.0,14374329700.0,6911647100.0,87594184300.0,,968715900.0,,,,,,,,,,,,,,,331543336500.0,438727300.0,,,,10019159000.0,139671175400.0,149690334500.0,481233671000.0,,6041677900.0,,,,,,,,,,,20129300.0,19517953200.0,39817148100.0,180222875800.0,3940219400.0,62198685500.0,37463214300.0,11504994800.0,1160000000.0,,,0
|
|
||||||
300750.SZ,20220430,20220430,20220331,1,1,1,2330851200.0,43295032600.0,35580140300.0,1158471200.0,,100289630900.0,1935152000.0,1786860400.0,24877828400.0,,10100118500.0,,,61578271700.0,,227220900.0,,,,,,,8924856400.0,222276559600.0,,,12380408000.0,,,,511561200.0,56266248400.0,28893882000.0,,,,,5357768600.0,,653619200.0,1708148800.0,6201003000.0,,27208014400.0,153979092300.0,,,,,,,,,,,,,,,,,376255651900.0,33235483200.0,15403153700.0,,,,,83593860700.0,64325631500.0,,,,5529734300.0,1981850300.0,,6590800.0,,,,,,,,,7197313100.0,1449820600.0,204121679200.0,12638046700.0,,,10894420700.0,1009284700.0,12919522900.0,6466877500.0,78538624300.0,,1787115400.0,,,,,,,,,,,,,,,282660303500.0,443534900.0,,,,8384011300.0,85211337100.0,93595348500.0,376255651900.0,,3290376800.0,,,,,,,,,,,23696100.0,15050335800.0,26664688800.0,147919492200.0,4267155900.0,56266248400.0,28893882000.0,7802863800.0,1010000000.0,,,1
|
|
||||||
300750.SZ,20220422,20220422,20211231,1,1,4,2330851200.0,43163696500.0,34095467500.0,1158471200.0,,89071889700.0,1363972900.0,1463828000.0,23753548200.0,3114909600.0,6466439300.0,,,40199691900.0,,201655900.0,,,,,,,5292231900.0,177734938700.0,,,10949033600.0,,,,619282400.0,41275333300.0,30998159500.0,,,,,4479606400.0,,527850700.0,1264339100.0,5542554400.0,,20575419100.0,129931922300.0,,,,243105100.0,,,,,,,,,,,,,307666860900.0,22119078800.0,12123056900.0,,,,,58405751300.0,48784286300.0,,,,5122787800.0,2403797500.0,0.0,6590800.0,6169623600.0,,,,,,,,3548532800.0,1242490300.0,149344832600.0,15855052000.0,1010000000.0,0.0,9953762700.0,1038576900.0,12099359100.0,3228720400.0,65699853800.0,,,,,,,,,,,,,,,,,215044686400.0,443534900.0,,,,8108903200.0,84513271300.0,92622174500.0,307666860900.0,,4208319800.0,,,,,,,,,,,77285500.0,11537915300.0,25217376200.0,107190037600.0,3114909600.0,41275333300.0,30998159500.0,6176214400.0,1010000000.0,,,0
|
|
||||||
300750.SZ,20211028,20211028,20210930,1,1,3,2329007802.0,41512967187.03,25859863285.73,1157782633.55,,80735121590.38,1754005408.73,5863666031.21,14340032235.16,,3282854834.31,,,34961665056.94,,176775294.63,,,,,,,3689743310.86,149294839099.23,,,10031478677.96,,,,521066919.71,31850222746.77,21495217684.82,,,,,3530624985.15,,349692478.44,755110152.8,4311764310.21,,21438993970.78,99856957130.14,,,,1679344985.15,,,,,,,,,,,,,249151796229.37,17159358715.27,8648141083.6,,,,,45594390099.07,32631866194.43,,,,3538683641.3,2171709495.66,,10638731.54,,,,,,,,,1572686982.26,1152044044.4,114496862624.12,17528377295.31,,,10171233831.28,360049010.39,7944056738.7,,54472495682.41,,,,,,,,,,,,,,,,,168969358306.53,443534934.1,,,,7487789886.43,72694648036.41,80182437922.84,249151796229.37,,2278562062.2,,,,,,,,,,,77075924.92,13196959051.03,20203698266.37,78226256293.5,2734554426.94,31850222746.77,21495217684.82,5990382032.37,1171669290.75,,,0
|
|
||||||
300750.SZ,20211028,20211028,20210930,1,1,3,2329007802.0,41512967187.03,25859863285.73,1157782633.55,,80735121590.38,1754005408.73,5863666031.21,14340032235.16,,3282854834.31,,,34961665056.94,,176775294.63,,,,,,,3689743310.86,149294839099.23,,,10031478677.96,,,,521066919.71,31850222746.77,21495217684.82,,,,,3530624985.15,,349692478.44,755110152.8,4311764310.21,,21438993970.78,99856957130.14,,,,1679344985.15,,,,,,,,,,,,,249151796229.37,17159358715.27,8648141083.6,,,,,45594390099.07,32631866194.43,,,,3538683641.3,2171709495.66,,10638731.54,,,,,,,,,1572686982.26,1152044044.4,114496862624.12,17528377295.31,,,10171233831.28,360049010.39,7944056738.7,,54472495682.41,,,,,,,,,,,,,,,,,168969358306.53,443534934.1,,,,7487789886.43,72694648036.41,80182437922.84,249151796229.37,,2278562062.2,,,,,,,,,,,77075924.92,13196959051.03,20203698266.37,78226256293.5,2734554426.94,31850222746.77,21495217684.82,5990382032.37,1171669290.75,,,1
|
|
||||||
300750.SZ,20210826,20210826,20210630,1,1,2,2329007802.0,41446874263.9,22565878445.75,1157782633.55,,74686697280.12,2214851732.73,5485309961.18,13981824366.21,4058611364.67,3848415008.73,,,24165705805.13,,143447332.7,,,,,,,3150312575.08,132996356932.87,,,9240532691.61,,,,463424807.46,25132132439.37,15450275778.57,0.0,0.0,,,3395293147.7,,329506902.78,478944306.35,3890656231.9,,12646811292.58,74787140887.04,,,,1184105581.4,,,,,,,,,,,,,207783497819.91,8701599250.29,7936400830.37,,,,,33850033847.32,25670496056.42,,,,3023749746.8,1454565477.15,0.0,565000646.18,6879740238.9,,,,,,,,1493766156.37,1057174566.45,92689792739.55,14273326292.78,1150000000.0,0.0,8709869807.16,235972124.69,6400308476.35,,39605688511.2,,,,,,,,,,,,,,,,,132295481250.75,693512300.6,,,,6729713769.57,68758302799.59,75488016569.16,207783497819.91,,1952271954.99,,,,,,,,,,,77075924.92,10758865173.59,19467134327.39,59520529903.74,4058611364.67,25132132439.37,15450275778.57,7444740885.08,1150000000.0,,,0
|
|
||||||
300750.SZ,20210430,20210430,20210331,1,1,1,2329474028.0,41380785863.11,20595335940.37,1157782633.55,,71677310067.0,1774375580.91,9447306209.1,12260857992.64,,1983836972.02,,,17194779915.91,,46920942.02,,,,,,,1777499958.73,120622316843.24,,,5574560949.21,,,,497767224.94,20760089316.68,5602125260.39,,,,,2527779959.26,,147951887.23,420276294.97,3497853311.61,,11262011782.97,52706588084.12,,,,727619072.06,,,,,,,,,,,,,173328904927.36,7046382303.41,6213829887.31,,,,,23346295000.95,17844739699.91,,,,3098793999.64,1336465854.43,,6172824.12,,,,,,,,,1473265562.64,904377178.92,66877122610.85,14339029833.92,,,7708599437.28,54350808.15,4674614610.02,,35110766315.06,,,,,,,,,,,,,,,,,101987888925.91,710020552.82,,,,5696780374.85,65644235626.6,71341016001.45,173328904927.36,,890877714.39,,,,,,,,,,,75269024.76,8125493258.78,21708164201.74,41191034700.86,3656541108.09,20760089316.68,5602125260.39,4533862168.27,1150000000.0,,,0
|
|
||||||
300750.SZ,20210430,20210430,20210331,1,1,1,2329474028.0,41380785863.11,20595335940.37,1157782633.55,,71677310067.0,1774375580.91,9447306209.1,12260857992.64,,1983836972.02,,,17194779915.91,,46920942.02,,,,,,,1777499958.73,120622316843.24,,,5574560949.21,,,,497767224.94,20760089316.68,5602125260.39,,,,,2527779959.26,,147951887.23,420276294.97,3497853311.61,,11262011782.97,52706588084.12,,,,727619072.06,,,,,,,,,,,,,173328904927.36,7046382303.41,6213829887.31,,,,,23346295000.95,17844739699.91,,,,3098793999.64,1336465854.43,,6172824.12,,,,,,,,,1473265562.64,904377178.92,66877122610.85,14339029833.92,,,7708599437.28,54350808.15,4674614610.02,,35110766315.06,,,,,,,,,,,,,,,,,101987888925.91,710020552.82,,,,5696780374.85,65644235626.6,71341016001.45,173328904927.36,,890877714.39,,,,,,,,,,,75269024.76,8125493258.78,21708164201.74,41191034700.86,3656541108.09,20760089316.68,5602125260.39,4533862168.27,1150000000.0,,,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,2329474028.0,41662151603.08,18640918703.75,1157782633.55,,68424116053.67,3288071512.61,9877156349.23,11293523722.88,3303956813.15,997118630.25,,,13224640950.39,,81548616.67,,,,,,,969240539.21,112864989321.68,,,4813072905.14,,,,372156591.66,19621648443.02,5750351820.37,,,,,2517935725.46,,147951887.23,363551716.95,3167109948.33,,5002631587.8,43753437618.91,,,,1330347108.86,,,,,,,,,,,,,156618426940.59,6068163254.2,6335080182.17,,,,,15636589526.9,15634844308.52,,,,2657564914.42,1321059090.43,0.0,6172824.12,4401603465.43,,,,,,,,1349038696.49,760008999.58,54977189803.22,14382255950.87,1193938630.3,0.0,6797704877.32,85518810.08,3918939197.71,,32446520720.48,,,,,,,,,,,,,,,,,87423710523.7,710020552.82,,,,4987417050.31,64207299366.58,69194716416.89,156618426940.59,,1126992951.02,,,,,,,,,,,75269024.76,6875227795.16,21170680072.11,31271433835.42,3303956813.15,19621648443.02,5750351820.37,4407776289.55,1193938630.3,,,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,2329474028.0,41662151603.08,18640918703.75,1157782633.55,,68424116053.67,3288071512.61,9877156349.23,11293523722.88,3303956813.15,997118630.25,,,13224640950.39,,81548616.67,,,,,,,969240539.21,112864989321.68,,,4813072905.14,,,,372156591.66,19621648443.02,5750351820.37,,,,,2517935725.46,,147951887.23,363551716.95,3167109948.33,,5002631587.8,43753437618.91,,,,1330347108.86,,,,,,,,,,,,,156618426940.59,6068163254.2,6335080182.17,,,,,15636589526.9,15634844308.52,,,,2657564914.42,1321059090.43,0.0,6172824.12,4401603465.43,,,,,,,,1349038696.49,760008999.58,54977189803.22,14382255950.87,1193938630.3,0.0,6797704877.32,85518810.08,3918939197.71,,32446520720.48,,,,,,,,,,,,,,,,,87423710523.7,710020552.82,,,,4987417050.31,64207299366.58,69194716416.89,156618426940.59,,1126992951.02,,,,,,,,,,,75269024.76,6875227795.16,21170680072.11,31271433835.42,3303956813.15,19621648443.02,5750351820.37,4407776289.55,1193938630.3,,,0
|
|
||||||
300750.SZ,20201028,20201028,20200930,1,1,3,2329474028.0,41267668240.95,16477692586.43,1097245469.55,,66437209386.46,1967213405.45,6851381952.07,8988062513.02,,655033779.17,,,9346975874.54,,,,,,,,,1416333485.15,101740472119.2,,,2311733016.79,,,,,17198092089.37,5656172336.78,,,,,2470422536.68,,147951887.23,342491525.84,2535329791.94,,3877580433.51,36028386135.32,,,,1155305887.36,,,,,,,,,,,,,137768858254.52,5419429150.29,4361165244.81,,,,,11510910950.46,11093220985.42,,,,1653018543.8,933795455.63,,14380319.72,,,,,,,,,1356368401.84,581206979.29,40542341632.86,14761040736.73,,,6048903332.43,121078988.67,3564969995.83,,30644786719.55,,,,,,,,,,,,,,,,,71187128352.41,709694163.22,,,,5225460213.39,61356269688.72,66581729902.11,137768858254.52,,893883527.01,,,,,,,,,,,,5417110399.38,15839444465.09,22604131935.88,4922955835.98,17198092089.37,5656172336.78,3635544672.23,729364515.6,,,0
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,2207113780.0,21714813493.64,15032163142.9,1097245469.55,,37571034186.03,874307109.33,5391856244.26,7771501102.25,4229576026.07,551171111.25,,,9120702363.9,,,,,,,,,1319042475.94,68130152338.81,,,1527611204.58,,,,,16402618133.36,3430354308.42,0.0,0.0,,,2423107313.8,,147951887.23,359696314.61,2350468845.86,,3992774774.45,31906951088.14,,,,1300961719.78,,,,,,,,,,,,,100037103426.95,6723868093.75,2876186024.14,,,,,12821286467.94,7438880488.43,,,,1386927107.57,662849296.73,0.0,17042223.28,4208329087.55,,,,,,,,1154945481.02,458181632.25,35466989734.91,4582049677.92,713971319.27,0.0,6101214728.99,77630155.57,1619553975.47,,19818287950.97,,,,,,,,,,,,,,,,,55285277685.88,1029206052.4,,,,5078667240.51,39673158500.56,44751825741.07,100037103426.95,,651028666.87,,,,,,,,,,,,4442361926.0,13163357346.51,20260166956.37,4229576026.07,16402618133.36,3430354308.42,4225371310.83,713971319.27,,,0
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,2207113780.0,21714813493.64,15032163142.9,1097245469.55,,37571034186.03,874307109.33,5391856244.26,7771501102.25,4229576026.07,551171111.25,,,9120702363.9,,,,,,,,,1319042475.94,68130152338.81,,,1527611204.58,,,,,16402618133.36,3430354308.42,0.0,0.0,,,2423107313.8,,147951887.23,359696314.61,2350468845.86,,3992774774.45,31906951088.14,,,,1300961719.78,,,,,,,,,,,,,100037103426.95,6723868093.75,2876186024.14,,,,,12821286467.94,7438880488.43,,,,1386927107.57,662849296.73,0.0,17042223.28,4208329087.55,,,,,,,,1154945481.02,458181632.25,35466989734.91,4582049677.92,713971319.27,0.0,6101214728.99,77630155.57,1619553975.47,,19818287950.97,,,,,,,,,,,,,,,,,55285277685.88,1029206052.4,,,,5078667240.51,39673158500.56,44751825741.07,100037103426.95,,651028666.87,,,,,,,,,,,,4442361926.0,13163357346.51,20260166956.37,4229576026.07,16402618133.36,3430354308.42,4225371310.83,713971319.27,,,1
|
|
||||||
300750.SZ,20200428,20200428,20200331,1,1,1,2208399700.0,21690483383.4,14322773169.6,1097245469.55,,37110260152.45,1368845782.86,6958116041.84,7844668160.97,,766901403.45,,,10193303476.8,,,,,,,,,1445792765.06,71654624828.61,,,1520944749.97,,,,,16936823089.92,1756814917.99,,,,,2331373470.76,,147951887.23,375597490.81,2277794465.42,,3179996567.8,29781840068.04,,,,1087997373.15,,,,,,,,,,,,,101436464896.65,5717526586.79,2489349924.44,,,,,16185682771.99,7573283671.28,,,,1615223768.07,722158365.68,,2418687.95,,,,,,,,,1159645442.09,,39832505062.62,4539302834.76,,,5756547909.56,53697173.7,1595065700.99,,18359783488.16,,,,,,,,,,,,,,,,,58192288550.78,1074894790.0,,,,4469433925.84,38774742420.03,43244176345.87,101436464896.65,,530735487.48,,,,,,,,,,,,4948467629.29,14802784202.81,23758966443.27,4878739672.03,16936823089.92,1756814917.99,5138693489.78,697643282.36,,,1
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,2208399700.0,21630448577.59,13652965292.41,1097245469.55,,32269635327.07,1389585592.37,9649949692.85,8338535645.35,4568565748.8,538163094.42,,,11480549879.88,,,,,,,,,1647816662.94,71694937173.28,,,1540452827.51,,,,,17417348593.44,1996524778.01,,,,,2302317207.14,,147951887.23,394096018.07,2079210533.02,,2248533970.82,29657039538.04,,,,1812135529.6,,,,,,,,,,,,,101351976711.32,4980563181.26,2125646681.77,,,,286915936.0,17420197790.4,10692137500.67,6161443242.83,,,1582275521.53,962984568.04,,2418687.95,5295890304.78,,,,,,,,1077468495.09,,45607378729.06,1508339195.7,873618580.61,,5289773262.4,91191949.71,813236654.86,,13556722824.54,,,,,,,,,,,,,,,,,59164101553.6,1074894790.0,,,,4052891263.24,38134983894.48,42187875157.72,101351976711.32,,620819644.93,,,,,,,,,,,,,17988485338.2,28112335291.07,4568565748.8,17417348593.44,1996524778.01,5298308992.73,873618580.61,,,0
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,2208399700.0,21630448577.59,13652965292.41,1097245469.55,,32269635327.07,1389585592.37,9649949692.85,8338535645.35,4568565748.8,538163094.42,,,11480549879.88,,,,,,,,,1647816662.94,71694937173.28,,,1540452827.51,,,,,17417348593.44,1996524778.01,,,,,2302317207.14,,147951887.23,394096018.07,2079210533.02,,2248533970.82,29657039538.04,,,,1812135529.6,,,,,,,,,,,,,101351976711.32,4980563181.26,2125646681.77,,,,286915936.0,17420197790.4,10692137500.67,6161443242.83,,,1582275521.53,962984568.04,,2418687.95,5295890304.78,,,,,,,,1077468495.09,,45607378729.06,1508339195.7,873618580.61,,5289773262.4,91191949.71,813236654.86,,13556722824.54,,,,,,,,,,,,,,,,,59164101553.6,1074894790.0,,,,4052891263.24,38134983894.48,42187875157.72,101351976711.32,,620819644.93,,,,,,,,,,,,,17988485338.2,28112335291.07,4568565748.8,17417348593.44,1996524778.01,5298308992.73,873618580.61,,,1
|
|
||||||
300750.SZ,20191026,20191026,20190930,1,1,3,2208399700.0,21521985575.3,12667619429.06,985878418.69,,33352339595.99,287810000.0,8710491739.55,9700597153.15,,2361924059.73,,139542854.11,10005326799.83,,,,,,,,,1167260929.19,68689001550.95,,,1176625150.34,,,,,16885925397.99,2831712605.56,,,,,1518584142.91,,100419270.78,341847641.95,2055036261.06,,1118431570.76,27622355108.0,,,,1487576248.68,,,,,,,,,,,,,96311356658.95,4630256269.72,1340563717.48,,,,314247518.1,17244910400.54,10889184263.67,7212285097.05,,,1519823498.03,1213384710.92,29996067.26,2418687.95,3179532040.92,,,,,,,,917868306.62,,43864214308.54,,,,5579606717.14,177088163.04,653515298.16,,11957626010.3,,,,,,,,,,,,,,,,,55821840318.84,1074894790.0,,,,3545602822.65,36943913517.46,40489516340.11,96311356658.95,,634925184.41,,,,,,,,,,,,,18411088892.7,28134094664.21,1615675024.83,16885925397.99,2831712605.56,3211946796.13,917159562.24,,,1
|
|
||||||
300750.SZ,20190824,20190824,20190630,1,1,2,2194445000.0,20966274995.41,11305749304.2,985878418.69,,32556486370.73,58980000.0,9444111464.19,8193892175.59,824534244.85,1029818178.9,2452287.27,177853201.6,9623692125.75,,,,,,,,,1233554253.66,63881882652.5,,,947416921.82,,,,,14883961290.06,3506528066.14,,,,,1555293801.94,,100419270.78,316656012.08,1736570054.02,,1425909205.95,26006748934.49,,,,736508349.96,,,,,,,,,,,,,89888631586.99,3638729122.03,1294039502.4,,,,314247518.1,17059577651.6,10098811857.43,7534909203.04,,,1317233803.46,803066668.27,22426699.31,311692470.8,2664652254.88,,,,,,,,830307415.47,,42250965044.76,,925232995.13,,4313623912.01,58389832.13,635800994.99,,9571776856.29,,,,,,,,,,,,,,,,,51822741901.05,773581200.0,,,,3488400716.48,34577488969.46,38065889685.94,89888631586.99,,-101277548.84,,,,,,,,,,,,,17638003639.78,27158389509.03,1004839733.72,14883961290.06,3506528066.14,2998771424.99,925232995.13,,,0
|
|
||||||
300750.SZ,20190427,20190427,20190331,1,1,1,2195017400.0,21452320895.65,10562239859.25,985878418.69,,32224951522.9,37900000.0,9162783167.49,7933064764.17,,1153320036.04,,182452713.88,7686537622.67,,,,,,,,,870074607.47,60520697494.05,,,1047709787.58,,,,,12718283064.26,4002146735.88,,,,,1331981184.25,,100419270.78,320180603.51,1481495508.21,,1008321047.6,23580574965.47,,,,652958907.43,,,,,,,,,,,,,84101272459.52,3394334761.13,1403970598.49,,,,314247518.1,,,5404891136.69,,,1336293223.26,1122299621.77,20963013.91,,,,,,,,,,990251685.25,,38597161467.45,,,,3507541924.93,41726802.59,626870612.25,,8505238976.51,,,,,,,,,,,,,,,,,47102400443.96,793701060.0,,,,2772478669.16,34226393346.4,36998872015.56,84101272459.52,,-175362167.19,,,,,,,,,,,,,17095847931.66,24124867219.59,799106865.88,12718283064.26,4002146735.88,3900340464.3,934764875.61,,,0
|
|
||||||
300750.SZ,20190427,20190427,20190331,1,1,1,2195017400.0,21452320895.65,10562239859.25,985878418.69,,32224951522.9,37900000.0,9162783167.49,7933064764.17,,1153320036.04,,182452713.88,7686537622.67,,,,,,,,,870074607.47,60520697494.05,,,1047709787.58,,,,,12718283064.26,4002146735.88,,,,,1331981184.25,,100419270.78,320180603.51,1481495508.21,,1008321047.6,23580574965.47,,,,652958907.43,,,,,,,,,,,,,84101272459.52,3394334761.13,1403970598.49,,,,314247518.1,,,5404891136.69,,,1336293223.26,1122299621.77,20963013.91,,,,,,,,,,990251685.25,,38597161467.45,,,,3507541924.93,41726802.59,626870612.25,,8505238976.51,,,,,,,,,,,,,,,,,47102400443.96,793701060.0,,,,2772478669.16,34226393346.4,36998872015.56,84101272459.52,,-175362167.19,,,,,,,,,,,,,17095847931.66,24124867219.59,799106865.88,12718283064.26,4002146735.88,3900340464.3,934764875.61,,,1
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,2195017400.0,21372918712.25,9515006632.3,985878418.69,,27731189739.92,,9742890628.44,6224857396.53,589281314.94,864640798.47,,92808117.05,7076101849.47,,,,,,,,,1076991664.73,53911422755.37,1516521098.2,,965198180.81,,,,,11574665757.11,1623838222.94,,,,,1346171137.42,,100419270.78,305828515.4,1240737742.63,,1298901335.85,19972281261.14,,,,512661245.82,,,,,,,,,,,,,73883704016.51,3490767815.96,1180092100.11,,,,314247518.1,11841128076.55,7057075077.4,4994400867.91,,,1122253456.83,722536564.72,19842845.23,,2904341329.33,,,,,,,,929024032.37,,31084941868.55,,943414523.31,,2512382681.52,40984489.33,611042047.22,,7598591557.34,,,,,,,,,,,,,,,,,38683533425.89,793701060.0,,,,2261889695.31,32938280895.31,35200170590.62,73883704016.51,,-336839207.93,,,,,,,,,,,,,15967748024.97,18898203153.95,682089431.99,11574665757.11,1623838222.94,2924184174.56,943414523.31,,,0
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,2195017400.0,21372918712.25,9515006632.3,985878418.69,,27731189739.92,,9742890628.44,6224857396.53,589281314.94,864640798.47,,92808117.05,7076101849.47,,,,,,,,,1076991664.73,53911422755.37,1516521098.2,,965198180.81,,,,,11574665757.11,1623838222.94,,,,,1346171137.42,,100419270.78,305828515.4,1240737742.63,,1298901335.85,19972281261.14,,,,512661245.82,,,,,,,,,,,,,73883704016.51,3490767815.96,1180092100.11,,,,314247518.1,11841128076.55,7057075077.4,4994400867.91,,,1122253456.83,722536564.72,19842845.23,,2904341329.33,,,,,,,,929024032.37,,31084941868.55,,943414523.31,,2512382681.52,40984489.33,611042047.22,,7598591557.34,,,,,,,,,,,,,,,,,38683533425.89,793701060.0,,,,2261889695.31,32938280895.31,35200170590.62,73883704016.51,,-336839207.93,,,,,,,,,,,,,15967748024.97,18898203153.95,682089431.99,11574665757.11,1623838222.94,2924184174.56,943414523.31,,,1
|
|
||||||
300750.SZ,20181026,20181026,20180930,1,1,3,2195017400.0,21332400491.65,8854096176.97,638253676.69,,23009873374.81,,4105020050.57,9849744045.57,,453947445.22,,,5286472060.07,,,,,,,,,1368390591.89,45173587344.33,1749328770.25,,984646309.7,,,,,10313102145.17,2612119399.87,,,,,1362641804.84,,100419270.78,176881170.51,902206805.13,,415681574.9,18617027251.15,,,,416495571.63,,,,,,,,,,,,,63790614595.48,3245327066.37,1248978938.95,,,,,,,1704582797.09,,,596544931.31,705588018.28,,,,,,,,,,,826658774.41,,21825445438.14,,,,2821540586.26,42052130.71,360701916.84,,7437101080.2,,,,,,,,,,,,,,,,,29262546518.34,793701060.0,,,,2226764875.78,32301303201.36,34528068077.14,63790614595.48,,75236516.05,,,,,,,,,,,,,13954764096.14,15096667354.42,683644204.57,10313102145.17,2612119399.87,1646424623.68,967479380.02,,,1
|
|
||||||
300750.SZ,20181026,20181026,20180930,1,1,3,2195017400.0,21332400491.65,8854096176.97,638253676.69,,23009873374.81,,4105020050.57,9849744045.57,,453947445.22,,,5286472060.07,,,,,,,,,1368390591.89,45173587344.33,1749328770.25,,984646309.7,,,,,10313102145.17,2612119399.87,,,,,1362641804.84,,100419270.78,176881170.51,902206805.13,,415681574.9,18617027251.15,,,,416495571.63,,,,,,,,,,,,,63790614595.48,3245327066.37,1248978938.95,,,,,,,1704582797.09,,,596544931.31,705588018.28,,,,,,,,,,,826658774.41,,21825445438.14,,,,2821540586.26,42052130.71,360701916.84,,7437101080.2,,,,,,,,,,,,,,,,,29262546518.34,793701060.0,,,,2226764875.78,32301303201.36,34528068077.14,63790614595.48,,75236516.05,,,,,,,,,,,,,13954764096.14,15096667354.42,683644204.57,10313102145.17,2612119399.87,1646424623.68,967479380.02,,,0
|
|
||||||
300750.SZ,20180824,20180824,20180630,1,1,2,2172437000.0,20520157651.05,7415859086.9,638253676.69,,17800002418.59,,2571239620.97,8528717101.73,474148632.84,678003502.29,,64274152.08,4919942324.71,,,,,,,,,2632034286.33,37691162710.81,1729158500.0,,913752605.6,,,,,9819507470.69,2645070047.6,,,,,1384785545.17,,100419270.78,158460787.9,708272329.32,,293403603.49,17752830160.55,,,,22800671.27,,,,,,,,,,,,,55443992871.36,3194631603.51,1401956157.12,,,,,6675843483.7,5740618051.51,349064690.97,,,524449445.7,271459638.63,16260284.94,,283008992.25,,,,,,,,785188697.21,,16047849442.03,,899399594.33,,2018155174.56,34549547.01,425180664.33,,6571916583.74,,,,,,,,,,,,,,,,,22619766025.77,,,,,2005370552.71,30818856292.88,32824226845.59,55443992871.36,,72148878.24,,,,,,,,,,,,,11099956722.7,12416461535.21,538422784.92,9819507470.69,2645070047.6,299269277.19,899399594.33,,,1
|
|
||||||
300750.SZ,20180824,20180824,20180630,1,1,2,2172437000.0,20520157651.05,7415859086.9,638253676.69,,17800002418.59,,2571239620.97,8528717101.73,474148632.84,678003502.29,,64274152.08,4919942324.71,,,,,,,,,2632034286.33,37691162710.81,1729158500.0,,913752605.6,,,,,9819507470.69,2645070047.6,,,,,1384785545.17,,100419270.78,158460787.9,708272329.32,,293403603.49,17752830160.55,,,,22800671.27,,,,,,,,,,,,,55443992871.36,3194631603.51,1401956157.12,,,,,6675843483.7,5740618051.51,349064690.97,,,524449445.7,271459638.63,16260284.94,,283008992.25,,,,,,,,785188697.21,,16047849442.03,,899399594.33,,2018155174.56,34549547.01,425180664.33,,6571916583.74,,,,,,,,,,,,,,,,,22619766025.77,,,,,2005370552.71,30818856292.88,32824226845.59,55443992871.36,,72148878.24,,,,,,,,,,,,,11099956722.7,12416461535.21,538422784.92,9819507470.69,2645070047.6,299269277.19,899399594.33,,,0
|
|
||||||
300750.SZ,20180522,20180522,20180331,1,1,1,1955193267.0,15374442887.79,6918251958.12,638253676.69,,9676141216.63,,7527750188.08,6715688989.42,149376993.55,847303512.7,,47382489.87,4113040896.1,,,,,,,,,1558593622.51,30651507998.01,1962716000.0,,780030501.29,,,,,8446673663.32,3122587039.87,,,,,1390279968.16,,100419270.78,163939750.97,580079605.61,,625001731.36,17171727531.36,,,,16230089.15,,,,,,,,,,,,,47823235529.37,2755256273.24,1163670014.17,,,,,7362937604.85,4308621518.19,518067888.02,,,509591839.94,306609488.43,16269159.28,,296573893.69,,,,,,,,449364718.01,,14931706124.58,,894088692.78,,1787562369.82,69115257.32,404289790.79,,5910312383.95,,,,,,,,,,,,,,,,,20842018508.53,,,,,1843395945.35,25137821075.49,26981217020.84,47823235529.37,,251679285.89,,,,,,,,,,,,,14243439177.5,11671559123.04,196759483.42,8446673663.32,3122587039.87,312843052.97,894088692.78,,,0
|
|
||||||
300750.SZ,20180522,20180522,20171231,1,1,4,1955193267.0,15354587816.94,6504904798.9,638253676.69,,14080936626.3,,5458335290.35,6918521550.9,90630850.1,305835456.79,,52310504.72,3417757092.32,,,,,,,,,2695030983.77,33033102914.27,1961291000.0,,791027220.9,,,,,8219496581.74,2974364031.46,,,,,1408760249.33,,100419270.78,139310483.53,510045198.34,,525068808.1,16629782844.18,,,,13744559.02,,,,,,,,,,,,,49662885758.45,2129095275.13,2245096000.7,,,,,8812715586.2,4978257325.43,203165478.74,,,517308034.99,436196766.94,15205262.28,,317156883.9,,,,,,,,364944599.97,,17890045939.15,,895045177.66,,1789007284.61,68992112.81,419460871.47,,5301600721.68,,,,,,,,,,,,,,,,,23191646660.83,,,,,1769799526.51,24701439571.11,26471239097.62,49662885758.45,,248500011.58,,,,,,,,,,,,,12376856841.25,13790972911.63,142941354.82,8219496581.74,2974364031.46,332362146.18,895045177.66,,,0
|
|
||||||
300750.SZ,20180522,20180522,20171231,1,1,4,1955193267.0,15354587816.94,6504904798.9,638253676.69,,14080936626.3,,5458335290.35,6918521550.9,90630850.1,305835456.79,,52310504.72,3417757092.32,,,,,,,,,2695030983.77,33033102914.27,1961291000.0,,791027220.9,,,,,8219496581.74,2974364031.46,,,,,1408760249.33,,100419270.78,139310483.53,510045198.34,,525068808.1,16629782844.18,,,,13744559.02,,,,,,,,,,,,,49662885758.45,2129095275.13,2245096000.7,,,,,8812715586.2,4978257325.43,203165478.74,,,517308034.99,436196766.94,15205262.28,,317156883.9,,,,,,,,364944599.97,,17890045939.15,,895045177.66,,1789007284.61,68992112.81,419460871.47,,5301600721.68,,,,,,,,,,,,,,,,,23191646660.83,,,,,1769799526.51,24701439571.11,26471239097.62,49662885758.45,,248500011.58,,,,,,,,,,,,,12376856841.25,13790972911.63,142941354.82,8219496581.74,2974364031.46,332362146.18,895045177.66,,,1
|
|
||||||
300750.SZ,20171110,20171110,20170630,1,1,2,1955193267.0,15073392635.47,4992362867.75,299841288.9,,1817625421.27,,2875309020.6,6005154594.85,129673951.35,156199612.05,,89547067.51,3955037968.76,,,,,,,,,11660834659.89,26689382296.28,1547503500.0,,310725425.65,,,,,5635475096.25,4237842734.96,,,,,1162449058.99,,100419270.78,48928917.03,332451118.62,,818438956.14,14194234078.42,,,,,,,,,,,,,,,,,40883616374.7,719950000.0,1257975977.42,,,,,5427777223.94,6190098389.53,192644288.31,,,402945039.76,396746820.17,8666706.59,,361005463.17,,,,,,,,129784955.93,,14367644864.82,,913849883.01,,1268416291.8,82065980.53,377532756.18,,3361814911.52,,,,,,,,,,,,,,,,,17729459776.34,,,,,519861419.41,22634295178.95,23154156598.36,40883616374.7,,313505119.83,,,,,,,,,,,,,8880463615.45,11617875613.47,219221018.86,5635475096.25,4237842734.96,369672169.76,913849883.01,,,0
|
|
||||||
300750.SZ,20171110,20171110,20170630,1,1,2,1955193267.0,15073392635.47,4992362867.75,299841288.9,,1817625421.27,,2875309020.6,6005154594.85,129673951.35,156199612.05,,89547067.51,3955037968.76,,,,,,,,,11660834659.89,26689382296.28,1547503500.0,,310725425.65,,,,,5635475096.25,4237842734.96,,,,,1162449058.99,,100419270.78,48928917.03,332451118.62,,818438956.14,14194234078.42,,,,,,,,,,,,,,,,,40883616374.7,719950000.0,1257975977.42,,,,,5427777223.94,6190098389.53,192644288.31,,,402945039.76,396746820.17,8666706.59,,361005463.17,,,,,,,,129784955.93,,14367644864.82,,913849883.01,,1268416291.8,82065980.53,377532756.18,,3361814911.52,,,,,,,,,,,,,,,,,17729459776.34,,,,,519861419.41,22634295178.95,23154156598.36,40883616374.7,,313505119.83,,,,,,,,,,,,,8880463615.45,11617875613.47,219221018.86,5635475096.25,4237842734.96,369672169.76,913849883.01,,,1
|
|
||||||
300750.SZ,20180522,20180522,20161231,1,1,4,613321800.0,11608553987.09,2965362316.99,299841288.9,,2456530834.16,,570522837.1,7315840024.05,183806946.21,101183102.22,,7564477.11,1359772316.12,,,,,,,,,9760704235.56,21761324772.53,143400000.0,,169658176.39,,,,,3727473865.79,1226129855.44,,,,,621645950.26,,100419270.78,14206421.31,264912007.47,,559144024.11,6826989571.55,,,,,,,,,,,,,,,,,28588314344.08,302000000.0,1226587998.8,,,,,4394039468.71,3173395264.55,87727135.56,,,446249267.28,248297683.21,5776292.16,,360240077.32,,,,,,,,240511234.77,,10182824422.36,,950079201.39,,930580458.65,28130130.54,403581087.31,,2614370877.89,,,,,,,,,,,,,,,,,12797195300.25,,,,,302472760.51,15488646283.32,15791119043.83,28588314344.08,,1566890.34,,,,,,,5400000.0,,,,,,7886362861.15,7567434733.26,191371423.32,3727473865.79,1226129855.44,366016369.48,950079201.39,,,0
|
|
||||||
300750.SZ,20180522,20180522,20161231,1,1,4,613321800.0,11608553987.09,2965362316.99,299841288.9,,2456530834.16,,570522837.1,7315840024.05,183806946.21,101183102.22,,7564477.11,1359772316.12,,,,,,,,,9760704235.56,21761324772.53,143400000.0,,169658176.39,,,,,3727473865.79,1226129855.44,,,,,621645950.26,,100419270.78,14206421.31,264912007.47,,559144024.11,6826989571.55,,,,,,,,,,,,,,,,,28588314344.08,302000000.0,1226587998.8,,,,,4394039468.71,3173395264.55,87727135.56,,,446249267.28,248297683.21,5776292.16,,360240077.32,,,,,,,,240511234.77,,10182824422.36,,950079201.39,,930580458.65,28130130.54,403581087.31,,2614370877.89,,,,,,,,,,,,,,,,,12797195300.25,,,,,302472760.51,15488646283.32,15791119043.83,28588314344.08,,1566890.34,,,,,,,5400000.0,,,,,,7886362861.15,7567434733.26,191371423.32,3727473865.79,1226129855.44,366016369.48,950079201.39,,,1
|
|
||||||
300750.SZ,20161001,20161001,20160630,1,1,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12726241200.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10186685700.0,,,,,,2539555500.0,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20161001,20161001,20160630,1,1,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12726241200.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10186685700.0,,,,,,2539555500.0,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20160729,20160729,20160331,1,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,11042108000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9037644600.0,,,,,,2004463400.0,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20180522,20180522,20151231,1,1,4,470590000.0,369014163.84,376303017.19,37079169.44,,1292935327.52,,422182294.7,2393930005.73,55484188.21,70469398.58,,,1041611188.85,,,,,,,,,227855161.28,5504467564.87,5000000.0,,,,,,,1313098299.52,474893794.61,,6710.03,,,502758023.88,,100419270.78,6133369.98,135241432.42,,630939035.37,3168489936.59,,,,,,,,,,,,,,,,,8672957501.46,,576558942.87,,,,,1041204473.76,1472399950.48,170045760.44,,,198490932.79,252617557.72,3639309.42,,311755056.01,,,,,,,,1322574459.48,,5349286442.97,,917666570.26,,581118102.95,30220779.54,296337217.09,,1825342669.84,,,,,,,,,,,,,,,,,7174629112.81,,,,,244663210.07,1253665178.58,1498328388.65,8672957501.46,,678828.11,,,,,,,,,,,,,2816112300.43,2513604424.24,55484188.21,1313105009.55,474893794.61,315394365.43,917666570.26,,,0
|
|
||||||
300750.SZ,20180522,20180522,20151231,1,1,4,470590000.0,369014163.84,376303017.19,37079169.44,,1292935327.52,,422182294.7,2393930005.73,55484188.21,70469398.58,,,1041611188.85,,,,,,,,,227855161.28,5504467564.87,5000000.0,,,,,,,1313098299.52,474893794.61,,6710.03,,,502758023.88,,100419270.78,6133369.98,135241432.42,,630939035.37,3168489936.59,,,,,,,,,,,,,,,,,8672957501.46,,576558942.87,,,,,1041204473.76,1472399950.48,170045760.44,,,198490932.79,252617557.72,3639309.42,,311755056.01,,,,,,,,1322574459.48,,5349286442.97,,917666570.26,,581118102.95,30220779.54,296337217.09,,1825342669.84,,,,,,,,,,,,,,,,,7174629112.81,,,,,244663210.07,1253665178.58,1498328388.65,8672957501.46,,678828.11,,,,,,,,,,,,,2816112300.43,2513604424.24,55484188.21,1313105009.55,474893794.61,315394365.43,917666570.26,,,1
|
|
||||||
300750.SZ,20171110,20171110,20141231,1,1,4,200000000.0,,49744909.19,6954380.45,,59580991.01,,,371591280.04,29995923.56,15325513.65,,,312078268.93,,,,,,,,,1104090329.41,1892662306.6,5000000.0,,227224101.96,,,,,242838681.05,174061216.38,,,,,237605481.13,,,302589.41,25097812.88,,70316438.57,982446321.38,,,,,,,,,,,,,,,,,2875108627.98,,197129703.88,,,,,104420606.01,384712991.47,8715160.0,,,21201376.97,30587729.51,92346.79,,62047482.54,,,,,,,,127376000.0,,936283397.17,,1344911122.2,,43656244.08,,214850053.5,,1603417419.78,,,,,,,,,,,,,,,,,2539700816.95,,,,,78524562.99,256883248.04,335407811.03,2875108627.98,,183958.4,,,,,,,,,,,,,371591280.04,489133597.48,29995923.56,242838681.05,174061216.38,62139829.33,1344911122.2,,,0
|
|
||||||
300750.SZ,20171110,20171110,20141231,1,1,4,200000000.0,,49744909.19,6954380.45,,59580991.01,,,371591280.04,29995923.56,15325513.65,,,312078268.93,,,,,,,,,1104090329.41,1892662306.6,5000000.0,,227224101.96,,,,,242838681.05,174061216.38,,,,,237605481.13,,,302589.41,25097812.88,,70316438.57,982446321.38,,,,,,,,,,,,,,,,,2875108627.98,,197129703.88,,,,,104420606.01,384712991.47,8715160.0,,,21201376.97,30587729.51,92346.79,,62047482.54,,,,,,,,127376000.0,,936283397.17,,1344911122.2,,43656244.08,,214850053.5,,1603417419.78,,,,,,,,,,,,,,,,,2539700816.95,,,,,78524562.99,256883248.04,335407811.03,2875108627.98,,183958.4,,,,,,,,,,,,,371591280.04,489133597.48,29995923.56,242838681.05,174061216.38,62139829.33,1344911122.2,,,1
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,comp_type,report_type,end_type,net_profit,finan_exp,c_fr_sale_sg,recp_tax_rends,n_depos_incr_fi,n_incr_loans_cb,n_inc_borr_oth_fi,prem_fr_orig_contr,n_incr_insured_dep,n_reinsur_prem,n_incr_disp_tfa,ifc_cash_incr,n_incr_disp_faas,n_incr_loans_oth_bank,n_cap_incr_repur,c_fr_oth_operate_a,c_inf_fr_operate_a,c_paid_goods_s,c_paid_to_for_empl,c_paid_for_taxes,n_incr_clt_loan_adv,n_incr_dep_cbob,c_pay_claims_orig_inco,pay_handling_chrg,pay_comm_insur_plcy,oth_cash_pay_oper_act,st_cash_out_act,n_cashflow_act,oth_recp_ral_inv_act,c_disp_withdrwl_invest,c_recp_return_invest,n_recp_disp_fiolta,n_recp_disp_sobu,stot_inflows_inv_act,c_pay_acq_const_fiolta,c_paid_invest,n_disp_subs_oth_biz,oth_pay_ral_inv_act,n_incr_pledge_loan,stot_out_inv_act,n_cashflow_inv_act,c_recp_borrow,proc_issue_bonds,oth_cash_recp_ral_fnc_act,stot_cash_in_fnc_act,free_cashflow,c_prepay_amt_borr,c_pay_dist_dpcp_int_exp,incl_dvd_profit_paid_sc_ms,oth_cashpay_ral_fnc_act,stot_cashout_fnc_act,n_cash_flows_fnc_act,eff_fx_flu_cash,n_incr_cash_cash_equ,c_cash_equ_beg_period,c_cash_equ_end_period,c_recp_cap_contrib,incl_cash_rec_saims,uncon_invest_loss,prov_depr_assets,depr_fa_coga_dpba,amort_intang_assets,lt_amort_deferred_exp,decr_deferred_exp,incr_acc_exp,loss_disp_fiolta,loss_scr_fa,loss_fv_chg,invest_loss,decr_def_inc_tax_assets,incr_def_inc_tax_liab,decr_inventories,decr_oper_payable,incr_oper_payable,others,im_net_cashflow_oper_act,conv_debt_into_cap,conv_copbonds_due_within_1y,fa_fnc_leases,im_n_incr_cash_equ,net_dism_capital_add,net_cash_rece_sec,credit_impa_loss,use_right_asset_dep,oth_loss_asset,end_bal_cash,beg_bal_cash,end_bal_cash_equ,beg_bal_cash_equ,update_flag
|
|
||||||
300750.SZ,20251021,20251021,20250930,1,1,3,,,338126567000.0,6320906000.0,,,,,,,,,,,,18609171000.0,363056644000.0,224120825000.0,23413386000.0,26742749000.0,,,,,,8119254000.0,282396214000.0,80660430000.0,19691000.0,4443202000.0,1942895000.0,68109000.0,27411000.0,6501309000.0,30087780000.0,31540210000.0,2045273000.0,119537000.0,,63792799000.0,-57291490000.0,30597681000.0,,1125480000.0,74995566000.0,,32237114000.0,33558798000.0,,4923115000.0,70719026000.0,4276539000.0,-621254000.0,27024225000.0,270159734000.0,297183959000.0,43272406000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20251021,20251021,20250930,1,1,3,,,338126567000.0,6320906000.0,,,,,,,,,,,,18609171000.0,363056644000.0,224120825000.0,23413386000.0,26742749000.0,,,,,,8119254000.0,282396214000.0,80660430000.0,19691000.0,4443202000.0,1942895000.0,68109000.0,27411000.0,6501309000.0,30087780000.0,31540210000.0,2045273000.0,119537000.0,,63792799000.0,-57291490000.0,30597681000.0,,1125480000.0,74995566000.0,25643519645.9636,32237114000.0,33558798000.0,1714326000.0,4923115000.0,70719026000.0,4276539000.0,-621254000.0,27024225000.0,270159734000.0,297183959000.0,43272406000.0,5488866000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20250731,20250731,20250630,1,1,2,32365447000.0,-774088000.0,222932355000.0,3345011000.0,,,,,,,,,,,,12159654000.0,238437020000.0,139969893000.0,16407674000.0,18804676000.0,,,,,,4567711000.0,179749954000.0,58687066000.0,,2026104000.0,1797958000.0,51763000.0,,3875825000.0,20212919000.0,9817644000.0,,114782000.0,,30145345000.0,-26269519000.0,24037000000.0,,152625000.0,64659939000.0,31658009450.1399,15113934000.0,27220080000.0,606327000.0,1718354000.0,44052368000.0,20607571000.0,600381000.0,53625499000.0,270159734000.0,323785232000.0,40470315000.0,2781185000.0,,2850287000.0,11355579000.0,244874000.0,667604000.0,,,-62178000.0,91385000.0,-178363000.0,-2875693000.0,-2846420000.0,-90990000.0,-13622417000.0,12126707000.0,19114641000.0,,58687066000.0,,,,53625499000.0,,,,105656000.0,,323785232000.0,270159734000.0,,,1
|
|
||||||
300750.SZ,20250415,20250415,20250331,1,1,1,,,111139836000.0,1395114000.0,,,,,,,,,,,,6572116000.0,119107066000.0,69577367000.0,7189748000.0,7120777000.0,,,,,,2350917000.0,86238809000.0,32868257000.0,,1598211000.0,183232000.0,30260000.0,,1811704000.0,10342606000.0,9131508000.0,,108144000.0,,19582258000.0,-17770554000.0,11432923000.0,,119264000.0,11787897000.0,21672458368.5059,4911352000.0,6104208000.0,98000000.0,70925000.0,11086486000.0,701411000.0,341988000.0,16141103000.0,270159734000.0,286300836000.0,235710000.0,235710000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20250315,20250315,20241231,1,1,4,54006794000.0,5165670000.0,417525378000.0,10506188000.0,,,,,,,,,,,,16847851000.0,444879417000.0,285455632000.0,25499653000.0,28529188000.0,,,,,,8404599000.0,347889072000.0,96990345000.0,963920000.0,2028899000.0,1838083000.0,75110000.0,,4906012000.0,31179943000.0,22169451000.0,244022000.0,187907000.0,,53781323000.0,-48875311000.0,30540129000.0,,292179000.0,33392735000.0,,19972240000.0,25807432000.0,496051000.0,2137299000.0,47916971000.0,-14524236000.0,-1596552000.0,31994247000.0,238165487000.0,270159734000.0,2560428000.0,1959694000.0,,8423325000.0,22437872000.0,470401000.0,1790382000.0,,,-19319000.0,257488000.0,-664223000.0,-4384806000.0,-6700359000.0,320345000.0,-16606853000.0,634969000.0,31206935000.0,,96990345000.0,,,,31994247000.0,,,872526000.0,239273000.0,,270159734000.0,238165487000.0,,,0
|
|
||||||
300750.SZ,20250315,20250315,20241231,1,1,4,54006794000.0,5165670000.0,417525378000.0,10506188000.0,,,,,,,,,,,,16847851000.0,444879417000.0,285455632000.0,25499653000.0,28529188000.0,,,,,,8404599000.0,347889072000.0,96990345000.0,963920000.0,2028899000.0,1838083000.0,75110000.0,,4906012000.0,31179943000.0,22169451000.0,244022000.0,187907000.0,,53781323000.0,-48875311000.0,30540129000.0,,292179000.0,33392735000.0,49279270654.9643,19972240000.0,25807432000.0,496051000.0,2137299000.0,47916971000.0,-14524236000.0,-1596552000.0,31994247000.0,238165487000.0,270159734000.0,2560428000.0,1959694000.0,,8423325000.0,22437872000.0,470401000.0,1790382000.0,,,-19319000.0,257488000.0,-664223000.0,-4384806000.0,-6700359000.0,320345000.0,-16606853000.0,634969000.0,31206935000.0,,96990345000.0,,,,31994247000.0,,,872526000.0,239273000.0,,270159734000.0,238165487000.0,,,1
|
|
||||||
300750.SZ,20241019,20241019,20240930,1,1,3,,,317539939100.0,8174888000.0,,,,,,,,,,,,10828118000.0,336542945100.0,220637018600.0,19328624300.0,23235105400.0,,,,,,5898595800.0,269099344000.0,67443601100.0,525584000.0,512532700.0,1472067000.0,55631200.0,,2565814800.0,21268347400.0,28950734900.0,241214500.0,,,50460296800.0,-47894481900.0,17823560900.0,,,19734321900.0,-13691482401.3572,13951582300.0,24858845700.0,496051400.0,1419576600.0,40230004500.0,-20495682600.0,-2265019600.0,-3211583000.0,238165486900.0,234953903900.0,1910761000.0,1488073700.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20241019,20241019,20240930,1,1,3,,,317539939100.0,8174888000.0,,,,,,,,,,,,10828118000.0,336542945100.0,220637018600.0,19328624300.0,23235105400.0,,,,,,5898595800.0,269099344000.0,67443601100.0,525584000.0,512532700.0,1472067000.0,55631200.0,,2565814800.0,21268347400.0,28950734900.0,241214500.0,,,50460296800.0,-47894481900.0,17823560900.0,,,19734321900.0,,13951582300.0,24858845700.0,496051400.0,1419576600.0,40230004500.0,-20495682600.0,-2265019600.0,-3211583000.0,238165486900.0,234953903900.0,1910761000.0,1488073700.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20240727,20240727,20240630,1,1,2,24878855300.0,3707393500.0,210078821800.0,5605173900.0,,,,,,,,,,,,7381135500.0,223065131100.0,144250502500.0,13195573200.0,17902671600.0,,,,,,3007429200.0,178356176500.0,44708954600.0,529335100.0,316453600.0,225161100.0,17754100.0,,1088703800.0,13830127900.0,21905527500.0,231440800.0,,,35967096200.0,-34878392400.0,15587835400.0,,,16010907800.0,391545768.4292,10135075800.0,23896998200.0,45880400.0,1154620200.0,35186694200.0,-19175786400.0,-1754412700.0,-11099637000.0,238165486900.0,227065849900.0,423072500.0,423072500.0,,2343369100.0,11284923100.0,214967000.0,647959300.0,,,-11045900.0,41648300.0,24331900.0,-2076994500.0,-3497286300.0,-274667700.0,-3421205200.0,20607642800.0,-10101595900.0,,44708954600.0,,,,-11099637000.0,,,,74912600.0,,227065849900.0,238165486900.0,,,1
|
|
||||||
300750.SZ,20240416,20240416,20240331,1,1,1,,,102413593800.0,3186710600.0,,,,,,,,,,,,4564714700.0,110165019100.0,68969931400.0,5633346700.0,5717762700.0,,,,,,1486067700.0,81807108500.0,28357910600.0,11111000.0,135950700.0,33933800.0,14951800.0,,195947300.0,7081546200.0,70746800.0,210693200.0,740816700.0,,8103803000.0,-7907855700.0,11920790200.0,,,12010688900.0,7575241365.1415,5090698600.0,813200200.0,22940200.0,602526600.0,6506425400.0,5504263600.0,-1011612600.0,24942705900.0,238165486900.0,263108192800.0,89898800.0,89898800.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20240316,20240316,20231231,1,1,4,46761034500.0,3013733800.0,417943222600.0,12739610500.0,,,,,,,,,,,,15724664000.0,446407497100.0,310521178200.0,21140596600.0,17117191500.0,,,,,,4802406300.0,353581372700.0,92826124400.0,1239798700.0,7651158400.0,1711392900.0,12853500.0,3306900.0,10618510400.0,33624896500.0,5649689400.0,321445400.0,210243200.0,,39806274600.0,-29187764200.0,46595746400.0,,366758000.0,50286500800.0,32528281889.0684,23795322000.0,9481092900.0,469828200.0,2293723300.0,35570138100.0,14716362700.0,2181446800.0,80536169700.0,157629317200.0,238165486900.0,3323996400.0,2926448200.0,,5853926900.0,21098130600.0,330992000.0,1099265800.0,,,-16983500.0,55557800.0,-46270400.0,-3825925800.0,-7809038300.0,156446100.0,31029323200.0,-34168243000.0,29013934100.0,,92826124400.0,,,,80536169700.0,,,254041400.0,117593400.0,,238165486900.0,157629317200.0,,,1
|
|
||||||
300750.SZ,20231020,20231020,20230930,1,1,3,,,298649159300.0,10179455400.0,,,,,,,,,,,,10019408600.0,318848023200.0,233164147500.0,15791826300.0,13852837500.0,,,,,,3385519700.0,266194330900.0,52653692300.0,3388378500.0,4803588500.0,1197789500.0,6339500.0,,9396095900.0,26917282900.0,2415394900.0,,547300.0,,29333225100.0,-19937129100.0,39935305000.0,,103628500.0,42049702100.0,8994946044.0122,18289107600.0,8860917300.0,469828200.0,49020400.0,27199045400.0,14850656700.0,1928720700.0,49495940500.0,157629317200.0,207125257700.0,2010768500.0,1876232800.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20230726,20230726,20230630,1,1,2,21473201500.0,345552200.0,202447361600.0,6619428100.0,,,,,,,,,,,,7066371300.0,216133160900.0,156679795700.0,10977957600.0,9392587400.0,,,,,,2012450500.0,179062791200.0,37070369800.0,3156756300.0,4324858000.0,650523900.0,,,8132138200.0,18452610700.0,1796910300.0,,,,20249521000.0,-12117382800.0,23407941000.0,,,24968247700.0,16287996540.7261,10969930700.0,7571774200.0,61328200.0,240759100.0,18782464000.0,6185783700.0,3535293800.0,34674064400.0,157629317200.0,192303381700.0,1560306700.0,1560306700.0,,1681987200.0,9460374100.0,142766900.0,497480800.0,,,-8327400.0,30353500.0,-213283400.0,-1417699300.0,-3109602300.0,-343131000.0,26530336700.0,-7684588600.0,-10687815900.0,,37070369800.0,,,,34674064400.0,,,,67709900.0,,192303381700.0,157629317200.0,,,1
|
|
||||||
300750.SZ,20230726,20230726,20230630,1,1,2,21473201500.0,345552200.0,202447361600.0,6619428100.0,,,,,,,,,,,,7066371300.0,216133160900.0,156679795700.0,10977957600.0,9392587400.0,,,,,,2012450500.0,179062791200.0,37070369800.0,3156756300.0,4324858000.0,650523900.0,,,8132138200.0,18452610700.0,1796910300.0,,,,20249521000.0,-12117382800.0,23407941000.0,,,24968247700.0,18473683340.7261,10969930700.0,7571774200.0,61328200.0,240759100.0,18782464000.0,6185783700.0,3535293800.0,34674064400.0,157629317200.0,192303381700.0,1560306700.0,1560306700.0,,1681987200.0,9460374100.0,142766900.0,497480800.0,,,-8327400.0,30353500.0,-213283400.0,-1417699300.0,-3109602300.0,-343131000.0,26530336700.0,-7684588600.0,-10687815900.0,,37070369800.0,,,,34674064400.0,,,,67709900.0,,192303381700.0,157629317200.0,,,0
|
|
||||||
300750.SZ,20230421,20230421,20230331,1,1,1,,,100373116000.0,2228192200.0,,,,,,,,,,,,3090305100.0,105691613300.0,74461164100.0,4975038100.0,4321756000.0,,,,,,967376600.0,84725334900.0,20966278500.0,641947900.0,4538242300.0,1001598900.0,,,6181789100.0,10465642800.0,1523083000.0,,,,11988725800.0,-5806936600.0,13568065400.0,,,14874732100.0,13095444235.6776,7266142400.0,1026620400.0,61328200.0,1224165000.0,9516927800.0,5357804200.0,-393399200.0,20123746900.0,157629317200.0,177753064100.0,1306666700.0,1306666700.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20230421,20230421,20230331,1,1,1,,,100373116000.0,2228192200.0,,,,,,,,,,,,3090305100.0,105691613300.0,74461164100.0,4975038100.0,4321756000.0,,,,,,967376600.0,84725334900.0,20966278500.0,641947900.0,4538242300.0,1001598900.0,,,6181789100.0,10465642800.0,1523083000.0,,,,11988725800.0,-5806936600.0,13568065400.0,,,14874732100.0,13095444235.6776,7266142400.0,1026620400.0,61328200.0,1224165000.0,9516927800.0,5357804200.0,-393399200.0,20123746900.0,157629317200.0,177753064100.0,1306666700.0,1306666700.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,33457143500.0,969747300.0,305775248400.0,9478689900.0,,,,,,,,,,,,14557214600.0,329811152800.0,235327104000.0,18157352000.0,10529733400.0,,,,,,4588120100.0,268602309600.0,61208843300.0,1531307500.0,1307996200.0,740372300.0,593900.0,,3580269900.0,48215268100.0,12764660700.0,,6740182400.0,,67720111200.0,-64139841300.0,50957726600.0,,5208177600.0,103621111500.0,26286437536.8799,17605770500.0,3551469400.0,,197440400.0,21354680400.0,82266431200.0,2788148900.0,82123582000.0,75505735200.0,157629317200.0,47455207300.0,2092259300.0,,2826926600.0,11960578600.0,236449600.0,894129200.0,,,5322700.0,37927500.0,-400241300.0,-3044935500.0,-4451227000.0,9145100.0,-39877670300.0,-58697293400.0,115418278300.0,,61208843300.0,,,,82123582000.0,,,1146247900.0,161383600.0,,157629317200.0,75505735200.0,,,0
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,33457143500.0,969747300.0,305775248400.0,9478689900.0,,,,,,,,,,,,14557214600.0,329811152800.0,235327104000.0,18157352000.0,10529733400.0,,,,,,4588120100.0,268602309600.0,61208843300.0,1531307500.0,1307996200.0,740372300.0,593900.0,,3580269900.0,48215268100.0,12764660700.0,,6740182400.0,,67720111200.0,-64139841300.0,50957726600.0,,5208177600.0,103621111500.0,27236325636.8799,17605770500.0,3551469400.0,,197440400.0,21354680400.0,82266431200.0,2788148900.0,82123582000.0,75505735200.0,157629317200.0,47455207300.0,2092259300.0,,2826926600.0,11960578600.0,236449600.0,894129200.0,,,5322700.0,37927500.0,-400241300.0,-3044935500.0,-4451227000.0,9145100.0,-39877670300.0,-58697293400.0,115418278300.0,,61208843300.0,,,,82123582000.0,,,1146247900.0,161383600.0,,157629317200.0,75505735200.0,,,1
|
|
||||||
300750.SZ,20221022,20221022,20220930,1,1,3,,,192085714500.0,7811257200.0,,,,,,,,,,,,8926725200.0,208823696800.0,159150089400.0,13081486800.0,7285509900.0,,,,,,3338662100.0,182855748200.0,25967948600.0,377572800.0,563479800.0,655282800.0,,,1596335400.0,35722696500.0,8686444400.0,,850000600.0,,45259141500.0,-43662806000.0,35913561100.0,,206959000.0,82948029300.0,4854322020.6801,12923179000.0,3055573400.0,,95957200.0,16074709600.0,66873319700.0,2913476400.0,52091938700.0,75505735200.0,127597674000.0,46827509200.0,1962509400.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20220824,20220824,20220630,1,1,2,9669961200.0,1253855000.0,116064146900.0,5839330400.0,,,,,,,,,,,,5155028000.0,127058505300.0,92698134200.0,8817451600.0,4536876200.0,,,,,,2323700200.0,108376162200.0,18682343000.0,1330627700.0,187379800.0,652012400.0,,,2170019900.0,24699849700.0,5946072300.0,,2441927600.0,,33087849500.0,-30917829600.0,24205364800.0,,265175700.0,70475445400.0,14501860992.3317,7174679900.0,940178200.0,,80993000.0,8195851200.0,62279594200.0,1183477300.0,51227584900.0,75505735200.0,126733320100.0,46004904900.0,1139905100.0,,660999200.0,4964053700.0,82940400.0,233746100.0,,,138600.0,21826700.0,-215568200.0,-2064382300.0,-633149200.0,421012500.0,-35479302600.0,-30610732700.0,70089074700.0,,18682343000.0,,,,51227584900.0,,,,67362000.0,,126733320100.0,75505735200.0,,,1
|
|
||||||
300750.SZ,20220430,20220430,20220331,1,1,1,,,52971346200.0,53002900.0,,,,,,,,,,,,2798736400.0,55823085500.0,40822552900.0,4043971400.0,1760241800.0,,,,,,2120433100.0,48747199100.0,7075886400.0,330775400.0,123878000.0,380027000.0,183000.0,,834863500.0,11607436800.0,2763716600.0,,2928961700.0,,17300115100.0,-16465251700.0,14380644000.0,,262973100.0,14840522500.0,4271684121.0743,1460225400.0,536101900.0,,109860800.0,2106188200.0,12734334300.0,-170008800.0,3174960200.0,75505735200.0,78680695400.0,196905400.0,196905400.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20220422,20220422,20211231,1,1,4,17860730100.0,1580329100.0,130616575600.0,414542800.0,,,,,,,,,,,,14298549300.0,145329667700.0,86393876300.0,9423183000.0,4127789000.0,,,,,,2476810700.0,102421659000.0,42908008700.0,4094314000.0,571745100.0,228638800.0,3223100.0,58414400.0,4956335300.0,43767770800.0,11725718900.0,295800300.0,2948104700.0,,58737394700.0,-53781059400.0,26276582500.0,,3235028400.0,31063023600.0,21236726212.8648,5457907900.0,1568025100.0,,378512600.0,7404445600.0,23658578000.0,-711778200.0,12073749200.0,63431986000.0,75505735200.0,1551412800.0,795200000.0,,2047739400.0,5847138200.0,159202600.0,340253100.0,,,23190300.0,67375700.0,,-1561030800.0,-1232106000.0,215449900.0,-28856721000.0,-27816000500.0,73855678100.0,,42908008700.0,,,,12073749200.0,,,,90030200.0,,75505735200.0,63431986000.0,,,1
|
|
||||||
300750.SZ,20220422,20220422,20211231,1,1,4,17860730100.0,1580329100.0,130616575600.0,414542800.0,,,,,,,,,,,,14298549300.0,145329667700.0,86393876300.0,9423183000.0,4127789000.0,,,,,,2476810700.0,102421659000.0,42908008700.0,4094314000.0,571745100.0,228638800.0,3223100.0,58414400.0,4956335300.0,43767770800.0,11725718900.0,295800300.0,2948104700.0,,58737394700.0,-53781059400.0,26276582500.0,,3235028400.0,31063023600.0,21236726212.8648,5457907900.0,1568025100.0,,378512600.0,7404445600.0,23658578000.0,-711778200.0,12073749200.0,63431986000.0,75505735200.0,1551412800.0,795200000.0,,2047739400.0,5847138200.0,159202600.0,340253100.0,,,23190300.0,67375700.0,,-1561030800.0,-1232106000.0,215449900.0,-28856721000.0,-27816000500.0,73855678100.0,,42908008700.0,,,,12073749200.0,,,,90030200.0,,75505735200.0,63431986000.0,,,0
|
|
||||||
300750.SZ,20211028,20211028,20210930,1,1,3,,,83626746277.27,535346958.22,,,,,,,,,,,,7782116412.72,91944209648.21,51379494480.13,6571571458.45,3480171938.71,,,,,,1826733218.37,63257971095.66,28686238552.55,2938674644.74,37113851.85,164722892.5,1387035.57,58414361.69,3200312786.35,30667430388.32,7449921995.07,177944806.0,1460499766.01,,39755796955.4,-36555484169.05,16682111411.78,,3221088249.26,20723206402.29,11934069869.9773,4283900195.11,1288764640.8,,193522043.25,5766186879.16,14957019523.13,-228684931.08,6859088975.55,63431985986.9,70291074962.45,820006741.25,820006741.25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20210826,20210826,20210630,1,1,2,5325108289.03,614595263.22,51085024721.36,140585405.15,,,,,,,,,,,,4098937926.36,55324548052.87,21559768798.96,4211528980.82,2523997750.53,,,,,,1287192835.98,29582488366.29,25742059686.58,1746377670.86,31702892.85,59164928.94,227975.57,,1837473468.22,20090694926.23,5568013121.5,162089096.03,1143479615.97,,26964276759.73,-25126803291.51,5744054032.33,,,6319060773.58,10214622538.1769,2174158921.05,475061070.79,,205756669.64,2854976661.48,3464084112.1,-234765497.65,3844575009.52,63431985986.9,67276560996.42,575006741.25,575006741.25,,817370458.03,2549707122.23,72565403.73,106499325.87,,,571920.37,30306302.87,,-257314301.91,-723546283.57,150453314.61,-11317249364.86,-5279233781.91,33520132588.52,,25742059686.58,,,,3844575009.52,,,,14343147.12,,67276560996.42,63431985986.9,,,1
|
|
||||||
300750.SZ,20210430,20210430,20210331,1,1,1,,,19699155644.5,68463823.72,,,,,,,,,,,,1637605513.45,21405224981.67,7311949649.62,1759283573.51,1021292581.76,,,,,,345828625.23,10438354430.12,10966870551.55,1653611877.72,,9257589.83,227975.57,,1663097443.12,8903269558.24,1303423035.72,,269831098.63,,10476523692.59,-8813426249.47,2281243461.99,,27016829.63,2309232792.7,795517931.2821,1738449618.43,315255006.47,,8266665.17,2061971290.07,247261502.63,-43193144.9,2357512659.81,63431985986.9,65789498646.71,972501.08,972501.08,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,6103918052.46,772394855.22,54002988575.54,151928522.94,,,,,,,,,,,,6397335867.06,60552252965.54,33461951736.87,4027848128.71,2265587429.63,,,,,,2366963038.37,42122350333.58,18429902631.96,2735874410.58,44779761.91,24087086.33,24649.08,,2804765907.9,13302355759.04,4088418479.98,,466447835.43,,17857222074.45,-15052456166.55,9450920678.78,,13199266407.5,43186548078.44,-3068497270.4043,4743701233.75,898809819.12,7825842.99,112602486.19,5755113539.06,37431434539.38,-576950661.91,40231930342.88,23200055644.02,63431985986.9,20536360992.16,923523424.41,,1169471948.67,4576797794.5,135243814.08,155847906.24,,,9890379.23,47137042.0,-286915936.0,26192466.45,-772834310.15,-5673139.63,-2401630461.19,-3415569969.88,11747641389.69,,18429902631.96,,,,40231930342.88,,,,,,63431985986.9,23200055644.02,,,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,6103918052.46,772394855.22,54002988575.54,151928522.94,,,,,,,,,,,,6397335867.06,60552252965.54,33461951736.87,4027848128.71,2265587429.63,,,,,,2366963038.37,42122350333.58,18429902631.96,2735874410.58,44779761.91,24087086.33,24649.08,,2804765907.9,13302355759.04,4088418479.98,,466447835.43,,17857222074.45,-15052456166.55,9450920678.78,,13199266407.5,43186548078.44,-3068497270.4043,4743701233.75,898809819.12,7825842.99,112602486.19,5755113539.06,37431434539.38,-576950661.91,40231930342.88,23200055644.02,63431985986.9,20536360992.16,923523424.41,,1169471948.67,4576797794.5,135243814.08,155847906.24,,,9890379.23,47137042.0,-286915936.0,26192466.45,-772834310.15,-5673139.63,-2401630461.19,-3415569969.88,11747641389.69,,18429902631.96,,,,40231930342.88,,,,,,63431985986.9,23200055644.02,,,0
|
|
||||||
300750.SZ,20201028,20201028,20200930,1,1,3,,,36371199567.28,114482857.95,,,,,,,,,,,,4825316285.67,41310998710.9,24822097581.29,2823360855.95,1745908648.26,,,,,,1613706843.31,31005073928.81,10305924782.09,1700046486.01,,12374592.63,3684.0,,1712424762.64,8050755719.05,2201534043.13,,40151993.35,,10292441755.53,-8580016992.89,6318374370.91,,13199242930.24,39964978293.31,-7205651306.8712,3594856317.38,749851132.13,,52137357.55,4396844807.06,35568133486.25,97997833.83,37392039109.28,23200055644.02,60592094753.3,20447360992.16,834523424.41,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,2143918030.12,217908314.21,24016663944.28,32332645.46,,,,,,,,,,,,2438827143.57,26487823733.31,16188323898.87,1903680069.18,1340543579.11,,,,,,1228723296.81,20661270843.97,5826552889.34,2852419271.07,,1765869.0,,,2854185140.07,5162370937.5,70700000.0,,148983251.15,,5382054188.65,-2527869048.58,4165228444.2,,2997600000.0,7971818444.2,-2911607178.1347,1643262959.49,657716347.49,,370675928.14,2671655235.12,5300163209.08,28838388.11,8627685437.95,23200055644.02,31827741081.97,808990000.0,808990000.0,,460355170.89,2316114146.94,67472468.68,79375064.46,,,,7116807.84,-286915936.0,369373574.54,-271258312.84,-13561794.14,2092973405.33,4116138675.55,-5587341718.38,,5826552889.34,,,,8627685437.95,,,,,,31827741081.97,23200055644.02,,,0
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,2143918030.12,217908314.21,24016663944.28,32332645.46,,,,,,,,,,,,2438827143.57,26487823733.31,16188323898.87,1903680069.18,1340543579.11,,,,,,1228723296.81,20661270843.97,5826552889.34,2852419271.07,,1765869.0,,,2854185140.07,5162370937.5,70700000.0,,148983251.15,,5382054188.65,-2527869048.58,4165228444.2,,2997600000.0,7971818444.2,-2911607178.1347,1643262959.49,657716347.49,,370675928.14,2671655235.12,5300163209.08,28838388.11,8627685437.95,23200055644.02,31827741081.97,808990000.0,808990000.0,,460355170.89,2316114146.94,67472468.68,79375064.46,,,,7116807.84,-286915936.0,369373574.54,-271258312.84,-13561794.14,2092973405.33,4116138675.55,-5587341718.38,,5826552889.34,,,,8627685437.95,,,,,,31827741081.97,23200055644.02,,,1
|
|
||||||
300750.SZ,20200428,20200428,20200331,1,1,1,,,12250452196.35,10316194.85,,,,,,,,,,,,1641626275.85,13902394667.05,8196211578.47,903620974.34,818014513.49,,,,,,837797285.07,10755644351.37,3146750315.68,876367408.52,,,,,876367408.52,2076740551.31,17200000.0,,172332000.0,,2266272551.31,-1389905142.79,1794510100.02,,2997600000.0,5076600100.02,-2428145279.3035,671702027.85,89478420.27,,357122140.52,1118302588.64,3958297511.38,6655507.93,5721798192.2,23200055644.02,28921853836.22,284490000.0,284490000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,5012673897.87,270468281.25,52149078427.56,395686584.53,,,,,,,,,,,,3763244302.06,56308009314.15,33260080970.87,3704062487.97,2688800053.78,,,,,,3183111244.73,42836054757.35,13471954556.8,15477402748.49,0.23,2563085.15,15088255.27,10026813.18,15505080902.32,9626986411.07,907758218.55,,3114021020.85,,13648765650.47,1856315251.85,4616632167.94,,1498800000.0,7333217057.62,-817733.8461,2418452429.42,573302388.77,,173132704.46,3164887522.65,4168329534.97,14801651.37,19511400994.99,3688654649.03,23200055644.02,1217784889.68,721974398.68,,1670005549.8,4137828483.56,113911953.13,157299905.57,,,-1382204.06,18928639.15,-27331582.1,-20752318.89,-838669146.42,50207460.38,-5775387378.74,-4768945377.05,12637959848.72,,13471954556.8,,,,19511400994.99,,,,,,23200055644.02,3688654649.03,,,0
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,5012673897.87,270468281.25,52149078427.56,395686584.53,,,,,,,,,,,,3763244302.06,56308009314.15,33260080970.87,3704062487.97,2688800053.78,,,,,,3183111244.73,42836054757.35,13471954556.8,15477402748.49,0.23,2563085.15,15088255.27,10026813.18,15505080902.32,9626986411.07,907758218.55,,3114021020.85,,13648765650.47,1856315251.85,4616632167.94,,1498800000.0,7333217057.62,-817733.8461,2418452429.42,573302388.77,,173132704.46,3164887522.65,4168329534.97,14801651.37,19511400994.99,3688654649.03,23200055644.02,1217784889.68,721974398.68,,1670005549.8,4137828483.56,113911953.13,157299905.57,,,-1382204.06,18928639.15,-27331582.1,-20752318.89,-838669146.42,50207460.38,-5775387378.74,-4768945377.05,12637959848.72,,13471954556.8,,,,19511400994.99,,,,,,23200055644.02,3688654649.03,,,1
|
|
||||||
300750.SZ,20191026,20191026,20190930,1,1,3,,,38036360575.38,163298908.7,,,,,,,,,,,,1774836858.05,39974496342.13,23046083793.97,2611212349.97,2332476003.68,,,,,,1659794653.67,29649566801.29,10324929540.84,15178453020.7,,2563085.15,14210702.04,,15195226807.89,6661477871.25,321750000.0,,932156630.0,,7915384501.25,7279842306.64,3058463176.85,,,4001503667.85,596534389.9903,1693048366.19,492320693.78,,62601933.18,2247970993.15,1753532674.7,23661063.46,19381965585.64,3688654649.03,23070620234.67,943040491.0,447230000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20191026,20191026,20190930,1,1,3,,,38036360575.38,163298908.7,,,,,,,,,,,,1774836858.05,39974496342.13,23046083793.97,2611212349.97,2332476003.68,,,,,,1659794653.67,29649566801.29,10324929540.84,15178453020.7,,2563085.15,14210702.04,,15195226807.89,6661477871.25,321750000.0,,932156630.0,,7915384501.25,7279842306.64,3058463176.85,,,4001503667.85,1039486288.1869,1693048366.19,492320693.78,,62601933.18,2247970993.15,1753532674.7,23661063.46,19381965585.64,3688654649.03,23070620234.67,943040491.0,447230000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20190824,20190824,20190630,1,1,2,2346495300.44,87744066.16,24838903624.97,109269862.19,,,,,,,,,,,,781516763.62,25729690250.78,13700891263.83,1752894045.03,1655079077.44,,,,,,1344522955.73,18453387342.03,7276302908.75,2657818813.56,,,,,2657818813.56,4623112893.49,90750000.0,,,,4713862893.49,-2056044079.93,1354369492.97,,,1796249492.97,5528716163.5267,1222988045.56,121183356.39,,45862760.81,1390034162.76,406215330.21,15718117.48,5642192276.51,3688654649.03,9330846925.54,441880000.0,441880000.0,,530322585.73,1817060732.44,52188372.72,71233411.93,,,-305715.96,6164952.02,,-8807709.54,-495832311.39,17405342.8,-3575604570.39,-2426304894.46,8706398499.9,148144846.35,7276302908.75,,,,5642192276.51,,,,,,9330846925.54,3688654649.03,,,0
|
|
||||||
300750.SZ,20190824,20190824,20190630,1,1,2,2346495300.44,87744066.16,24838903624.97,109269862.19,,,,,,,,,,,,781516763.62,25729690250.78,13700891263.83,1752894045.03,1655079077.44,,,,,,1344522955.73,18453387342.03,7276302908.75,2657818813.56,,,,,2657818813.56,4623112893.49,90750000.0,,,,4713862893.49,-2056044079.93,1354369492.97,,,1796249492.97,5783236226.2656,1222988045.56,121183356.39,,45862760.81,1390034162.76,406215330.21,15718117.48,5642192276.51,3688654649.03,9330846925.54,441880000.0,441880000.0,,530322585.73,1817060732.44,52188372.72,71233411.93,,,-305715.96,6164952.02,,-8807709.54,-495832311.39,17405342.8,-3575604570.39,-2426304894.46,8706398499.9,,7276302908.75,,,,5642192276.51,,,,,,9330846925.54,3688654649.03,,,1
|
|
||||||
300750.SZ,20190427,20190427,20190331,1,1,1,,,12878552646.43,299432.71,,,,,,,,,,,,421498351.55,13300350430.69,6221938005.9,748693434.59,701069344.37,,,,,,651798444.58,8323499229.44,4976851201.25,14605433.53,,,,,14605433.53,2019864308.52,75250000.0,,626495569.66,,2721609878.18,-2707004444.65,274025394.22,,,715025394.22,4255915886.1405,279493169.29,61759955.59,,24669985.03,365923109.91,349102284.31,-22720393.29,2596228647.62,3688654649.03,6284883296.65,441000000.0,441000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,3735896487.72,262258592.79,33853639616.99,37127687.41,,,,,,,,,,,,2274383357.82,36165150662.22,19041614626.94,2299961469.07,1868081717.0,,,,,,1639227148.68,24848884961.69,11316265700.53,70629509.16,5258600.0,3655688.2,294506.1,,79838303.46,6629274672.98,192025942.3,,12746210861.04,,19567511476.32,-19487673172.86,4123196326.07,,510282473.44,10908434734.88,5771848024.1698,3493721841.0,216119536.13,,155877429.51,3865718806.64,7042715928.24,27440781.07,-1101250763.02,4789905412.05,3688654649.03,6274955935.37,108785163.6,,974912150.01,2125110234.63,95733856.19,83377065.66,,,91538964.57,15782022.0,314247518.1,-184397531.48,-669755258.27,15459358.23,-4371312786.43,-3143244270.65,11851141407.59,119517889.87,11316265700.53,,,,-1101250763.02,,,,,,3688654649.03,4789905412.05,,,0
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,3735896487.72,262258592.79,33853639616.99,37127687.41,,,,,,,,,,,,2274383357.82,36165150662.22,19041614626.94,2299961469.07,1868081717.0,,,,,,1639227148.68,24848884961.69,11316265700.53,70629509.16,5258600.0,3655688.2,294506.1,,79838303.46,6629274672.98,192025942.3,,12746210861.04,,19567511476.32,-19487673172.86,4123196326.07,,510282473.44,10908434734.88,5771848024.1698,3493721841.0,216119536.13,,155877429.51,3865718806.64,7042715928.24,27440781.07,-1101250763.02,4789905412.05,3688654649.03,6274955935.37,108785163.6,,974912150.01,2125110234.63,95733856.19,83377065.66,,,91538964.57,15782022.0,314247518.1,-184397531.48,-669755258.27,15459358.23,-4371312786.43,-3143244270.65,11851141407.59,,11316265700.53,,,,-1101250763.02,,,,,,3688654649.03,4789905412.05,,,1
|
|
||||||
300750.SZ,20181026,20181026,20180930,1,1,3,,,21070111447.41,301325611.35,,,,,,,,,,,,704920707.06,22076357765.82,12588299955.24,1554320363.04,1269800694.62,,,,,,1060506072.64,16472927085.54,5603430680.28,397786320.4,,3660866.63,,,401447187.03,4003526664.32,188726677.3,,10556014049.83,,14748267391.45,-14346820204.42,3098388086.68,,,9412815605.34,163613248.4859,2282129396.03,154081142.29,,185815261.12,2622025799.44,6790789805.9,24982414.85,-1927617303.39,4789905412.05,2862288108.66,6314427518.66,108785163.6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
300750.SZ,20180824,20180824,20180630,1,1,2,1069893694.3,-97443594.11,11349245325.45,145178535.71,,,,,,,,,,,,560299594.35,12054723455.51,8740027942.34,976570165.74,671456234.75,,,,,,608343009.72,10996397352.55,1058326102.96,216767226.15,,3206903.36,,,219974129.51,2506446403.66,103842000.0,,6573449373.0,,9183737776.66,-8963763647.15,2683586736.64,,,8113178621.7,-2883539480.9055,1688445920.37,93782534.45,,114716247.56,1896944702.38,6216233919.32,5815768.51,-1683387856.36,4789905412.05,3106517555.69,5429591885.06,67650590.0,,207126112.45,934646157.43,46852863.98,36271274.26,,,2444993.47,,,-59838864.61,-198227130.98,-973329.73,-1662466492.98,474319090.22,266011187.56,,1058326102.96,,,,-1683387856.36,,,,,,3106517555.69,4789905412.05,,,0
|
|
||||||
300750.SZ,20180522,20180522,20180331,1,1,1,469264488.71,65166429.44,2561651184.82,136600925.36,,,,,,,,,,,,211514708.3,2909766818.48,4899971184.88,451661730.79,339098883.01,,,,,,488869504.21,6179601302.89,-3269834484.41,4220209248.47,,,,,4220209248.47,1667611627.4,,,151925834.11,,1819537461.51,2400671786.96,997738375.18,,20695110.88,1037619613.06,-4701407794.046,1052569621.31,42973564.05,,66470960.3,1162014145.66,-124394532.6,-13184201.95,-1006741432.0,4789905412.05,3783163980.05,19186127.0,19186127.0,,127717465.75,418689739.66,22774627.17,14666290.5,,,328223.0,,,-27972938.86,-70034407.27,,-606145268.44,-2419349974.35,-1284794230.57,19855070.85,-3269834484.41,,,,-1006741432.0,,,,,,3783163980.05,4789905412.05,,,0
|
|
||||||
300750.SZ,20180522,20180522,20171231,1,1,4,4194056577.66,112588566.26,18872908615.92,21013193.89,,,,,,,,,,,,529176792.58,19423098602.39,12357592298.17,2122637417.2,1493296692.69,,,,,,1108823984.08,17082350392.14,2340748210.25,758831340.52,448002008.14,2565089.09,572921.94,,1209971359.69,7180281117.24,1665503314.78,,656.0,,8845785088.02,-7635813728.33,4476769278.83,,9028894.69,10664444151.52,4099608510.9298,1421628377.86,81600198.58,,228481941.8,1731710518.24,8932733633.28,-13763656.75,3623904458.45,1166000953.6,4789905412.05,6178645978.0,1168645100.0,,244744030.88,1279538608.41,75101189.69,26541967.12,,,78311541.52,,,-1344305303.77,-245133190.87,-2604999.44,-2290181545.88,-5075995986.77,5163299958.56,124786796.88,2340748210.25,,,,3623904458.45,,,,,,4789905412.05,1166000953.6,,,0
|
|
||||||
300750.SZ,20181026,20181026,20170930,1,1,3,,,10333130705.0,18590039.13,,,,,,,,,,,,438765326.08,10790486070.21,9339844151.58,1447940056.29,973528442.38,,,,,,762537994.18,12523850644.43,-1733364574.22,1902846575.98,447302008.14,2565089.09,572921.94,,2353286595.15,5268771842.36,1293525820.0,,33801356.44,,6596099018.8,-4242812423.65,2560246872.03,,2626381.59,8738485131.62,,1367562190.03,58673275.89,,192651364.04,1618886829.96,7119598301.66,3054315.86,1146475619.65,1166000953.6,2312476573.25,6175611878.0,1168645100.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20171110,20171110,20170630,1,1,2,2020743800.0,34312300.0,6701189072.6,6314977.79,,,,,,,,,,,,236369322.05,6943873372.44,5680819173.2,954740070.6,544344685.49,,,,,,383613562.34,7563517491.63,-619644119.19,198806392.58,445502008.14,1122943.61,572921.94,,646004266.27,3978747353.07,651932500.0,,1534321000.0,,6165000853.07,-5518996586.8,1515912025.59,,,6599412903.59,-3817342677.722,1109776166.12,25777423.37,,184404131.28,1319957720.77,5279455182.82,2908894.84,-856276628.33,1166000953.6,309724325.27,5083500878.0,73500000.0,,49177200.0,477360300.0,31487700.0,5951300.0,,,2279700.0,,,-1245985200.0,-67539100.0,-997900.0,-2641681800.0,-1366773700.0,2082021300.0,,-619644100.0,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20180522,20180522,20170331,1,1,1,24302205.99,15763102.24,3404527894.74,13236437.91,,,,,,,,,,,,362505387.34,3780269719.99,2722235315.54,369852769.21,238870764.39,,,,,,255577266.62,3586536115.76,193733604.23,51615559.94,,,,,51615559.94,2459107491.01,219204000.0,,1501137963.78,,4179449454.79,-4127833894.85,413910040.9,,66308848.89,3990218891.79,,969797476.02,12861203.02,,75330960.74,1057989639.78,2932229252.01,-352048.57,-1002223087.18,1166000953.6,163777866.42,3510000002.0,,,-7807006.14,289187792.31,14656308.34,1939204.66,,,322076.28,,,-85172231.78,-18053126.42,,-1157067016.01,962653382.55,116440384.84,36568527.37,193733604.23,,,,-1002223087.18,,,,,,163777866.42,1166000953.6,,,0
|
|
||||||
300750.SZ,20180522,20180522,20161231,1,1,4,2918436854.29,65609349.18,11524664337.65,1476437.43,,,,,,,,,,,,421522517.2,11947663292.28,5954917349.27,1249671965.87,1559891278.12,,,,,,1074055972.23,9838536565.49,2109126726.79,61944950.69,10027000.0,,5046154.0,,77018104.69,2800818908.69,262828666.62,,9441784763.04,,12505432338.35,-12428414233.66,1930654288.91,,747351550.61,13809851365.52,-10067555462.0948,937312259.12,53696810.21,,1847820297.11,2838829366.44,10971021999.08,-2077449.43,649657042.78,516343910.82,1166000953.6,11131845526.0,7840000.0,,233858870.04,731417250.67,47998770.85,5071074.74,,,158205248.94,,,-76080348.84,-129670575.05,-2090649.0,-320169108.33,-14762136096.64,13031595453.28,207080632.66,2109126726.79,,,,649657042.78,,,,,,1166000953.6,516343910.82,,,0
|
|
||||||
300750.SZ,20180522,20180522,20151231,1,1,4,950581074.45,113184042.2,4153743551.55,670144.46,,,,,,,,,,,,221173494.7,4375587190.71,2302132506.69,437554338.26,474554245.93,,,,,,496812115.82,3711053206.7,664533984.01,1088566666.05,,,,,1088566666.05,1553786649.12,,173225298.0,2900000.0,,1729911947.12,-641345281.07,830867703.13,,893371268.45,1874742721.58,1290805842.4247,628641795.8,69496886.29,,736699312.71,1434837994.8,439904726.78,-800509.91,462292919.81,54050991.01,516343910.82,150503750.0,500000.0,,58641678.66,164100734.24,24986934.33,3237903.35,,,590103.88,,,-1455431.76,-110143619.54,-2194284.46,-697915929.01,-2315594532.87,2476515310.54,,664533984.01,,,,462292919.81,,,,,,516343910.82,54050991.01,,,0
|
|
||||||
300750.SZ,20171110,20171110,20141231,1,1,4,55563800.0,24221600.0,732813440.92,4165547.69,,,,,,,,,,,,11345197.89,748324186.5,601009216.98,98419099.09,28689220.56,,,,,,159111051.94,887228588.57,-138904402.07,3180178.72,,,,,3180178.72,300525204.81,,,976061675.94,,1276586880.75,-1273406702.03,201635144.87,,1556561925.62,1782597070.49,,4760000.0,4752841.5,,307574012.42,317086853.92,1465510216.57,-4995362.09,48203750.38,5847240.63,54050991.01,24400000.0,24400000.0,,2591100.0,44569700.0,22656600.0,64800.0,,,102500.0,,,-16117600.0,-19814600.0,,-220368300.0,-313910300.0,281536200.0,,-138904400.0,,,,,,,,,,,,,,0
|
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
end_date,ex_date,div_proc,cash_div
|
|
||||||
20250630,,预案,0.0
|
|
||||||
20250630,20250820,实施,1.007
|
|
||||||
20241231,,预案,0.0
|
|
||||||
20241231,,股东大会通过,0.0
|
|
||||||
20241231,20250422,实施,2.24
|
|
||||||
20241211,,预案,0.0
|
|
||||||
20241211,,股东大会通过,0.0
|
|
||||||
20241211,20250124,实施,1.23
|
|
||||||
20240630,,预案,0.0
|
|
||||||
20231231,,预案,0.0
|
|
||||||
20231231,,股东大会通过,0.0
|
|
||||||
20231231,20240430,实施,5.028
|
|
||||||
20230630,,预案,0.0
|
|
||||||
20221231,,预案,0.0
|
|
||||||
20221231,,股东大会通过,0.0
|
|
||||||
20221231,20230426,实施,2.52
|
|
||||||
20220630,,预案,0.0
|
|
||||||
20220630,,股东大会通过,0.0
|
|
||||||
20220630,20220928,实施,0.6528
|
|
||||||
20211231,,预案,0.0
|
|
||||||
20211231,,股东大会通过,0.0
|
|
||||||
20210630,,预案,0.0
|
|
||||||
20201231,,预案,0.0
|
|
||||||
20201231,,股东大会通过,0.0
|
|
||||||
20201231,20210705,实施,0.240048
|
|
||||||
20200630,,预案,0.0
|
|
||||||
20191231,,预案,0.0
|
|
||||||
20191231,,股东大会通过,0.0
|
|
||||||
20191231,20200604,实施,0.2201281
|
|
||||||
20190630,,预案,0.0
|
|
||||||
20181231,,预案,0.0
|
|
||||||
20181231,,股东大会通过,0.0
|
|
||||||
20181231,20190722,实施,0.142037
|
|
||||||
20180630,,预案,0.0
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
300750.SZ,20250731,20250630,226368
|
|
||||||
300750.SZ,20250415,20250331,226327
|
|
||||||
300750.SZ,20250315,20250228,208828
|
|
||||||
300750.SZ,20250315,20241231,212061
|
|
||||||
300750.SZ,20241019,20240930,229043
|
|
||||||
300750.SZ,20240727,20240630,237334
|
|
||||||
300750.SZ,20240416,20240331,250264
|
|
||||||
300750.SZ,20240316,20240229,260219
|
|
||||||
300750.SZ,20240316,20231231,260992
|
|
||||||
300750.SZ,20231020,20230930,233256
|
|
||||||
300750.SZ,20230726,20230630,217464
|
|
||||||
300750.SZ,20230421,20230331,206031
|
|
||||||
300750.SZ,20230310,20230228,195845
|
|
||||||
300750.SZ,20230310,20221231,183317
|
|
||||||
300750.SZ,20221022,20220930,185383
|
|
||||||
300750.SZ,20220824,20220630,150353
|
|
||||||
300750.SZ,20220422,20220331,140911
|
|
||||||
300750.SZ,20220430,20220331,140911
|
|
||||||
300750.SZ,20220422,20211231,141963
|
|
||||||
300750.SZ,20211028,20210930,134193
|
|
||||||
300750.SZ,20210826,20210630,135198
|
|
||||||
300750.SZ,20210430,20210331,182794
|
|
||||||
300750.SZ,20210428,20210331,182794
|
|
||||||
300750.SZ,20210428,20201231,133060
|
|
||||||
300750.SZ,20201028,20200930,131130
|
|
||||||
300750.SZ,20200827,20200630,121586
|
|
||||||
300750.SZ,20200428,20200331,150855
|
|
||||||
300750.SZ,20200425,20200331,150855
|
|
||||||
300750.SZ,20200425,20191231,76710
|
|
||||||
300750.SZ,20191026,20190930,94339
|
|
||||||
300750.SZ,20190824,20190630,80513
|
|
||||||
300750.SZ,20190427,20190331,76045
|
|
||||||
300750.SZ,20190425,20181231,82514
|
|
||||||
300750.SZ,20181026,20180930,99847
|
|
||||||
300750.SZ,20180824,20180630,164739
|
|
||||||
300750.SZ,20180608,20180611,368718
|
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,basic_eps,diluted_eps,total_revenue,revenue,int_income,prem_earned,comm_income,n_commis_income,n_oth_income,n_oth_b_income,prem_income,out_prem,une_prem_reser,reins_income,n_sec_tb_income,n_sec_uw_income,n_asset_mg_income,oth_b_income,fv_value_chg_gain,invest_income,ass_invest_income,forex_gain,total_cogs,oper_cost,int_exp,comm_exp,biz_tax_surchg,sell_exp,admin_exp,fin_exp,assets_impair_loss,prem_refund,compens_payout,reser_insur_liab,div_payt,reins_exp,oper_exp,compens_payout_refu,insur_reser_refu,reins_cost_refund,other_bus_cost,operate_profit,non_oper_income,non_oper_exp,nca_disploss,total_profit,income_tax,n_income,n_income_attr_p,minority_gain,oth_compr_income,t_compr_income,compr_inc_attr_p,compr_inc_attr_m_s,ebit,ebitda,insurance_exp,undist_profit,distable_profit,rd_exp,fin_exp_int_exp,fin_exp_int_inc,transfer_surplus_rese,transfer_housing_imprest,transfer_oth,adj_lossgain,withdra_legal_surplus,withdra_legal_pubfund,withdra_biz_devfund,withdra_rese_fund,withdra_oth_ersu,workers_welfare,distr_profit_shrhder,prfshare_payable_dvd,comshare_payable_dvd,capit_comstock_div,continued_net_profit,update_flag
|
|
||||||
300750.SZ,20251021,20251021,20250930,1,1,3,11.02,11.02,283071987000.0,283071987000.0,,,,,,,,,,,,,,,878537000.0,5236818000.0,4943750000.0,,236417478000.0,211427147000.0,,,1843066000.0,2408522000.0,8231715000.0,-7015786000.0,-4077847000.0,,,,,,,,,,,60552312000.0,372284000.0,212195000.0,,60712402000.0,8415535000.0,52296866000.0,49034109000.0,3262757000.0,7455238000.0,59752104000.0,56472049000.0,3280055000.0,51409807000.0,,,,,15067826000.0,2183477000.0,8060682000.0,,,,,,,,,,,,,,,52296866000.0,1
|
|
||||||
300750.SZ,20250731,20250731,20250630,1,1,2,6.92,6.92,178886253000.0,178886253000.0,,,,,,,,,,,,,,,178363000.0,2875693000.0,2981557000.0,,149241453000.0,134123603000.0,,,1245850000.0,1621425000.0,5127530000.0,-5821810000.0,-2498964000.0,,,,,,,,,,,38820520000.0,168476000.0,176496000.0,,38812500000.0,6447053000.0,32365447000.0,30485139000.0,1880308000.0,1376911000.0,33742358000.0,31804164000.0,1938194000.0,30541999000.0,42915712000.0,,,,10094566000.0,1557999000.0,5125146000.0,,,,,,,,,,,,,,,32365447000.0,1
|
|
||||||
300750.SZ,20250415,20250415,20250331,1,1,1,3.18,3.18,84704589000.0,84704589000.0,,,,,,,,,,,,,,,25565000.0,1339222000.0,1469564000.0,,71833284000.0,64030111000.0,,,559098000.0,852316000.0,2623930000.0,-2287911000.0,-1109939000.0,,,,,,,,,,,17340443000.0,108032000.0,73444000.0,,17375031000.0,2513397000.0,14861634000.0,13962558000.0,899076000.0,614450000.0,15476084000.0,14508266000.0,967818000.0,14776292000.0,,,,,4814003000.0,782951000.0,2384036000.0,,,,,,,,,,,,,,,14861634000.0,1
|
|
||||||
300750.SZ,20250415,20250415,20250331,1,1,1,3.18,3.18,84704589000.0,84704589000.0,,,,,,,,,,,,,,,25565000.0,1339222000.0,1469564000.0,,71833284000.0,64030111000.0,,,559098000.0,852316000.0,2623930000.0,-2287911000.0,-1109939000.0,,,,,,,,,,,17340443000.0,108032000.0,73444000.0,,17375031000.0,2513397000.0,14861634000.0,13962558000.0,899076000.0,614450000.0,15476084000.0,14508266000.0,967818000.0,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20250315,20250315,20241231,1,1,4,11.58,11.58,362012554000.0,362012554000.0,,,,,,,,,,,,,,,664223000.0,3987823000.0,3743040000.0,,312599750000.0,273518959000.0,,,2057466000.0,3562797000.0,9689839000.0,-4131918000.0,-8423325000.0,,,,,,,,,,,64051799000.0,135422000.0,1005182000.0,,63182039000.0,9175245000.0,54006794000.0,50744682000.0,3262113000.0,-1687613000.0,52319181000.0,48940398000.0,3378782000.0,61464661000.0,86402589000.0,,,,18606756000.0,3879076000.0,9502997000.0,,,,,,,,,,,,,,,54006794000.0,1
|
|
||||||
300750.SZ,20241019,20241019,20240930,1,1,3,8.1894,8.1829,259044748600.0,259044748600.0,,,,,,,,,,,,,,,190410200.0,3127166700.0,2712745400.0,,223014892600.0,186032900900.0,,,1557473800.0,10927707300.0,6774455800.0,-2894208700.0,-6651709400.0,,,,,,,,,,,46125749700.0,142603700.0,547867400.0,,45720486000.0,6987230700.0,38733255300.0,36001073800.0,2732181500.0,-568007300.0,38165248000.0,35252110200.0,2913137800.0,46518082900.0,,,,,13073136100.0,2966060400.0,7126535700.0,,,,,,,,,,,,,,,38733255300.0,1
|
|
||||||
300750.SZ,20240727,20240727,20240630,1,1,2,5.2017,5.1975,166766833600.0,166766833600.0,,,,,,,,,,,,,,,-24331900.0,2076994500.0,1916680600.0,,144640149400.0,122517848800.0,,,973678300.0,7004983100.0,4391272500.0,-1183454700.0,-1913611600.0,,,,,,,,,,,29554566300.0,85083600.0,189697800.0,,29449952100.0,4571096800.0,24878855300.0,22864987400.0,2013867900.0,-1936799500.0,22942055800.0,20773319800.0,2168736000.0,27019052300.0,39241814300.0,,,,8592452400.0,2059047700.0,5009250600.0,,,,,,,,,,,,,,,24878855300.0,1
|
|
||||||
300750.SZ,20240416,20240416,20240331,1,1,1,2.3909,2.389,79770778600.0,79770778600.0,,,,,,,,,,,,,,,-73450400.0,817635400.0,665871400.0,,70391729300.0,58698906300.0,,,574391200.0,3386939900.0,2303072500.0,312941500.0,-507556600.0,,,,,,,,,,,13332747100.0,26663000.0,159187800.0,,13200222200.0,2004579400.0,11195642900.0,10509923200.0,685719700.0,-229046000.0,10966596800.0,10105445100.0,861151800.0,13405371900.0,,,,,4340204800.0,1048364500.0,2632483700.0,,,,,,,,,,,,,,,11195642900.0,1
|
|
||||||
300750.SZ,20240316,20240316,20231231,1,1,4,11.79,11.779,400917044900.0,400917044900.0,,,,,,,,,,,,,,,46270400.0,3189201200.0,3745762000.0,,356718585800.0,309070434000.0,,,1695507700.0,17954440500.0,8461824300.0,-4927697400.0,-5853926900.0,,,,,,,,,,,53718302100.0,503675200.0,307924000.0,,53914053300.0,7153018800.0,46761034500.0,44121248300.0,2639786100.0,-4711859000.0,42049175500.0,39568104200.0,2481071300.0,51182922200.0,73828904000.0,,,,18356108400.0,3446515800.0,8321802100.0,,,,,,,,,,,,,,,46761034500.0,1
|
|
||||||
300750.SZ,20231020,20231020,20230930,1,1,3,7.0958,7.0844,294677250600.0,294677250600.0,,,,,,,,,,,,,,,215302500.0,2189770600.0,1307678000.0,,264479515000.0,230096038100.0,,,1105082900.0,10222106900.0,6917820800.0,-1833890000.0,-2848221100.0,,,,,,,,,,,37015470400.0,416987300.0,266043400.0,,37166414300.0,4650152200.0,32516262100.0,31145473600.0,1370788600.0,-2958450600.0,29557811600.0,28154741800.0,1403069700.0,35611604300.0,,,,,14875734500.0,2317681200.0,5683966700.0,,,,,,,,,,,,,,,32516262100.0,1
|
|
||||||
300750.SZ,20230726,20230726,20230630,1,1,2,4.7201,4.7125,189246041300.0,189246041300.0,,,,,,,,,,,,,,,213283400.0,1417699300.0,568276700.0,,168529510800.0,148305934100.0,,,638811900.0,6699756700.0,4512280500.0,-3159346300.0,-1903493700.0,,,,,,,,,,,25357423300.0,300135500.0,188482100.0,,25469076700.0,3995875200.0,21473201500.0,20717264500.0,755937000.0,-1808645700.0,19664555800.0,18925205800.0,739350000.0,20863805500.0,31032137200.0,,,,9850086700.0,1450307700.0,3627578200.0,,,,,,,,,,,,,,,21473201500.0,1
|
|
||||||
300750.SZ,20230421,20230421,20230331,1,1,1,4.0332,4.0215,89038465300.0,89038465300.0,,,,,,,,,,,,,,,112896900.0,1527471300.0,587107500.0,,80044922600.0,70101011700.0,,,274706600.0,2916572500.0,1851067100.0,-466751900.0,-1092544100.0,,,,,,,,,,,12016687500.0,174634200.0,179823800.0,,12011497900.0,1930890700.0,10080607200.0,9822265100.0,258342100.0,-2911771700.0,7168835500.0,6849115100.0,319720400.0,10986170900.0,,,,,4652229200.0,694811000.0,1723865300.0,,,,,,,,,,,,,,,10080607200.0,1
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,12.9178,12.8795,328593987500.0,328593987500.0,,,,,,,,,,,,,,,400241300.0,2514538600.0,2614517000.0,,297718806500.0,262049609200.0,,,907484500.0,11099401200.0,6978669400.0,-2799985800.0,-2826926600.0,,,,,,,,,,,36821983000.0,159426800.0,308553600.0,,36672856200.0,3215712700.0,33457143500.0,30729163500.0,2727980100.0,5046510500.0,38503654000.0,35452143600.0,3051510400.0,31406613600.0,44659154600.0,,,,15510453500.0,2132375400.0,3987365200.0,,,,,,,,,,,,,,,33457143500.0,0
|
|
||||||
300750.SZ,20230310,20230310,20221231,1,1,4,12.9178,12.8795,328593987500.0,328593987500.0,,,,,,,,,,,,,,,400241300.0,2514538600.0,2614517000.0,,297718806500.0,262049609200.0,,,907484500.0,11099401200.0,6978669400.0,-2799985800.0,-2826926600.0,,,,,,,,,,,36821983000.0,159426800.0,308553600.0,,36672856200.0,3215712700.0,33457143500.0,30729163500.0,2727980100.0,5046510500.0,38503654000.0,35452143600.0,3051510400.0,31406613600.0,44659154600.0,,,,15510453500.0,2132375400.0,3987365200.0,,,,,,,,,,,,,,,33457143500.0,1
|
|
||||||
300750.SZ,20221022,20221022,20220930,1,1,3,7.4704,7.4317,210340240500.0,210340240500.0,,,,,,,,,,,,,,,262789100.0,2744662400.0,2996607600.0,,192704656100.0,170480855400.0,,,568940800.0,7023199800.0,4471553700.0,-1842082800.0,-910439900.0,,,,,,,,,,,22458644500.0,115030000.0,246559100.0,,22327115300.0,2694951500.0,19632163800.0,17591591700.0,2040572100.0,3855361800.0,23487525600.0,21208643400.0,2278882300.0,18520693500.0,,,,,10576516000.0,1613622800.0,2602105100.0,,,,,,,,,,,,,,,19632163800.0,1
|
|
||||||
300750.SZ,20220824,20220824,20220630,1,1,2,3.5233,3.5047,112971257900.0,112971257900.0,,,,,,,,,,,,,,,215568200.0,1794546100.0,2019612300.0,,104388258600.0,91873351200.0,,,325839300.0,3467585200.0,2650226100.0,-357835300.0,-256621000.0,,,,,,,,,,,11683072000.0,79633500.0,52931500.0,,11709774000.0,2039812900.0,9669961200.0,8168034600.0,1501926500.0,1687656700.0,11357617900.0,10001392700.0,1356225200.0,9318827600.0,14666929800.0,,,,5768093100.0,1046506000.0,1440321000.0,,,,,,,,,,,,,,,9669961200.0,1
|
|
||||||
300750.SZ,20220430,20220430,20220331,1,1,1,0.6439,0.6405,48678419100.0,48678419100.0,,,,,,,,,,,,,,,,460911700.0,575976000.0,,47149190100.0,41627574200.0,,,158282700.0,1533477100.0,1245955100.0,-374100.0,5731600.0,,,,,,,,,,,2456137800.0,40882200.0,16663900.0,,2480356100.0,504896900.0,1975459100.0,1492804600.0,482654500.0,-1562500300.0,412958800.0,574861600.0,-161902800.0,1980534400.0,,,,,2568036600.0,488026200.0,661516300.0,,,,,,,,,,,,,,,1975459100.0,1
|
|
||||||
300750.SZ,20220422,20220422,20211231,1,1,4,6.876,6.8392,130355796400.0,130355796400.0,,,,,,,,,,,,,,,,1232699000.0,575836900.0,,113415030000.0,96093722300.0,,,486534200.0,4367869400.0,3368937100.0,-641200000.0,-2034437800.0,,,,,,,,,,,19823729200.0,183039700.0,119639800.0,,19887129100.0,2026399000.0,17860730100.0,15931317900.0,1929412300.0,3013987200.0,20874717400.0,19012644700.0,1862072600.0,18123376500.0,24560000600.0,,,,7691427600.0,1161100400.0,2323262000.0,,,,,,,,,,,,,,,17860730100.0,1
|
|
||||||
300750.SZ,20220422,20220422,20211231,1,1,4,6.876,6.8392,130355796400.0,130355796400.0,,,,,,,,,,,,,,,,1232699000.0,575836900.0,,113415030000.0,96093722300.0,,,486534200.0,4367869400.0,3368937100.0,-641200000.0,-2034437800.0,,,,,,,,,,,19823729200.0,183039700.0,119639800.0,,19887129100.0,2026399000.0,17860730100.0,15931317900.0,1929412300.0,3013987200.0,20874717400.0,19012644700.0,1862072600.0,18123376500.0,24560000600.0,,,,7691427600.0,1161100400.0,2323262000.0,,,,,,,,,,,,,,,17860730100.0,0
|
|
||||||
300750.SZ,20211028,20211028,20210930,1,1,3,3.3464,3.3323,73361545522.2,73361545522.2,,,,,,,,,,,,,,,,122219105.98,289494823.52,,63738850188.28,53179031934.71,,,333383540.3,2628002721.68,2226934203.99,-498402600.18,-1414630587.72,,,,,,,,,,,10891595620.99,68915266.17,86822687.86,,10873688199.3,1728706695.85,9144981503.45,7751145658.78,1393835844.67,1207017837.53,10351999340.98,8902714769.96,1449284571.02,11684094062.78,,,,,4594923266.82,721680591.36,1566751971.65,,,,,,,,,,,,,,,9144981503.45,1
|
|
||||||
300750.SZ,20210826,20210826,20210630,1,1,2,1.9416,1.9337,44074560629.16,44074560629.16,,,,,,,,,,,,,,,,117184251.12,225874649.39,,38515960372.41,32061735306.82,,,247186341.64,1593220857.92,1425297189.47,-422603555.91,-754103840.97,,,,,,,,,,,6316838359.17,56962628.74,38880638.18,,6334920349.73,1009812060.7,5325108289.03,4483787564.06,841320724.97,824254440.25,6149362729.28,5309066568.03,840296161.25,6545438974.9,9288553973.85,,,,2793753774.44,452359068.1,1070188235.09,,,,,,,,,,,,,,,5325108289.03,1
|
|
||||||
300750.SZ,20210430,20210430,20210331,1,1,1,0.8463,0.843,19166685223.52,19166685223.52,,,,,,,,,,,,,,,,6273485.03,39872868.34,,16759642781.58,13938104773.61,,,108324544.27,691753897.31,717159236.06,-199348756.05,-255909609.04,,,,,,,,,,,2806431714.88,20621617.04,31474885.15,,2795578446.77,451709061.44,2343869385.33,1954417236.62,389452148.71,-235029090.84,2108840294.49,1718301999.99,390538294.5,2856720791.99,,,,,1180785376.9,216287144.99,512078908.29,,,,,,,,,,,,,,,2343869385.33,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,2.4942,2.4848,50319487697.2,50319487697.2,,,,,,,,,,,,,,,286915936.0,-117648607.8,-4027332.09,,44655315480.69,36349153592.22,,,295129893.6,2216709532.73,1768115240.89,-712642421.45,-827489419.04,,,,,,,,,,,6959489551.43,94318062.61,71254204.8,,6982553409.24,878635356.78,6103918052.46,5583338710.38,520579342.08,505828698.82,6609746751.28,6089512016.47,520234734.81,6289688334.33,11157577849.15,,,,3569377694.03,640434316.54,1494600958.67,,,,,,,,,,,,,,,6103918052.46,1
|
|
||||||
300750.SZ,20210428,20210428,20201231,1,1,4,2.4942,2.4848,50319487697.2,50319487697.2,,,,,,,,,,,,,,,286915936.0,-117648607.8,-4027332.09,,44655315480.69,36349153592.22,,,295129893.6,2216709532.73,1768115240.89,-712642421.45,-827489419.04,,,,,,,,,,,6959489551.43,94318062.61,71254204.8,,6982553409.24,878635356.78,6103918052.46,5583338710.38,520579342.08,505828698.82,6609746751.28,6089512016.47,520234734.81,6289688334.33,11157577849.15,,,,3569377694.03,640434316.54,1494600958.67,,,,,,,,,,,,,,,6103918052.46,0
|
|
||||||
300750.SZ,20201028,20201028,20200930,1,1,3,1.5243,1.519,31522480929.97,31522480929.97,,,,,,,,,,,,,,,286915936.0,-343565018.81,-53737069.45,,27956553133.24,22883453805.41,,,174855655.78,1301071521.09,1154240525.66,-691223489.56,-817760655.74,,,,,,,,,,,4428419699.07,51173766.54,45152299.35,,4434441166.26,752230680.19,3682210486.07,3356875043.55,325335442.52,287180494.46,3969390980.53,3629938925.63,339452054.9,5295486705.97,,,,,2120160102.4,386867863.89,1070748621.8,,,,,,,,,,,,,,,3682210486.07,1
|
|
||||||
300750.SZ,20201028,20201028,20200930,1,1,3,1.5243,1.519,31522480929.97,31522480929.97,,,,,,,,,,,,,,,286915936.0,-343565018.81,-53737069.45,,27956553133.24,22883453805.41,,,174855655.78,1301071521.09,1154240525.66,-691223489.56,-817760655.74,,,,,,,,,,,4428419699.07,51173766.54,45152299.35,,4434441166.26,752230680.19,3682210486.07,3356875043.55,325335442.52,287180494.46,3969390980.53,3629938925.63,339452054.9,5295486705.97,,,,,2120160102.4,386867863.89,1070748621.8,,,,,,,,,,,,,,,3682210486.07,0
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,0.8833,0.8805,18829453132.97,18829453132.97,,,,,,,,,,,,,,,286915936.0,-406292308.07,-88395180.45,,16777260846.52,13717117142.14,,,101445380.16,792140085.18,809663593.83,-401913973.1,-338341629.6,,,,,,,,,,,2594040723.68,25328338.96,22713511.25,,2596655551.39,452737521.27,2143918030.12,1937281090.5,206636939.62,42364310.59,2186282340.71,1967490112.44,218792228.27,2311503122.65,4774464802.73,,,,1298453447.42,256688048.79,623732754.44,,,,,,,,,,,,,,,2143918030.12,0
|
|
||||||
300750.SZ,20200827,20200827,20200630,1,1,2,0.8833,0.8805,18829453132.97,18829453132.97,,,,,,,,,,,,,,,286915936.0,-406292308.07,-88395180.45,,16777260846.52,13717117142.14,,,101445380.16,792140085.18,809663593.83,-401913973.1,-338341629.6,,,,,,,,,,,2594040723.68,25328338.96,22713511.25,,2596655551.39,452737521.27,2143918030.12,1937281090.5,206636939.62,42364310.59,2186282340.71,1967490112.44,218792228.27,2311503122.65,4774464802.73,,,,1298453447.42,256688048.79,623732754.44,,,,,,,,,,,,,,,2143918030.12,1
|
|
||||||
300750.SZ,20200428,20200428,20200331,1,1,1,0.3406,0.3396,9030794052.46,9030794052.46,,,,,,,,,,,,,,,286915936.0,-348146749.47,-29567547.69,,8188919060.9,6764865485.58,,,54015270.55,352566282.28,412747503.97,-139684257.75,-96898077.07,,,,,,,,,,,1106046439.49,7194638.06,16264436.89,,1096976640.66,191963042.83,905013597.83,742043183.2,162970414.63,-118995658.48,786017939.35,651959025.75,134058913.6,1133338722.94,,,,,638663048.54,116204500.18,304532042.79,,,,,,,,,,,,,,,905013597.83,0
|
|
||||||
300750.SZ,20200428,20200428,20200331,1,1,1,0.3406,0.3396,9030794052.46,9030794052.46,,,,,,,,,,,,,,,286915936.0,-348146749.47,-29567547.69,,8188919060.9,6764865485.58,,,54015270.55,352566282.28,412747503.97,-139684257.75,-96898077.07,,,,,,,,,,,1106046439.49,7194638.06,16264436.89,,1096976640.66,191963042.83,905013597.83,742043183.2,162970414.63,-118995658.48,786017939.35,651959025.75,134058913.6,1312818614.89,,,,,638663048.54,116204500.18,304532042.79,,,,,,,,,,,,,,,905013597.83,1
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,2.0937,2.0887,45788020642.41,45788020642.41,,,,,,,,,,,,,,,27331582.1,-79604902.02,-11899568.84,,40624707856.41,32482760512.62,,,272228105.62,2156553541.51,1832673929.87,-781621299.53,-1434329163.69,,,,,,,,,,,5758793258.1,62428112.63,60456806.48,,5760764564.25,748090666.38,5012673897.87,4560307432.71,452366465.16,957658852.86,5970332750.73,5517966285.57,452366465.16,5722463917.76,10131504260.02,,,,2992107516.52,289254465.49,1078256966.28,,,,,,,,,,,,,,,5012673897.87,0
|
|
||||||
300750.SZ,20200425,20200425,20191231,1,1,4,2.0937,2.0887,45788020642.41,45788020642.41,,,,,,,,,,,,,,,27331582.1,-79604902.02,-11899568.84,,40624707856.41,32482760512.62,,,272228105.62,2156553541.51,1832673929.87,-781621299.53,-1434329163.69,,,,,,,,,,,5758793258.1,62428112.63,60456806.48,,5760764564.25,748090666.38,5012673897.87,4560307432.71,452366465.16,957658852.86,5970332750.73,5517966285.57,452366465.16,5722463917.76,10131504260.02,,,,2992107516.52,289254465.49,1078256966.28,,,,,,,,,,,,,,,5012673897.87,1
|
|
||||||
300750.SZ,20191026,20191026,20190930,1,1,3,1.6002,1.5959,32855706536.08,32855706536.08,,,,,,,,,,,,,,,,-62620220.59,-7917302.55,,28894615247.49,23301405480.87,,,201508967.69,1477529588.94,1629018744.75,-632605668.62,-550692987.35,,,,,,,,,,,4446278015.84,46102640.95,34688668.76,,4457691988.03,697474456.56,3760217531.47,3464305267.56,295912263.91,971764392.34,4731981923.81,4436069659.9,295912263.91,5059302675.96,,,,,2255954070.6,192122654.09,828347798.84,,,,,,,,,,,,,,,3760217531.47,1
|
|
||||||
300750.SZ,20191026,20191026,20190930,1,1,3,1.6002,1.5959,32855706536.08,32855706536.08,,,,,,,,,,,,,,,,-62620220.59,-7917302.55,,28894615247.49,23301405480.87,,,201508967.69,1477529588.94,1629018744.75,-632605668.62,-550692987.35,,,,,,,,,,,4446278015.84,46102640.95,34688668.76,,4457691988.03,697474456.56,3760217531.47,3464305267.56,295912263.91,971764392.34,4731981923.81,4436069659.9,295912263.91,4534188607.12,,,,,2255954070.6,192122654.09,828347798.84,,,,,,,,,,,,,,,3760217531.47,0
|
|
||||||
300750.SZ,20190824,20190824,20190630,1,1,2,0.9674,0.9666,20263844170.44,20263844170.44,,,,,,,,,,,,,,,,-45894420.7,-6203272.34,,17726032155.44,14226726997.42,,,117905051.7,804073640.0,1061946966.06,-428054892.49,-421525991.07,,,,,,,,,,,2812549873.07,10005017.82,17588816.33,,2804966074.56,458470774.12,2346495300.44,2102435142.7,244060157.74,235561659.09,2582056959.53,2337996801.79,244060157.74,2945403830.85,4885886347.94,,,,1413111807.02,119945783.05,532991928.58,,,,,,,,,,,,,,,2346495300.44,0
|
|
||||||
300750.SZ,20190427,20190427,20190331,1,1,1,0.48,0.48,9981855666.38,9981855666.38,,,,,,,,,,,,,,,,16802477.33,2097769.4,,8817890513.83,7116134804.4,,,86639222.05,401176198.42,525048115.72,-110462345.72,36205911.5,,,,,,,,,,,1321125127.01,6548666.78,5256479.6,,1322417314.19,205595113.39,1116822200.8,1047233226.95,69588973.85,161477040.74,1278299241.54,1208710267.69,69588973.85,1426164772.5,,,,,748586098.54,58662867.4,255070916.72,,,,,,,,,,,,,,,1116822200.8,0
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,1.6412,1.6407,29611265434.22,29611265434.22,,,,,,,,,,,,,,,-314247518.1,184397531.48,-4264014.31,,25729175371.38,19902284153.15,,,171183911.7,1378868425.55,1590659572.27,-279733226.14,974912150.01,,,,,,,,,,,4168476326.68,62303262.42,25966337.17,,4204813251.93,468916764.21,3735896487.72,3387035207.64,348861280.08,-585339219.51,3150557268.21,2801695988.13,348861280.08,4110132051.73,6414353208.21,,,,1991000384.84,204435332.83,565817388.3,,,,,,,,,,,,,,,3735896487.72,0
|
|
||||||
300750.SZ,20190425,20190425,20181231,1,1,4,1.6412,1.6407,29611265434.22,29611265434.22,,,,,,,,,,,,,,,-314247518.1,184397531.48,-4264014.31,,25729175371.38,19902284153.15,,,171183911.7,1378868425.55,1590659572.27,-279733226.14,974912150.01,,,,,,,,,,,4168476326.68,62303262.42,25966337.17,,4204813251.93,468916764.21,3735896487.72,3387035207.64,348861280.08,-585339219.51,3150557268.21,2801695988.13,348861280.08,4110132051.73,6414353208.21,,,,1991000384.84,204435332.83,565817388.3,,,,,,,,,,,,,,,3735896487.72,1
|
|
||||||
300750.SZ,20181026,20181026,20180930,1,1,3,1.17,1.17,19135923760.37,19135923760.37,,,,,,,,,,,,,,,,69427412.54,9583242.07,,16534427281.6,13150477803.26,,,101462647.63,846876034.25,983822491.58,-150717424.86,454657985.55,,,,,,,,,,,3071726107.71,15983636.65,4285602.67,,3083424141.69,441187671.13,2642236470.56,2378500010.06,263736460.5,-208586704.74,2433649765.82,2169913305.32,263736460.5,3467983671.62,,,,,1147847744.19,234936100.17,369419073.26,,,,,,,,,,,,,,,2642236470.56,1
|
|
||||||
300750.SZ,20181026,20181026,20180930,1,1,3,1.17,1.17,19135923760.37,19135923760.37,,,,,,,,,,,,,,,,69427412.54,9583242.07,,16534427281.6,13150477803.26,,,101462647.63,846876034.25,983822491.58,-150717424.86,454657985.55,,,,,,,,,,,3071726107.71,15983636.65,4285602.67,,3083424141.69,441187671.13,2642236470.56,2378500010.06,263736460.5,-208586704.74,2433649765.82,2169913305.32,263736460.5,3467983671.62,,,,,1147847744.19,234936100.17,369419073.26,,,,,,,,,,,,,,,2642236470.56,0
|
|
||||||
300750.SZ,20180824,20180824,20180630,1,1,2,0.4659,,9359580668.12,9359580668.12,,,,,,,,,,,,,,,,59838864.61,20009437.82,,8420213004.66,6431566540.72,,,35368966.71,448795383.07,1320335349.34,-22979347.63,207126112.45,,,,,,,,,,,1215792945.89,8159715.82,3277772.87,,1220674888.84,150781194.54,1069893694.3,910954288.0,158939406.3,-176351133.34,893542560.96,734603154.66,158939406.3,1135419727.12,2153190022.79,,,,,,,,,,,,,,,,,,,,,1069893694.3,0
|
|
||||||
300750.SZ,20180522,20180522,20180331,1,1,1,0.212,,3711641230.77,3711641230.77,,,,,,,,,,,,,,,,27972938.86,12043585.12,,3353698085.04,2495640398.99,,,14792182.15,147749265.04,565033595.37,2765177.74,127717465.75,,,,,,,,,,,539889042.27,3447660.53,2328501.22,,541008201.58,71743712.87,469264488.71,413347159.22,55917329.49,3179274.31,472443763.02,416526433.53,55917329.49,642726969.9,,,,,,,,,,,,,,,,,,,,,,469264488.71,0
|
|
||||||
300750.SZ,20180522,20180522,20171231,1,1,4,2.0084,,19996860806.33,19996860806.33,,,,,,,,,,,,,,,,1344305303.77,-49976783.37,,16875255721.27,12740187148.7,,,95900521.0,795766091.83,2956488278.51,42169650.35,244744030.88,,,,,,,,,,,4832020495.66,18655542.93,2575814.31,,4848100224.28,654043646.62,4194056577.66,3877954869.7,316101707.96,246933121.24,4440989698.9,4124887990.94,316101707.96,3608196383.76,4989378148.98,,,,,,,,,,,,,,,,,,,,,4194056577.66,0
|
|
||||||
300750.SZ,20181026,20181026,20170930,1,1,3,1.33,1.33,11970899899.45,11970899899.45,,,,,,,,,,,,,,,,1344112981.19,-19477989.06,,10402804866.65,7697664142.61,,,44337735.52,504161719.26,905233643.98,57697766.78,115122025.1,,,,,,,,,,,3293200146.4,13549843.33,4540268.55,,3302209721.18,470922060.98,2831287660.2,2570510205.15,260777455.05,344145542.58,3175433202.78,2914655747.73,260777455.05,2071982527.37,,,,,1078587833.4,85878529.21,33616243.84,,,,,,,,,,,,,,,2831287660.2,1
|
|
||||||
300750.SZ,20181026,20181026,20170930,1,1,3,1.33,1.33,11970899899.45,11970899899.45,,,,,,,,,,,,,,,,1344112981.19,-19477989.06,,10402804866.65,7697664142.61,,,44337735.52,504161719.26,905233643.98,57697766.78,115122025.1,,,,,,,,,,,3293200146.4,13549843.33,4540268.55,,3302209721.18,470922060.98,2831287660.2,2570510205.15,260777455.05,344145542.58,3175433202.78,2914655747.73,260777455.05,2124244812.74,,,,,1078587833.4,85878529.21,33616243.84,,,,,,,,,,,,,,,2831287660.2,0
|
|
||||||
300750.SZ,20171110,20171110,20170630,1,1,2,0.974,,6294695149.0,6294695149.0,,,,,,,,,,,,,,,,1245985248.03,-13175301.07,,5484178667.47,3934602921.36,,,24025547.56,269397374.58,1158841331.86,48134260.94,49177231.17,,,,,,,,,,,2328662915.71,6979859.43,2825898.64,2284479.0,2332816876.5,312073095.21,2020743781.29,1856935080.43,163808700.86,311938229.49,2332682010.78,2168873309.92,163808700.86,1179989159.79,1694788459.79,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20180522,20180522,20170331,1,1,1,-0.0189,,1454385691.84,1454385691.84,,,,,,,,,,,,,,,,85172231.78,-12978308.38,,1551974320.73,905259335.22,,,4410984.45,74633237.11,538433567.86,29237196.09,,,,,,,,,,,,-12738473.39,43140845.75,31953.67,,30370418.69,13875218.84,16495199.85,-11687915.1,35990121.09,81363.73,24383569.72,-11606551.37,35990121.09,-68351432.8,,,,,,,,,,,,,,,,,,,,,,16495199.85,0
|
|
||||||
300750.SZ,20180522,20180522,20161231,1,1,4,1.8736,,14878985098.12,14878985098.12,,,,,,,,,,,,,,,,76080348.84,21669756.19,,11584739495.37,8376801892.4,,,109215284.54,632190722.09,2152228887.34,80443838.96,233858870.04,,,,,,,,,,,3212120702.65,188974466.62,881463.97,,3400213705.3,481776851.01,2918436854.29,2851821419.26,66615435.03,888062.23,2919324916.52,2852709481.49,66615435.03,3374689441.71,4159176537.97,,,,,,,,,,,,,,,,,,,,,2918436854.29,0
|
|
||||||
300750.SZ,20161001,20161001,20160630,1,1,2,,,4786106400.0,4786106400.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,995792500.0,,,,,,4786106400.0,4786106400.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20160729,20160729,20160331,1,1,1,,,2088372900.0,2088372900.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,476764100.0,,,,,,2088372900.0,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
300750.SZ,20180522,20180522,20151231,1,1,4,0.7755,,5702884874.34,5702884874.34,,,,,,,,,,,,,,,,1455431.76,-9658518.48,,4658155646.48,3499202013.73,,,39629825.6,330920265.24,620575323.94,109186539.31,58641678.66,,,,,,,,,,,1045594555.74,71190367.14,16752779.33,,1100032143.55,149451069.1,950581074.45,930646375.1,19934699.35,494869.71,951075944.16,931141244.81,19934699.35,1153915767.17,1346241339.09,,,,,,,,,,,,,,,,,,,,,950581074.45,0
|
|
||||||
300750.SZ,20171110,20171110,20141231,1,1,4,,,866786361.55,866786361.55,,,,,,,,,,,,,,,,16117579.09,13024101.96,,866520694.75,643729807.47,,,10300.8,43294226.16,152321605.53,24573664.53,2591090.26,,,,,,,,,,,16383245.89,46216154.07,169330.58,102484.05,62430069.38,6866277.79,55563791.59,54425751.28,1138040.31,183958.4,55747749.99,54609709.68,1138040.31,27430421.59,94721521.59,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,trade_date,close,turnover_rate,turnover_rate_f,volume_ratio,pe,pe_ttm,pb,ps,ps_ttm,dv_ratio,dv_ttm,total_share,float_share,free_share,total_mv,circ_mv
|
|
||||||
300750.SZ,20251231,367.26,0.3765,0.5701,0.73,33.0287,26.2793,5.3318,4.6298,4.3416,1.3628,1.8399,456361.226,425638.5861,281129.1965,167603223.8608,156320027.1311
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
300750.SZ,20251021,20250930,227474
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
name,list_date
|
|
||||||
宁德时代,20180611
|
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,proc,exp_date,vol,amount,high_limit,low_limit
|
|
||||||
300750.SZ,20251010,20250930,实施,,15990782.0,4385504687.9,317.63,231.5
|
|
||||||
300750.SZ,20250902,20250831,实施,,8690006.0,2130545080.93,290.0,231.5
|
|
||||||
300750.SZ,20250506,20250430,实施,,6640986.0,1550809971.05,237.38,231.5
|
|
||||||
300750.SZ,20250425,20250425,实施,,1075275.0,254677939.51,237.38,236.01
|
|
||||||
300750.SZ,20250407,,预案,,,8000000000.0,392.32,
|
|
||||||
300750.SZ,20250224,20250221,完成,,71547.0,1412292.78,19.74,19.74
|
|
||||||
300750.SZ,20241227,,股东大会通过,,,1412292.78,19.74,19.74
|
|
||||||
300750.SZ,20241227,,股东大会通过,,,1412300.0,19.74,19.74
|
|
||||||
300750.SZ,20241030,20241030,完成,,15991524.0,2710713907.1,194.1,146.31
|
|
||||||
300750.SZ,20240909,,预案,,,1412292.78,19.74,19.74
|
|
||||||
300750.SZ,20240909,,预案,,,1412300.0,19.74,19.74
|
|
||||||
300750.SZ,20240801,20240731,实施,,15991524.0,2710713907.1,194.1,146.31
|
|
||||||
300750.SZ,20240701,20240630,实施,,14483830.0,2446006804.38,194.1,146.31
|
|
||||||
300750.SZ,20240618,20240617,完成,,46944.0,926700.0,19.74,19.74
|
|
||||||
300750.SZ,20240618,20240617,完成,,187070.0,3665800.0,19.74,19.53
|
|
||||||
300750.SZ,20240316,,预案,,,926700.0,19.74,19.74
|
|
||||||
300750.SZ,20240316,,预案,,,926700.0,19.74,19.74
|
|
||||||
300750.SZ,20240301,20240229,实施,,11609630.0,1896541059.43,181.16,146.31
|
|
||||||
300750.SZ,20240201,20240131,实施,,10367912.0,1700392748.16,181.16,146.31
|
|
||||||
300750.SZ,20240102,20231231,实施,,9086912.0,1503263150.63,181.16,146.31
|
|
||||||
300750.SZ,20231201,20231130,实施,,4377000.0,764172035.62,181.16,165.39
|
|
||||||
300750.SZ,20231120,20231117,实施,,1043098.0,188400157.46,181.16,179.53
|
|
||||||
300750.SZ,20231031,,预案,,,3000000000.0,294.45,
|
|
||||||
300750.SZ,20231031,,预案,,,3000000000.0,294.45,
|
|
||||||
300750.SZ,20231026,,提议,,,3000000000.0,,
|
|
||||||
300750.SZ,20231026,,预案,,,3000000000.0,,
|
|
||||||
300750.SZ,20230908,,预案,,,3665800.0,19.74,19.53
|
|
||||||
300750.SZ,20230908,,预案,,,3665800.0,19.74,19.53
|
|
||||||
300750.SZ,20230415,20230414,完成,,49240.0,1739161.2,,
|
|
||||||
300750.SZ,20230415,20230414,完成,,80320.0,2840089.6,,35.15
|
|
||||||
300750.SZ,20230415,20230414,完成,,49240.0,1739161.2,,
|
|
||||||
300750.SZ,20230415,20230414,完成,,80320.0,2840089.6,,35.15
|
|
||||||
300750.SZ,20230401,,股东大会通过,,,1739161.2,,
|
|
||||||
300750.SZ,20230401,,股东大会通过,,,2840089.6,,35.15
|
|
||||||
300750.SZ,20230401,,股东大会通过,,,1739161.2,,
|
|
||||||
300750.SZ,20230401,,股东大会通过,,,2840089.6,,35.15
|
|
||||||
300750.SZ,20230310,,预案,,,2840089.6,,35.15
|
|
||||||
300750.SZ,20230310,,预案,,,2840089.6,,35.15
|
|
||||||
300750.SZ,20220908,,预案,,,1739161.2,,
|
|
||||||
300750.SZ,20220908,,预案,,,1739161.2,,
|
|
||||||
300750.SZ,20220822,20220819,完成,,64050.0,2262867.7,,
|
|
||||||
300750.SZ,20220822,20220819,完成,,72240.0,2544799.2,,
|
|
||||||
300750.SZ,20220822,20220819,完成,,64050.0,2262867.7,,
|
|
||||||
300750.SZ,20220822,20220819,完成,,64050.0,2262900.0,,
|
|
||||||
300750.SZ,20220822,20220819,完成,,72240.0,2544799.2,,
|
|
||||||
300750.SZ,20220518,,股东大会通过,,,2262867.7,,35.53
|
|
||||||
300750.SZ,20220518,,股东大会通过,,,2544799.2,,
|
|
||||||
300750.SZ,20220518,,股东大会通过,,,2262867.7,,35.53
|
|
||||||
300750.SZ,20220518,,股东大会通过,,,2262900.0,,35.53
|
|
||||||
300750.SZ,20220518,,股东大会通过,,,2544799.2,,
|
|
||||||
300750.SZ,20220422,,预案,,,2544799.2,,
|
|
||||||
300750.SZ,20220422,,预案,,,2544799.2,,
|
|
||||||
300750.SZ,20210913,,预案,,,2262867.7,,35.53
|
|
||||||
300750.SZ,20210913,,预案,,,2262867.7,,35.53
|
|
||||||
300750.SZ,20210913,,预案,,,2262900.0,,35.53
|
|
||||||
300750.SZ,20210622,20210621,完成,,234010.0,8333884.58,35.53,35.15
|
|
||||||
300750.SZ,20210622,20210621,完成,,232216.0,8253933.71,35.53,35.15
|
|
||||||
300750.SZ,20210622,20210621,完成,,234010.0,8333884.58,35.53,35.15
|
|
||||||
300750.SZ,20210622,20210621,完成,,232216.0,8253933.71,35.53,35.15
|
|
||||||
300750.SZ,20210521,,股东大会通过,,,8253933.71,35.5442,35.5442
|
|
||||||
300750.SZ,20210521,,股东大会通过,,,8333884.58,,35.15
|
|
||||||
300750.SZ,20210521,,股东大会通过,,,8253933.71,35.5442,35.5442
|
|
||||||
300750.SZ,20210521,,股东大会通过,,,8333884.58,,35.15
|
|
||||||
300750.SZ,20210428,,预案,,,8333884.58,,35.15
|
|
||||||
300750.SZ,20210428,,预案,,,8333884.58,,35.15
|
|
||||||
300750.SZ,20200911,,预案,,,8253933.71,35.5442,35.5442
|
|
||||||
300750.SZ,20200911,,预案,,,8253933.71,35.5442,35.5442
|
|
||||||
300750.SZ,20200526,20200522,完成,,1034140.0,36630244.54,,
|
|
||||||
300750.SZ,20200526,20200522,完成,,251780.0,8871401.33,35.2347,35.2347
|
|
||||||
300750.SZ,20200526,20200522,完成,,1034140.0,36630244.54,,
|
|
||||||
300750.SZ,20200526,20200522,完成,,251780.0,8871401.33,35.2347,35.2347
|
|
||||||
300750.SZ,20200519,,股东大会通过,,,36630244.54,,
|
|
||||||
300750.SZ,20200519,,股东大会通过,,,36630244.54,,
|
|
||||||
300750.SZ,20200425,,预案,,,36630244.54,,
|
|
||||||
300750.SZ,20200425,,预案,,,36630244.54,,
|
|
||||||
300750.SZ,20190903,,预案,,,8871401.33,35.2347,35.2347
|
|
||||||
300750.SZ,20190903,,预案,,,8871401.33,35.2347,35.2347
|
|
||||||
300750.SZ,20190712,20190710,完成,,572400.0,20144982.22,,
|
|
||||||
300750.SZ,20190712,20190710,完成,,572400.0,20144982.22,,
|
|
||||||
300750.SZ,20190522,,股东大会通过,,,20144982.22,,
|
|
||||||
300750.SZ,20190522,,股东大会通过,,,20144982.22,,
|
|
||||||
300750.SZ,20190425,,预案,,,20144982.22,,
|
|
||||||
300750.SZ,20190425,,预案,,,20144982.22,,
|
|
||||||
|
@ -1,445 +0,0 @@
|
|||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>300750.SZ Financial Report</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f6fa;
|
|
||||||
--card-bg: #ffffff;
|
|
||||||
--header-bg: #f7f8fb;
|
|
||||||
--section-bg: #f0f2f5;
|
|
||||||
--border: #e5e7eb;
|
|
||||||
--text-primary: #111827;
|
|
||||||
--text-secondary: #6b7280;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 32px;
|
|
||||||
background: var(--bg);
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
color: var(--text-primary);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-container {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 32px 40px;
|
|
||||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 24px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: var(--card-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-align: right;
|
|
||||||
background: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:first-child,
|
|
||||||
td:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.company-table th,
|
|
||||||
.company-table td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
background: var(--card-bg);
|
|
||||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th:first-child {
|
|
||||||
left: 0;
|
|
||||||
z-index: 4;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table th:first-child,
|
|
||||||
.metrics-table td:first-child {
|
|
||||||
width: 180px;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
background: var(--card-bg);
|
|
||||||
font-weight: 600;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.04);
|
|
||||||
z-index: 2;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:not(:first-child) {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td:first-child {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody tr:hover td {
|
|
||||||
background: #f4efff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-row td {
|
|
||||||
background: #eef1f6;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-row td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-label {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-spacer {
|
|
||||||
background: #eef1f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-name {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container table {
|
|
||||||
margin-bottom: 0;
|
|
||||||
min-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-gap {
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data {
|
|
||||||
margin-top: 24px;
|
|
||||||
padding: 32px;
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-green { background-color: #e6f7eb !important; }
|
|
||||||
.bg-red { background-color: #ffeef0 !important; }
|
|
||||||
.font-red { color: #d32f2f !important; }
|
|
||||||
.font-green { color: #1b873f !important; }
|
|
||||||
.font-blue { color: #2563eb !important; }
|
|
||||||
.italic { font-style: italic !important; }
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body { padding: 16px; }
|
|
||||||
.report-container { padding: 24px; }
|
|
||||||
table { font-size: 0.85rem; }
|
|
||||||
th,
|
|
||||||
td { padding: 10px 12px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="report-container">
|
|
||||||
<h1>宁德时代 (300750.SZ) - Financial Report</h1>
|
|
||||||
<p><em>Report generated on: 2026-01-03</em></p>
|
|
||||||
|
|
||||||
<table class="company-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>代码</th>
|
|
||||||
<th>简称</th>
|
|
||||||
<th>上市日期</th>
|
|
||||||
<th>PE</th>
|
|
||||||
<th>PB</th>
|
|
||||||
<th>股息率(%)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>300750.SZ</td>
|
|
||||||
<td>宁德时代</td>
|
|
||||||
<td>2018-06-11</td>
|
|
||||||
<td>33.03</td>
|
|
||||||
<td>5.33</td>
|
|
||||||
<td>1.84%</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="table-gap"></div>
|
|
||||||
|
|
||||||
<table class="metrics-table" data-table="metrics" data-scrollable="true">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>指标</th>
|
|
||||||
<th>2025Q3</th><th>2024A</th><th>2023A</th><th>2022A</th><th>2021A</th><th>2020A</th><th>2019A</th><th>2018A</th><th>2017A</th><th>2016A</th><th>2015A</th><th>2014A</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="section-row"><td class="section-label">主要指标</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">ROE</td><td>15.60%</td><td>20.55%</td><td>22.32%</td><td>18.68%</td><td>18.85%</td><td>8.70%</td><td>11.96%</td><td>10.28%</td><td>15.70%</td><td>18.41%</td><td>74.23%</td><td>21.19%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROA</td><td>5.47%</td><td>6.45%</td><td>6.15%</td><td>5.11%</td><td>5.18%</td><td>3.56%</td><td>4.50%</td><td>4.58%</td><td>7.81%</td><td>9.98%</td><td>10.73%</td><td>1.89%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROCE/ROIC</td><td>11.87%</td><td>16.58%</td><td>16.87%</td><td>12.81%</td><td>14.82%</td><td>8.07%</td><td>12.35%</td><td>10.67%</td><td>12.26%</td><td>19.55%</td><td>36.60%</td><td>4.72%</td></tr>
|
|
||||||
<tr><td class="metric-name">毛利率</td><td>25.31%</td><td>24.44%</td><td>22.91%</td><td>20.25%</td><td>26.28%</td><td>27.76%</td><td>29.06%</td><td>32.79%</td><td>36.29%</td><td>43.70%</td><td>38.64%</td><td>25.73%</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润率</td><td>17.32%</td><td>14.02%</td><td>11.01%</td><td>9.35%</td><td>12.22%</td><td>11.10%</td><td>9.96%</td><td>11.44%</td><td>19.39%</td><td>19.17%</td><td>16.32%</td><td>6.28%</td></tr>
|
|
||||||
<tr><td class="metric-name">收入(亿)</td><td>2,830.72</td><td>3,620.13</td><td>4,009.17</td><td>3,285.94</td><td>1,303.56</td><td>503.19</td><td>457.88</td><td>296.11</td><td>199.97</td><td>148.79</td><td>57.03</td><td>8.67</td></tr>
|
|
||||||
<tr><td class="metric-name">收入增速</td><td>9.28%</td><td>-9.70%</td><td>22.01%</td><td>152.07%</td><td>159.06%</td><td>9.90%</td><td>54.63%</td><td>48.08%</td><td>34.40%</td><td>160.90%</td><td>557.93%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润(亿)</td><td>490.34</td><td>507.45</td><td>441.21</td><td>307.29</td><td>159.31</td><td>55.83</td><td>45.60</td><td>33.87</td><td>38.78</td><td>28.52</td><td>9.31</td><td>0.54</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润增速</td><td>36.20%</td><td>15.01%</td><td>43.58%</td><td>92.89%</td><td>185.34%</td><td>22.43%</td><td>34.64%</td><td>-12.66%</td><td>35.98%</td><td>206.43%</td><td>1609.94%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">经营净现金流(亿)</td><td>806.60</td><td>969.90</td><td>928.26</td><td>612.09</td><td>429.08</td><td>184.30</td><td>134.72</td><td>113.16</td><td>23.41</td><td>21.09</td><td>6.65</td><td>-1.39</td></tr>
|
|
||||||
<tr><td class="metric-name">资本开支(亿)</td><td>300.88</td><td>311.80</td><td>336.25</td><td>482.15</td><td>437.68</td><td>133.02</td><td>96.27</td><td>66.29</td><td>71.80</td><td>28.01</td><td>15.54</td><td>3.01</td></tr>
|
|
||||||
<tr><td class="metric-name">自由现金流(亿)</td><td>505.73</td><td>658.10</td><td>592.01</td><td>129.94</td><td>-8.60</td><td>51.28</td><td>38.45</td><td>46.87</td><td>-48.40</td><td>-6.92</td><td>-8.89</td><td>-4.39</td></tr>
|
|
||||||
<tr><td class="metric-name">分红(亿)</td><td>-</td><td>152.80</td><td>221.18</td><td>126.72</td><td>-</td><td>5.59</td><td>4.86</td><td>3.12</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">回购(亿)</td><td>-</td><td>129.80</td><td>129.84</td><td>0.32</td><td>0.90</td><td>2.54</td><td>1.39</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产(亿)</td><td>8,960.82</td><td>7,866.58</td><td>7,171.68</td><td>6,009.52</td><td>3,076.67</td><td>1,566.18</td><td>1,013.52</td><td>738.84</td><td>496.63</td><td>285.88</td><td>86.73</td><td>28.75</td></tr>
|
|
||||||
<tr><td class="metric-name">净资产(亿)</td><td>3,142.48</td><td>2,469.30</td><td>1,977.08</td><td>1,644.81</td><td>845.13</td><td>642.07</td><td>381.35</td><td>329.38</td><td>247.01</td><td>154.89</td><td>12.54</td><td>2.57</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉(亿)</td><td>8.91</td><td>8.95</td><td>7.08</td><td>7.04</td><td>5.28</td><td>1.48</td><td>1.48</td><td>1.00</td><td>1.00</td><td>1.00</td><td>1.00</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">费用指标</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">销售费用率</td><td>0.85%</td><td>0.98%</td><td>4.48%</td><td>3.38%</td><td>3.35%</td><td>4.41%</td><td>4.71%</td><td>4.66%</td><td>3.98%</td><td>4.25%</td><td>5.80%</td><td>4.99%</td></tr>
|
|
||||||
<tr><td class="metric-name">管理费用率</td><td>2.91%</td><td>2.68%</td><td>2.11%</td><td>2.12%</td><td>2.58%</td><td>3.51%</td><td>4.00%</td><td>5.37%</td><td>14.78%</td><td>14.46%</td><td>10.88%</td><td>17.57%</td></tr>
|
|
||||||
<tr><td class="metric-name">SG&A比例</td><td>3.76%</td><td>3.66%</td><td>6.59%</td><td>5.50%</td><td>5.94%</td><td>7.92%</td><td>8.71%</td><td>10.03%</td><td>18.76%</td><td>18.71%</td><td>16.68%</td><td>22.57%</td></tr>
|
|
||||||
<tr><td class="metric-name">研发费用率</td><td>5.32%</td><td>5.14%</td><td>4.58%</td><td>4.72%</td><td>5.90%</td><td>7.09%</td><td>6.53%</td><td>6.72%</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">其他费用率</td><td>-1.09%</td><td>1.63%</td><td>0.74%</td><td>0.68%</td><td>2.23%</td><td>1.66%</td><td>3.85%</td><td>4.60%</td><td>-1.87%</td><td>5.82%</td><td>5.64%</td><td>-3.11%</td></tr>
|
|
||||||
<tr><td class="metric-name">折旧费用占比</td><td>-</td><td>6.20%</td><td>5.26%</td><td>3.64%</td><td>4.49%</td><td>9.10%</td><td>9.04%</td><td>7.18%</td><td>6.40%</td><td>4.92%</td><td>2.88%</td><td>5.14%</td></tr>
|
|
||||||
<tr><td class="metric-name">所得税率</td><td>13.86%</td><td>14.52%</td><td>13.27%</td><td>8.77%</td><td>10.19%</td><td>12.58%</td><td>12.99%</td><td>11.15%</td><td>13.49%</td><td>14.17%</td><td>13.59%</td><td>11.00%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">资产占比</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">现金占比</td><td>36.18%</td><td>38.58%</td><td>36.85%</td><td>31.79%</td><td>28.95%</td><td>43.69%</td><td>31.84%</td><td>37.53%</td><td>28.35%</td><td>8.59%</td><td>14.91%</td><td>2.07%</td></tr>
|
|
||||||
<tr><td class="metric-name">库存占比</td><td>8.95%</td><td>7.61%</td><td>6.34%</td><td>12.76%</td><td>13.07%</td><td>8.44%</td><td>11.33%</td><td>9.58%</td><td>6.88%</td><td>4.76%</td><td>12.01%</td><td>10.85%</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款占比</td><td>7.42%</td><td>8.15%</td><td>8.93%</td><td>9.65%</td><td>7.72%</td><td>7.21%</td><td>8.23%</td><td>8.43%</td><td>13.93%</td><td>25.59%</td><td>27.60%</td><td>12.92%</td></tr>
|
|
||||||
<tr><td class="metric-name">预付款占比</td><td>1.51%</td><td>0.76%</td><td>0.97%</td><td>2.64%</td><td>2.10%</td><td>0.64%</td><td>0.53%</td><td>1.17%</td><td>0.62%</td><td>0.35%</td><td>0.81%</td><td>0.53%</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产占比</td><td>14.35%</td><td>14.31%</td><td>16.09%</td><td>14.82%</td><td>13.42%</td><td>12.53%</td><td>17.19%</td><td>15.67%</td><td>16.55%</td><td>13.04%</td><td>15.14%</td><td>8.45%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期投资占比</td><td>6.68%</td><td>6.97%</td><td>6.98%</td><td>2.93%</td><td>3.56%</td><td>3.07%</td><td>1.52%</td><td>1.31%</td><td>1.59%</td><td>0.59%</td><td>-</td><td>7.90%</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉占比</td><td>0.10%</td><td>0.11%</td><td>0.10%</td><td>0.12%</td><td>0.17%</td><td>0.09%</td><td>0.15%</td><td>0.14%</td><td>0.20%</td><td>0.35%</td><td>1.16%</td><td>-</td></tr>
|
|
||||||
<tr class="other-assets-row"><td class="metric-name">其他资产占比</td><td>24.80%</td><td>23.51%</td><td>23.75%</td><td>25.30%</td><td>31.02%</td><td>24.32%</td><td>29.22%</td><td>26.19%</td><td>31.87%</td><td>46.72%</td><td>28.37%</td><td>57.27%</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款占比</td><td>14.73%</td><td>16.65%</td><td>16.32%</td><td>15.73%</td><td>15.86%</td><td>9.98%</td><td>10.55%</td><td>9.55%</td><td>10.02%</td><td>11.10%</td><td>16.98%</td><td>13.38%</td></tr>
|
|
||||||
<tr><td class="metric-name">预收款占比</td><td>4.54%</td><td>3.54%</td><td>3.34%</td><td>3.73%</td><td>3.75%</td><td>4.39%</td><td>6.08%</td><td>6.76%</td><td>0.41%</td><td>0.31%</td><td>1.96%</td><td>0.30%</td></tr>
|
|
||||||
<tr><td class="metric-name">短期借款占比</td><td>4.50%</td><td>5.41%</td><td>3.09%</td><td>3.60%</td><td>5.09%</td><td>4.91%</td><td>3.16%</td><td>2.85%</td><td>5.26%</td><td>5.13%</td><td>21.90%</td><td>11.29%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期借款占比</td><td>8.75%</td><td>10.33%</td><td>11.64%</td><td>9.83%</td><td>7.19%</td><td>3.87%</td><td>4.91%</td><td>4.72%</td><td>4.29%</td><td>1.06%</td><td>0.00%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">运营资产占比</td><td>-1.38%</td><td>-3.67%</td><td>-3.43%</td><td>5.57%</td><td>3.28%</td><td>1.92%</td><td>3.46%</td><td>2.86%</td><td>11.00%</td><td>19.29%</td><td>21.49%</td><td>10.63%</td></tr>
|
|
||||||
<tr><td class="metric-name">有息负债率</td><td>13.25%</td><td>15.74%</td><td>14.73%</td><td>13.44%</td><td>12.28%</td><td>8.78%</td><td>8.07%</td><td>7.58%</td><td>9.54%</td><td>6.19%</td><td>21.90%</td><td>11.29%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">周转能力</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">存货周转天数</td><td>138</td><td>79</td><td>53</td><td>106</td><td>152</td><td>132</td><td>129</td><td>129</td><td>97</td><td>59</td><td>108</td><td>176</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款周转天数</td><td>85</td><td>64</td><td>58</td><td>64</td><td>66</td><td>81</td><td>66</td><td>76</td><td>126</td><td>179</td><td>153</td><td>156</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款周转天数</td><td>227</td><td>174</td><td>138</td><td>131</td><td>185</td><td>156</td><td>120</td><td>129</td><td>142</td><td>138</td><td>153</td><td>218</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产周转率</td><td>2.20</td><td>3.22</td><td>3.47</td><td>3.69</td><td>3.16</td><td>2.56</td><td>2.63</td><td>2.56</td><td>2.43</td><td>3.99</td><td>4.34</td><td>3.57</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产周转率</td><td>0.32</td><td>0.46</td><td>0.56</td><td>0.55</td><td>0.42</td><td>0.32</td><td>0.45</td><td>0.40</td><td>0.40</td><td>0.52</td><td>0.66</td><td>0.30</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">人均效率</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">员工人数</td><td>-</td><td>131,988</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创收(万)</td><td>-</td><td>274.28</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创利(万)</td><td>-</td><td>38.45</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均薪酬(万)</td><td>-</td><td>19.32</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">市场表现</td><td class="section-spacer" colspan="12"></td></tr>
|
|
||||||
<tr><td class="metric-name">股价</td><td>367.26</td><td>266.00</td><td>163.26</td><td>393.42</td><td>588.00</td><td>351.11</td><td>106.40</td><td>73.80</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">市值(亿)</td><td>16,760</td><td>11,713</td><td>7,182</td><td>9,609</td><td>13,705</td><td>8,179</td><td>2,350</td><td>1,620</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PE</td><td>33.03</td><td>26.55</td><td>23.37</td><td>60.32</td><td>245.47</td><td>179.35</td><td>69.37</td><td>41.77</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PB</td><td>5.33</td><td>4.94</td><td>3.98</td><td>6.40</td><td>18.74</td><td>13.33</td><td>6.36</td><td>5.01</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">股东户数</td><td>227,474</td><td>212,061</td><td>260,992</td><td>183,317</td><td>141,963</td><td>133,060</td><td>76,710</td><td>82,514</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const scrollableTables = document.querySelectorAll('table[data-scrollable="true"]');
|
|
||||||
scrollableTables.forEach(table => {
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'table-container';
|
|
||||||
table.parentNode.insertBefore(container, table);
|
|
||||||
container.appendChild(table);
|
|
||||||
});
|
|
||||||
|
|
||||||
const parseValue = (text) => {
|
|
||||||
if (!text || text.trim() === '-') return null;
|
|
||||||
return parseFloat(text.replace(/%|,/g, ''));
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightIfOverThirtyPercent = (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 30) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleRules = {
|
|
||||||
'ROE': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 15) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'ROA': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 10) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'毛利率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 50) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'净利润率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 20) {
|
|
||||||
cell.classList.add('bg-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'收入增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'净利润增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'经营净现金流(亿)': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value < 0) cell.classList.add('bg-red', 'font-red');
|
|
||||||
},
|
|
||||||
'应收款周转天数': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 90) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'现金占比': highlightIfOverThirtyPercent,
|
|
||||||
'库存占比': highlightIfOverThirtyPercent,
|
|
||||||
'应收款占比': highlightIfOverThirtyPercent,
|
|
||||||
'预付款占比': highlightIfOverThirtyPercent,
|
|
||||||
'固定资产占比': highlightIfOverThirtyPercent,
|
|
||||||
'长期投资占比': highlightIfOverThirtyPercent,
|
|
||||||
'商誉占比': highlightIfOverThirtyPercent,
|
|
||||||
'其他资产占比': highlightIfOverThirtyPercent
|
|
||||||
};
|
|
||||||
|
|
||||||
const metricsTables = document.querySelectorAll('table[data-table="metrics"]');
|
|
||||||
metricsTables.forEach(table => {
|
|
||||||
let netProfitValues = [];
|
|
||||||
let fcfRow = null;
|
|
||||||
const rows = table.querySelectorAll('tbody tr');
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
if (metricName === '净利润(亿)') {
|
|
||||||
row.querySelectorAll('td:not(:first-child)').forEach(cell => {
|
|
||||||
netProfitValues.push(parseValue(cell.textContent));
|
|
||||||
});
|
|
||||||
} else if (metricName === '自由现金流(亿)') {
|
|
||||||
fcfRow = row;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
const cells = row.querySelectorAll('td:not(:first-child)');
|
|
||||||
if (styleRules[metricName]) {
|
|
||||||
cells.forEach(cell => {
|
|
||||||
styleRules[metricName](cell);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (row === fcfRow && netProfitValues.length > 0) {
|
|
||||||
cells.forEach((cell, index) => {
|
|
||||||
const fcfValue = parseValue(cell.textContent);
|
|
||||||
const netProfitValue = netProfitValues[index];
|
|
||||||
if (fcfValue !== null) {
|
|
||||||
if (fcfValue < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else if (netProfitValue !== null && fcfValue > netProfitValue) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# 宁德时代 (300750.SZ) - Financial Report
|
|
||||||
*Report generated on: 2026-01-03*
|
|
||||||
|
|
||||||
| 代码 | 简称 | 上市日期 | PE | PB | 股息率(%) |
|
|
||||||
|:---|:---|:---|:---|:---|:---|
|
|
||||||
| 300750.SZ | 宁德时代 | 2018-06-11 | 33.03 | 5.33 | 1.84% |
|
|
||||||
|
|
||||||
|
|
||||||
## 主要指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| ROE | 15.60% | 20.55% | 22.32% | 18.68% | 18.85% | 8.70% | 11.96% | 10.28% | 15.70% | 18.41% | 74.23% | 21.19% |
|
|
||||||
| ROA | 5.47% | 6.45% | 6.15% | 5.11% | 5.18% | 3.56% | 4.50% | 4.58% | 7.81% | 9.98% | 10.73% | 1.89% |
|
|
||||||
| ROCE/ROIC | 11.87% | 16.58% | 16.87% | 12.81% | 14.82% | 8.07% | 12.35% | 10.67% | 12.26% | 19.55% | 36.60% | 4.72% |
|
|
||||||
| 毛利率 | 25.31% | 24.44% | 22.91% | 20.25% | 26.28% | 27.76% | 29.06% | 32.79% | 36.29% | 43.70% | 38.64% | 25.73% |
|
|
||||||
| 净利润率 | 17.32% | 14.02% | 11.01% | 9.35% | 12.22% | 11.10% | 9.96% | 11.44% | 19.39% | 19.17% | 16.32% | 6.28% |
|
|
||||||
| 收入(亿) | 2,830.72 | 3,620.13 | 4,009.17 | 3,285.94 | 1,303.56 | 503.19 | 457.88 | 296.11 | 199.97 | 148.79 | 57.03 | 8.67 |
|
|
||||||
| 收入增速 | 9.28% | -9.70% | 22.01% | 152.07% | 159.06% | 9.90% | 54.63% | 48.08% | 34.40% | 160.90% | 557.93% | - |
|
|
||||||
| 净利润(亿) | 490.34 | 507.45 | 441.21 | 307.29 | 159.31 | 55.83 | 45.60 | 33.87 | 38.78 | 28.52 | 9.31 | 0.54 |
|
|
||||||
| 净利润增速 | 36.20% | 15.01% | 43.58% | 92.89% | 185.34% | 22.43% | 34.64% | -12.66% | 35.98% | 206.43% | 1609.94% | - |
|
|
||||||
| 经营净现金流(亿) | 806.60 | 969.90 | 928.26 | 612.09 | 429.08 | 184.30 | 134.72 | 113.16 | 23.41 | 21.09 | 6.65 | -1.39 |
|
|
||||||
| 资本开支(亿) | 300.88 | 311.80 | 336.25 | 482.15 | 437.68 | 133.02 | 96.27 | 66.29 | 71.80 | 28.01 | 15.54 | 3.01 |
|
|
||||||
| 自由现金流(亿) | 505.73 | 658.10 | 592.01 | 129.94 | -8.60 | 51.28 | 38.45 | 46.87 | -48.40 | -6.92 | -8.89 | -4.39 |
|
|
||||||
| 分红(亿) | - | 152.80 | 221.18 | 126.72 | - | 5.59 | 4.86 | 3.12 | - | - | - | - |
|
|
||||||
| 回购(亿) | - | 129.80 | 129.84 | 0.32 | 0.90 | 2.54 | 1.39 | - | - | - | - | - |
|
|
||||||
| 总资产(亿) | 8,960.82 | 7,866.58 | 7,171.68 | 6,009.52 | 3,076.67 | 1,566.18 | 1,013.52 | 738.84 | 496.63 | 285.88 | 86.73 | 28.75 |
|
|
||||||
| 净资产(亿) | 3,142.48 | 2,469.30 | 1,977.08 | 1,644.81 | 845.13 | 642.07 | 381.35 | 329.38 | 247.01 | 154.89 | 12.54 | 2.57 |
|
|
||||||
| 商誉(亿) | 8.91 | 8.95 | 7.08 | 7.04 | 5.28 | 1.48 | 1.48 | 1.00 | 1.00 | 1.00 | 1.00 | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 费用指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 销售费用率 | 0.85% | 0.98% | 4.48% | 3.38% | 3.35% | 4.41% | 4.71% | 4.66% | 3.98% | 4.25% | 5.80% | 4.99% |
|
|
||||||
| 管理费用率 | 2.91% | 2.68% | 2.11% | 2.12% | 2.58% | 3.51% | 4.00% | 5.37% | 14.78% | 14.46% | 10.88% | 17.57% |
|
|
||||||
| SG&A比例 | 3.76% | 3.66% | 6.59% | 5.50% | 5.94% | 7.92% | 8.71% | 10.03% | 18.76% | 18.71% | 16.68% | 22.57% |
|
|
||||||
| 研发费用率 | 5.32% | 5.14% | 4.58% | 4.72% | 5.90% | 7.09% | 6.53% | 6.72% | - | - | - | - |
|
|
||||||
| 其他费用率 | -1.09% | 1.63% | 0.74% | 0.68% | 2.23% | 1.66% | 3.85% | 4.60% | -1.87% | 5.82% | 5.64% | -3.11% |
|
|
||||||
| 折旧费用占比 | - | 6.20% | 5.26% | 3.64% | 4.49% | 9.10% | 9.04% | 7.18% | 6.40% | 4.92% | 2.88% | 5.14% |
|
|
||||||
| 所得税率 | 13.86% | 14.52% | 13.27% | 8.77% | 10.19% | 12.58% | 12.99% | 11.15% | 13.49% | 14.17% | 13.59% | 11.00% |
|
|
||||||
|
|
||||||
|
|
||||||
## 资产占比
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 现金占比 | 36.18% | 38.58% | 36.85% | 31.79% | 28.95% | 43.69% | 31.84% | 37.53% | 28.35% | 8.59% | 14.91% | 2.07% |
|
|
||||||
| 库存占比 | 8.95% | 7.61% | 6.34% | 12.76% | 13.07% | 8.44% | 11.33% | 9.58% | 6.88% | 4.76% | 12.01% | 10.85% |
|
|
||||||
| 应收款占比 | 7.42% | 8.15% | 8.93% | 9.65% | 7.72% | 7.21% | 8.23% | 8.43% | 13.93% | 25.59% | 27.60% | 12.92% |
|
|
||||||
| 预付款占比 | 1.51% | 0.76% | 0.97% | 2.64% | 2.10% | 0.64% | 0.53% | 1.17% | 0.62% | 0.35% | 0.81% | 0.53% |
|
|
||||||
| 固定资产占比 | 14.35% | 14.31% | 16.09% | 14.82% | 13.42% | 12.53% | 17.19% | 15.67% | 16.55% | 13.04% | 15.14% | 8.45% |
|
|
||||||
| 长期投资占比 | 6.68% | 6.97% | 6.98% | 2.93% | 3.56% | 3.07% | 1.52% | 1.31% | 1.59% | 0.59% | - | 7.90% |
|
|
||||||
| 商誉占比 | 0.10% | 0.11% | 0.10% | 0.12% | 0.17% | 0.09% | 0.15% | 0.14% | 0.20% | 0.35% | 1.16% | - |
|
|
||||||
| 其他资产占比 | 24.80% | 23.51% | 23.75% | 25.30% | 31.02% | 24.32% | 29.22% | 26.19% | 31.87% | 46.72% | 28.37% | 57.27% |
|
|
||||||
| 应付款占比 | 14.73% | 16.65% | 16.32% | 15.73% | 15.86% | 9.98% | 10.55% | 9.55% | 10.02% | 11.10% | 16.98% | 13.38% |
|
|
||||||
| 预收款占比 | 4.54% | 3.54% | 3.34% | 3.73% | 3.75% | 4.39% | 6.08% | 6.76% | 0.41% | 0.31% | 1.96% | 0.30% |
|
|
||||||
| 短期借款占比 | 4.50% | 5.41% | 3.09% | 3.60% | 5.09% | 4.91% | 3.16% | 2.85% | 5.26% | 5.13% | 21.90% | 11.29% |
|
|
||||||
| 长期借款占比 | 8.75% | 10.33% | 11.64% | 9.83% | 7.19% | 3.87% | 4.91% | 4.72% | 4.29% | 1.06% | 0.00% | 0.00% |
|
|
||||||
| 运营资产占比 | -1.38% | -3.67% | -3.43% | 5.57% | 3.28% | 1.92% | 3.46% | 2.86% | 11.00% | 19.29% | 21.49% | 10.63% |
|
|
||||||
| 有息负债率 | 13.25% | 15.74% | 14.73% | 13.44% | 12.28% | 8.78% | 8.07% | 7.58% | 9.54% | 6.19% | 21.90% | 11.29% |
|
|
||||||
|
|
||||||
|
|
||||||
## 周转能力
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 存货周转天数 | 138 | 79 | 53 | 106 | 152 | 132 | 129 | 129 | 97 | 59 | 108 | 176 |
|
|
||||||
| 应收款周转天数 | 85 | 64 | 58 | 64 | 66 | 81 | 66 | 76 | 126 | 179 | 153 | 156 |
|
|
||||||
| 应付款周转天数 | 227 | 174 | 138 | 131 | 185 | 156 | 120 | 129 | 142 | 138 | 153 | 218 |
|
|
||||||
| 固定资产周转率 | 2.20 | 3.22 | 3.47 | 3.69 | 3.16 | 2.56 | 2.63 | 2.56 | 2.43 | 3.99 | 4.34 | 3.57 |
|
|
||||||
| 总资产周转率 | 0.32 | 0.46 | 0.56 | 0.55 | 0.42 | 0.32 | 0.45 | 0.40 | 0.40 | 0.52 | 0.66 | 0.30 |
|
|
||||||
|
|
||||||
|
|
||||||
## 人均效率
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 员工人数 | - | 131,988 | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均创收(万) | - | 274.28 | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均创利(万) | - | 38.45 | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均薪酬(万) | - | 19.32 | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 市场表现
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A | 2015A | 2014A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 股价 | 367.26 | 266.00 | 163.26 | 393.42 | 588.00 | 351.11 | 106.40 | 73.80 | - | - | - | - |
|
|
||||||
| 市值(亿) | 16,760 | 11,713 | 7,182 | 9,609 | 13,705 | 8,179 | 2,350 | 1,620 | - | - | - | - |
|
|
||||||
| PE | 33.03 | 26.55 | 23.37 | 60.32 | 245.47 | 179.35 | 69.37 | 41.77 | - | - | - | - |
|
|
||||||
| PB | 5.33 | 4.94 | 3.98 | 6.40 | 18.74 | 13.33 | 6.36 | 5.01 | - | - | - | - |
|
|
||||||
| 股东户数 | 227,474 | 212,061 | 260,992 | 183,317 | 141,963 | 133,060 | 76,710 | 82,514 | - | - | - | - |
|
|
||||||
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
date_str,Price,PE,PB,MarketCap,Shareholders
|
|
||||||
20250930,19.28,26.6914,2.1851,6103652104.0,12225.0
|
|
||||||
20241231,16.33,31.8397,1.8835,5169742680.0,12364.0
|
|
||||||
20240930,17.66,34.4329,1.844,5590793370.000001,12979.0
|
|
||||||
20231231,17.33,42.0868,1.8442,5486322145.999999,15965.0
|
|
||||||
20221231,,,,,7.0
|
|
||||||
20211231,,,,,
|
|
||||||
20201231,,,,,
|
|
||||||
20191231,,,,,
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,total_share,cap_rese,undistr_porfit,surplus_rese,special_rese,money_cap,trad_asset,notes_receiv,accounts_receiv,oth_receiv,prepayment,div_receiv,int_receiv,inventories,amor_exp,nca_within_1y,sett_rsrv,loanto_oth_bank_fi,premium_receiv,reinsur_receiv,reinsur_res_receiv,pur_resale_fa,oth_cur_assets,total_cur_assets,fa_avail_for_sale,htm_invest,lt_eqt_invest,invest_real_estate,time_deposits,oth_assets,lt_rec,fix_assets,cip,const_materials,fixed_assets_disp,produc_bio_assets,oil_and_gas_assets,intan_assets,r_and_d,goodwill,lt_amor_exp,defer_tax_assets,decr_in_disbur,oth_nca,total_nca,cash_reser_cb,depos_in_oth_bfi,prec_metals,deriv_assets,rr_reins_une_prem,rr_reins_outstd_cla,rr_reins_lins_liab,rr_reins_lthins_liab,refund_depos,ph_pledge_loans,refund_cap_depos,indep_acct_assets,client_depos,client_prov,transac_seat_fee,invest_as_receiv,total_assets,lt_borr,st_borr,cb_borr,depos_ib_deposits,loan_oth_bank,trading_fl,notes_payable,acct_payable,adv_receipts,sold_for_repur_fa,comm_payable,payroll_payable,taxes_payable,int_payable,div_payable,oth_payable,acc_exp,deferred_inc,st_bonds_payable,payable_to_reinsurer,rsrv_insur_cont,acting_trading_sec,acting_uw_sec,non_cur_liab_due_1y,oth_cur_liab,total_cur_liab,bond_payable,lt_payable,specific_payables,estimated_liab,defer_tax_liab,defer_inc_non_cur_liab,oth_ncl,total_ncl,depos_oth_bfi,deriv_liab,depos,agency_bus_liab,oth_liab,prem_receiv_adva,depos_received,ph_invest,reser_une_prem,reser_outstd_claims,reser_lins_liab,reser_lthins_liab,indept_acc_liab,pledge_borr,indem_payable,policy_div_payable,total_liab,treasury_share,ordin_risk_reser,forex_differ,invest_loss_unconf,minority_int,total_hldr_eqy_exc_min_int,total_hldr_eqy_inc_min_int,total_liab_hldr_eqy,lt_payroll_payable,oth_comp_income,oth_eqt_tools,oth_eqt_tools_p_shr,lending_funds,acc_receivable,st_fin_payable,payables,hfs_assets,hfs_sales,cost_fin_assets,fair_value_fin_assets,contract_assets,contract_liab,accounts_receiv_bill,accounts_pay,oth_rcv_total,fix_assets_total,cip_total,oth_pay_total,long_pay_total,debt_invest,oth_debt_invest,update_flag
|
|
||||||
688334.SH,20251022,20251022,20250930,1,1,3,316579466.0,2126849242.42,359198226.63,56145760.28,,958101465.03,255000000.0,65922503.07,122902597.89,,10627348.38,,,55860555.79,,569253743.0,,,,,,,14151955.63,2053255878.37,,,33639874.31,,,,,,9633886.5,,,,,120943268.05,,23716852.85,,2910346.65,,16199037.64,1628167683.86,,,,,,,,,,,,,,,,,3681423562.23,33618259.83,,,,,,,73695517.18,,,,50000302.78,18338526.53,,,,,,,,,,,4891580.71,16389194.76,462890978.1,,,,,26652295.13,71695132.01,,153409379.33,,,,,,,,,,,,,,,,,616300357.43,,,,,207030509.47,2858092695.33,3065123204.8,3681423562.23,11780000.0,-680000.0,,,,,,,,,,,,293292107.7,188825100.96,73695517.18,1435709.58,995912119.98,9633886.5,6283748.44,9603639.91,423295458.32,,0
|
|
||||||
688334.SH,20250821,20250821,20250630,1,1,2,316579466.0,2126849242.42,367528100.04,56145760.28,,1137566182.9,,45433707.78,116798179.89,1568958.95,8492140.9,,,58870674.19,,375599099.4,,,,,,,17835826.52,1762183295.53,,,33431639.26,,,,,1021686763.6,7570975.74,,,,,123020106.32,,23716852.85,,2913258.03,,8424537.64,1936811731.14,,,,,,,,,,,,,,,,,3698995026.67,33614527.22,,,,,,,74665774.95,,,,34142250.58,9189817.3,,,6074403.46,,,,,,,,4891580.71,19530154.12,477255250.32,,9603639.9,0.0,,26870887.83,73951454.2,,156762441.19,,,,,,,,,,,,,,,,,634017691.51,,,,,198554766.42,2866422568.74,3064977335.16,3698995026.67,11780000.0,-680000.0,,,,,,,,,,,18525.0,328761269.2,162231887.67,74665774.95,1568958.95,1021686763.6,7570975.74,6074403.46,9603639.9,713196955.6,,0
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,316579466.0,2126849242.42,342117182.66,56145760.28,,822894685.51,260000000.0,71574744.07,110429551.03,,17230433.4,,,52487546.87,,365650386.0,,,,,,,20311852.37,1721685667.01,,,33514628.83,,,,,,,,,,,125102107.86,,23716852.85,,3008647.04,,2868600.0,1945649414.43,,,,,,,,,,,,,,,,,3667335081.44,33591200.0,,,,,,,131200821.74,,,,14863946.31,13179927.93,,,,,,,,,,,5732081.8,21962134.99,506958713.93,,,,,26775514.32,76662182.79,,159225607.74,,,,,,,,,,,,,,,,,666184321.67,,,,,160059108.41,2841091651.36,3001150759.77,3667335081.44,11620000.0,-600000.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,316579466.0,2126849242.42,342117182.66,56145760.28,,822894685.51,260000000.0,71574744.07,110429551.03,,17230433.4,,,52487546.87,,365650386.0,,,,,,,20311852.37,1721685667.01,,,33514628.83,,,,,,7224161.43,,,,,125102107.86,,23716852.85,,3008647.04,,2868600.0,1945649414.43,,,,,,,,,,,,,,,,,3667335081.44,33591200.0,,,,,,,131200821.74,,,,14863946.31,13179927.93,,,,,,,,,,,5732081.8,21962134.99,506958713.93,,,,,26775514.32,76662182.79,,159225607.74,,,,,,,,,,,,,,,,,666184321.67,,,,,160059108.41,2841091651.36,3001150759.77,3667335081.44,11620000.0,-600000.0,,,,,,,,,,,18525.0,315349634.5,182004295.1,131200821.74,1087942.76,1051896635.54,7224161.43,4670166.66,9604086.56,694533336.25,,1
|
|
||||||
688334.SH,20250411,20250411,20241231,1,1,4,316579466.0,2126849242.42,279142979.23,56145760.28,,1054330577.41,,75073721.94,97051453.54,812763.36,6693483.71,,,51847329.48,,267475538.22,,,,,,,23757642.76,1577061035.42,,,33339030.59,,,,,1083800226.26,6673114.52,,157638.44,,,127237272.52,,23716852.85,,2997871.56,,3240687.64,1971016116.74,,,,,,,,,,,,,,,,,3548077152.16,,,,,,,,124433136.78,,,,6671431.76,14290966.37,0.0,31657946.6,3646354.73,,,,,,,,7600574.21,20056119.3,490628860.57,,9604086.55,0.0,,26994107.02,80194969.72,,128607268.81,,,,,,,,,,,,,,,,,619236129.38,,,,,150723574.85,2778117447.93,2928841022.78,3548077152.16,11620000.0,-600000.0,,,,,,,,,,,18525.0,282272330.82,172125175.48,124433136.78,812763.36,1083957864.7,6673114.52,35304301.33,9604086.55,685349494.31,,0
|
|
||||||
688334.SH,20241030,20241030,20240930,1,1,3,316579466.0,2126849242.42,315056546.33,36092710.23,,501472308.23,545000000.0,63225665.13,166471855.14,,6981484.75,,,48840365.57,,178047037.77,,,,,,,21584327.53,1532625029.58,,,33318971.47,,,,,1073957284.05,1395917.32,,,,,126892784.79,,23227861.11,,3493317.74,,15633181.41,2021049145.58,,,,,,,,,,,,,,,,,3553674175.16,,,,,,,,212788079.25,,,,27798195.58,26393625.6,,,,,,,,,,,7603097.03,11536323.99,486066659.38,,,,,27202476.54,81750709.22,,134316592.93,,,,,,,,,,,,,,,,,620383252.31,,,,,138452957.87,2794837964.98,2933290922.85,3553674175.16,10810000.0,260000.0,,,,,,,,,,,18525.0,193609684.61,229697520.27,212788079.25,983460.46,1073957284.05,1395917.32,6337653.32,13404906.56,737692097.1,,0
|
|
||||||
688334.SH,20240830,20240830,20240630,1,1,2,316579466.0,2489803394.01,196193705.0,29058687.84,,955522097.63,,50722820.87,72939143.73,769986.02,3212973.83,,,41859111.76,,513851572.88,,,,,,,8504669.32,1647400901.04,,,33312530.51,,,,,827992298.75,1345150.0,,,,,100690969.91,,23256838.51,,2454945.18,,16781569.94,1844795117.11,,,,,,,,,,,,,,,,,3492196018.15,,,,,,,,48518339.26,,,,19567037.19,17184742.15,,,7601424.58,,,,,,,,7527449.03,12543246.27,321996342.99,,13404906.57,0.0,,27363940.94,84766448.72,,138304422.31,,,,,,,,,,,,,,,,,460300765.3,,,,,,3031895252.85,3031895252.85,3492196018.15,10810000.0,260000.0,,,,,,,,,,,18525.0,209054104.51,123661964.6,48518339.26,769986.02,827992298.75,1345150.0,7601424.58,13404906.57,832697139.94,,0
|
|
||||||
688334.SH,20240430,20240430,20240331,1,1,1,316579466.0,2489803394.01,224725878.92,29058687.84,,663623218.16,280000000.0,76690382.1,71604981.98,,12012468.55,,,44391732.58,,433488333.33,,,,,,,6739882.11,1590023283.92,,,33181636.33,,,,,805558688.24,6987856.55,,,,,100912931.75,,23716852.85,,2666559.82,,31312845.0,1912767887.05,,,,,,,,,,,,,,,,,3502791170.97,,,,,,,3000000.0,39588332.67,,,,8969577.27,12526922.38,,,,,,,,,,,7440429.99,15256166.54,298005832.89,,,,,28648995.57,86481188.22,,144607911.31,,,,,,,,,,,,,,,,,442613744.2,,,,,,3060177426.77,3060177426.77,3502791170.97,11250000.0,10000.0,,,,,,,,,,,302100.0,199514083.53,148295364.08,42588332.67,1170185.11,805558688.24,6987856.55,11710320.51,13405479.91,901322455.78,,0
|
|
||||||
688334.SH,20240411,20240411,20231231,1,1,4,316579466.0,2489803394.01,178129426.48,29058687.84,,863748210.71,,104881495.03,35711610.22,499071.0,4852150.6,,,54020475.84,,430135555.56,,,,,,,11594735.18,1505746924.14,,,33051587.46,,,,,825553724.31,6836580.64,,,,,102747609.11,,23716852.85,,2669336.95,,32981473.2,1930430437.1,,,,,,,,,,,,,,,,,3436177361.24,,,,,,,,38507685.26,,,,3888182.58,12134350.73,,,5154786.68,,,,,,,,7440429.99,16674905.25,274176050.89,,13405479.91,0.0,,28867588.29,90037227.72,,148420336.02,,,,,,,,,,,,,,,,,422596386.91,,,,,,3013580974.33,3013580974.33,3436177361.24,11250000.0,10000.0,,,,,,,,,,,303620.0,190375710.4,140593105.25,38507685.26,499071.0,825553724.31,6836580.64,5154786.68,13405479.91,894849385.77,,1
|
|
||||||
688334.SH,20240411,20240411,20231231,1,1,4,316579466.0,2489803394.01,178129426.48,29058687.84,,863748210.71,,104881495.03,35711610.22,499071.0,4852150.6,,,54020475.84,,430135555.56,,,,,,,11594735.18,1505746924.14,,,33051587.46,,,,,825553724.31,6836580.64,,,,,102747609.11,,23716852.85,,2669336.95,,32981473.2,1930430437.1,,,,,,,,,,,,,,,,,3436177361.24,,,,,,,,38507685.26,,,,3888182.58,12134350.73,,,5154786.68,,,,,,,,7440429.99,16674905.25,274176050.89,,13405479.91,0.0,,28867588.29,90037227.72,,148420336.02,,,,,,,,,,,,,,,,,422596386.91,,,,,,3013580974.33,3013580974.33,3436177361.24,11250000.0,10000.0,,,,,,,,,,,303620.0,190375710.4,140593105.25,38507685.26,499071.0,825553724.31,6836580.64,5154786.68,13405479.91,894849385.77,,0
|
|
||||||
688334.SH,20231028,20231028,20230930,1,1,3,316579466.0,2489803394.01,153952388.75,14915802.63,,769485417.61,300000000.0,64994604.56,83291654.56,,20053880.17,,744438.89,59766883.51,,,,,,,,,4692606.52,1304610906.72,,,33686616.66,,,,,814810688.89,2224612.01,,,,,100137042.47,,23913452.13,,1461221.4,,27914070.0,2087625628.87,,,,,,,,,,,,,,,,,3392236535.59,,,,,,,,54449201.21,,,,19679511.26,9811005.98,,,,,,,,,,,7008054.97,11166166.44,264952583.79,,,,,29371312.23,91743567.22,,152302900.41,,,,,,,,,,,,,,,,,417255484.2,,,,,,2974981051.39,2974981051.39,3392236535.59,8690000.0,-270000.0,,,,,,,,,,,759145.0,146553877.87,148286259.12,54449201.21,1566714.79,814810688.89,2224612.01,16284766.06,17206173.24,1075223811.49,,0
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,316579466.0,2489803394.01,110961238.82,14915802.63,,1242151396.86,,17029068.4,59436138.81,676481.59,19839369.08,0.0,146555.56,66696945.59,,,,,,,,,6582064.29,1413317165.18,,,33697604.29,,,,,834065278.87,1997431.32,,,,,100906414.0,,24076449.39,,1487864.42,,28792858.2,1895553625.65,,,,,,,,,,,,,,,,,3308870790.83,,,,,,,,43850443.4,,,,18118561.93,4687893.02,,,4367401.15,,,,,,,,7008054.97,13066063.29,220024698.0,,17206173.24,0.0,,29901483.41,95879106.72,,156856191.37,,,,,,,,,,,,,,,,,376880889.37,,,,,,2931989901.46,2931989901.46,3308870790.83,8690000.0,-270000.0,,,,,,,,,,,759145.0,128926280.24,76465207.21,43850443.4,823037.15,834065278.87,1997431.32,4367401.15,17206173.24,861467713.89,,1
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,316579466.0,2489803394.01,110961238.82,14915802.63,,1242151396.86,,17029068.4,59436138.81,676481.59,19839369.08,0.0,146555.56,66696945.59,,,,,,,,,6582064.29,1413317165.18,,,33697604.29,,,,,834065278.87,1997431.32,,,,,100906414.0,,24076449.39,,1487864.42,,28792858.2,1895553625.65,,,,,,,,,,,,,,,,,3308870790.83,,,,,,,,43850443.4,,,,18118561.93,4687893.02,,,4367401.15,,,,,,,,7008054.97,13066063.29,220024698.0,,17206173.24,0.0,,29901483.41,95879106.72,,156856191.37,,,,,,,,,,,,,,,,,376880889.37,,,,,,2931989901.46,2931989901.46,3308870790.83,8690000.0,-270000.0,,,,,,,,,,,759145.0,128926280.24,76465207.21,43850443.4,823037.15,834065278.87,1997431.32,4367401.15,17206173.24,861467713.89,,0
|
|
||||||
688334.SH,20230530,20230530,20230331,1,1,1,237434599.0,1509165257.22,123903357.39,14915802.63,,291242156.24,,23306750.77,59767962.56,,23895755.93,,5845000.0,62807753.87,,,,,,,,,6711310.14,475950793.43,,,33980752.7,,,,,846784086.62,2118533.58,,,,,102313273.0,,24402443.88,,1809801.37,,21245250.0,1800007150.2,,,,,,,,,,,,,,,,,2275957943.63,,,,,,,,35525583.63,,,,9928847.46,4865892.71,,,,,,,,,,,7132006.04,14531392.72,227219430.01,,,,,30676284.46,100540546.22,,163239497.38,,,,,,,,,,,,,,,,,390458927.39,,,,,,1885499016.24,1885499016.24,2275957943.63,8940000.0,80000.0,,,,,,,,,,,759145.0,144773585.22,83074713.33,35525583.63,7459958.92,846784086.62,2118533.58,10462122.23,17206873.24,757483100.33,,0
|
|
||||||
688334.SH,20230530,20230530,20221231,1,1,4,237434599.0,1509165257.22,89076310.02,14915802.63,,286273457.22,,33886894.4,57699052.9,2027990.54,21131746.43,,4635540.38,79218866.22,,,,,,,,,17267587.53,502898760.62,,,33652732.59,,,,,871960668.03,2627199.72,,,,,104171247.95,,24402443.88,,1809801.37,,16879602.8,1751957758.15,,,,,,,,,,,,,,,,,2254856518.77,,,,,,,,44532079.08,,,,4671298.84,5089620.49,,,1894687.67,,,,,,,,6933631.23,10833488.83,236343186.6,,17206873.24,,,30956212.71,104036219.43,,167841363.3,,,,,,,,,,,,,,,,,404184549.9,,,,,,1850671968.87,1850671968.87,2254856518.77,8940000.0,80000.0,,,,,,,,,,,757625.0,162388380.46,91585947.3,44532079.08,6663530.92,871960668.03,2627199.72,1894687.67,17206873.24,687047010.79,,0
|
|
||||||
688334.SH,20230530,20230530,20221231,1,1,4,237434599.0,1509165257.22,89076310.02,14915802.63,,286273457.22,,33886894.4,57699052.9,2027990.54,21131746.43,,4635540.38,79218866.22,,,,,,,,,17267587.53,502898760.62,,,33652732.59,,,,,871960668.03,2627199.72,,,,,104171247.95,,24402443.88,,1809801.37,,16879602.8,1751957758.15,,,,,,,,,,,,,,,,,2254856518.77,,,,,,,,44532079.08,,,,4671298.84,5089620.49,,,1894687.67,,,,,,,,6933631.23,10833488.83,236343186.6,,17206873.24,,,30956212.71,104036219.43,,167841363.3,,,,,,,,,,,,,,,,,404184549.9,,,,,,1850671968.87,1850671968.87,2254856518.77,8940000.0,80000.0,,,,,,,,,,,757625.0,162388380.46,91585947.3,44532079.08,6663530.92,871960668.03,2627199.72,1894687.67,17206873.24,687047010.79,,1
|
|
||||||
688334.SH,20230530,20230530,20211231,1,1,4,237434599.0,1509165257.22,-29267576.97,2902403.32,,455408636.43,,28256363.42,75127624.77,387525.36,10288730.4,,1083078.23,74484184.59,,,,,,,,,10574777.91,655610921.11,,,36046248.01,,,,,914310811.07,13828814.91,,,,,103596484.73,,25543887.3,,2486994.01,,5897946.99,1516110913.44,,,,,,,,,,,,,,,,,2171721834.55,,,,,,,,39521033.41,,,,4617201.76,7946066.24,,9992339.29,18716470.84,,,,,,,,6789923.36,10477511.58,260114605.91,,21008266.55,,,26554827.85,124343762.49,,192222546.07,,,,,,,,,,,,,,,,,452337151.98,,,,,,1719384682.57,1719384682.57,2171721834.55,10480000.0,-850000.0,,,,,,,,,,,,162054059.43,103383988.19,39521033.41,1470603.59,914310811.07,13828814.91,28708810.13,21008266.55,401735555.56,,0
|
|
||||||
688334.SH,20230530,20230530,20201231,1,1,4,140680000.0,393047675.32,77982117.77,76295784.6,,186783624.45,,55042004.9,52866632.73,775181.12,6292850.33,,1303420.53,92185530.69,,,,,,,,,16087892.58,415527450.45,,,41802975.45,,,,,729171459.0,16647747.35,,,,,62913194.97,,,,7113646.23,,4732023.19,862381046.19,,,,,,,,,,,,,,,,,1277908496.64,,,,,,,4525000.0,37096563.43,,,,4524023.44,12343310.43,,,32364556.94,,,,,,,,3800000.0,117905135.24,384970832.9,,24809659.97,22400000.0,,2342477.82,149619948.26,,210522086.05,,,,,,,,,,,,,,,,,595492918.95,,,,,,682415577.69,682415577.69,1277908496.64,11350000.0,-5590000.0,,,,,,,,,,,4190313.12,172412243.42,107908637.63,41621563.43,2078601.65,729171459.0,16647747.35,32364556.94,47209659.97,,,0
|
|
||||||
688334.SH,20220630,20220630,20191231,1,1,4,140680000.0,102148296.28,212862234.27,76295784.6,,224394412.92,,55256405.98,44752593.85,1194959.6,3523202.96,,292051.46,64268354.9,,,,,,,,,8163444.65,401845426.32,,,,,,,,564859808.37,16233214.96,,,,,11229663.66,,,,4165884.58,,7633741.4,604122312.97,,,,,,,,,,,,,,,,,1005967739.29,,,,,,,4999380.47,70584935.69,127346312.15,,,8590308.4,6385661.06,,,32297017.15,,,,,,,,3800000.0,1429300.49,255432915.41,,28611880.0,22400000.0,,3106038.3,161220590.43,,224238508.73,,,,,,,,,,,,,,,,,479671424.14,,,,,,526296315.15,526296315.15,1005967739.29,8900000.0,-5690000.0,,,,,,,,,,,,,100008999.83,75584316.16,1487011.06,564859808.37,16233214.96,32297017.15,51011880.0,,,0
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,comp_type,report_type,end_type,net_profit,finan_exp,c_fr_sale_sg,recp_tax_rends,n_depos_incr_fi,n_incr_loans_cb,n_inc_borr_oth_fi,prem_fr_orig_contr,n_incr_insured_dep,n_reinsur_prem,n_incr_disp_tfa,ifc_cash_incr,n_incr_disp_faas,n_incr_loans_oth_bank,n_cap_incr_repur,c_fr_oth_operate_a,c_inf_fr_operate_a,c_paid_goods_s,c_paid_to_for_empl,c_paid_for_taxes,n_incr_clt_loan_adv,n_incr_dep_cbob,c_pay_claims_orig_inco,pay_handling_chrg,pay_comm_insur_plcy,oth_cash_pay_oper_act,st_cash_out_act,n_cashflow_act,oth_recp_ral_inv_act,c_disp_withdrwl_invest,c_recp_return_invest,n_recp_disp_fiolta,n_recp_disp_sobu,stot_inflows_inv_act,c_pay_acq_const_fiolta,c_paid_invest,n_disp_subs_oth_biz,oth_pay_ral_inv_act,n_incr_pledge_loan,stot_out_inv_act,n_cashflow_inv_act,c_recp_borrow,proc_issue_bonds,oth_cash_recp_ral_fnc_act,stot_cash_in_fnc_act,free_cashflow,c_prepay_amt_borr,c_pay_dist_dpcp_int_exp,incl_dvd_profit_paid_sc_ms,oth_cashpay_ral_fnc_act,stot_cashout_fnc_act,n_cash_flows_fnc_act,eff_fx_flu_cash,n_incr_cash_cash_equ,c_cash_equ_beg_period,c_cash_equ_end_period,c_recp_cap_contrib,incl_cash_rec_saims,uncon_invest_loss,prov_depr_assets,depr_fa_coga_dpba,amort_intang_assets,lt_amort_deferred_exp,decr_deferred_exp,incr_acc_exp,loss_disp_fiolta,loss_scr_fa,loss_fv_chg,invest_loss,decr_def_inc_tax_assets,incr_def_inc_tax_liab,decr_inventories,decr_oper_payable,incr_oper_payable,others,im_net_cashflow_oper_act,conv_debt_into_cap,conv_copbonds_due_within_1y,fa_fnc_leases,im_n_incr_cash_equ,net_dism_capital_add,net_cash_rece_sec,credit_impa_loss,use_right_asset_dep,oth_loss_asset,end_bal_cash,beg_bal_cash,end_bal_cash_equ,beg_bal_cash_equ,update_flag
|
|
||||||
688334.SH,20251022,20251022,20250930,1,1,3,,,687674498.9,1279725.93,,,,,,,,,,,,6875707.78,695829932.61,101152525.55,140798139.16,64055576.05,,,,,,37221100.09,343227340.85,352602591.76,,2750600000.0,21075133.57,443285.64,,2772118419.21,97648775.1,3140000000.0,,,,3237648775.1,-465530355.89,33591200.0,,,66591200.0,-253667286.8919,,149824760.3,,3248827.8,153073588.1,-86482388.1,,-199410152.23,1033337730.72,833927578.49,33000000.0,33000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20250821,20250821,20250630,1,1,2,147537437.62,256316.93,505401214.82,1012931.72,,,,,,,,,,,,5231268.78,511645415.32,63947997.4,91350338.08,44753545.58,,,,,,21737868.61,221789749.67,289855665.65,,1386600000.0,10728467.89,443285.64,,1397771753.53,79094130.95,1615000000.0,,,,1694094130.95,-296322377.42,33591200.0,,,66591200.0,5404496.4374,,76442931.25,,2222855.29,78665786.54,-12074586.54,,-18541298.31,1033337730.72,1014796432.41,33000000.0,33000000.0,,-534840.44,64625502.38,4250299.78,,,,289772.76,,-3467377.36,-14924721.67,84613.53,-123219.19,-6488504.27,13320672.7,83437339.36,,289855665.65,,,,-18541298.31,,,-60912.43,1653285.95,,1014796432.41,1033337730.72,,,1
|
|
||||||
688334.SH,20250821,20250821,20250630,1,1,2,147537437.62,256316.93,505401214.82,1012931.72,,,,,,,,,,,,5231268.78,511645415.32,63947997.4,91350338.08,44753545.58,,,,,,21737868.61,221789749.67,289855665.65,,1386600000.0,10728467.89,443285.64,,1397771753.53,79094130.95,1615000000.0,,,,1694094130.95,-296322377.42,33591200.0,,,66591200.0,,,76442931.25,,2222855.29,78665786.54,-12074586.54,,-18541298.31,1033337730.72,1014796432.41,33000000.0,33000000.0,,-534840.44,64625502.38,4250299.78,,,,289772.76,,-3467377.36,-14924721.67,84613.53,-123219.19,-6488504.27,13320672.7,83437339.36,,289855665.65,,,,-18541298.31,,,-60912.43,1653285.95,,1014796432.41,1033337730.72,,,0
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,,,246870153.95,119229.43,,,,,,,,,,,,696830.25,247686213.63,35585744.25,49492166.48,20900047.31,,,,,,9895012.47,115872970.51,131813243.12,260000000.0,,1741712.09,,,261741712.09,6292300.2,,,620000000.0,,626292300.2,-364550588.11,33591200.0,,,33591200.0,-48350236.3298,,31866102.44,,1175377.8,33041480.24,549719.76,,-232187625.23,1033337730.72,801150105.49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,,,246870153.95,119229.43,,,,,,,,,,,,696830.25,247686213.63,35585744.25,49492166.48,20900047.31,,,,,,9895012.47,115872970.51,131813243.12,260000000.0,,1741712.09,,,261741712.09,6292300.2,,,620000000.0,,626292300.2,-364550588.11,33591200.0,,,33591200.0,,,31866102.44,,1175377.8,33041480.24,549719.76,,-232187625.23,1033337730.72,801150105.49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20250411,20250411,20241231,1,1,4,254878787.34,827189.6,983761056.71,22016044.22,,,,,,,,,,,,31927950.32,1037705051.25,196402467.55,223854738.4,63382092.8,,,,,,71582684.21,555221982.96,482483068.29,1344000000.0,,51843073.39,40500.0,,1395883573.39,143247412.01,,,874000000.0,,1017247412.01,378636161.38,,,,,,3800000.0,131590193.58,,458002197.8,593392391.38,-593392391.38,,267726838.29,765610892.43,1033337730.72,,,,1681594.25,123519697.28,8636188.49,,,,-170411.9,217495.46,-7980328.88,-38163645.51,758633.58,-1873481.27,888208.08,50073249.7,88586874.42,,482483068.29,,,,267726838.29,,,-3060752.79,3663770.44,,1033337730.72,741019544.85,,24591347.58,0
|
|
||||||
688334.SH,20250411,20250411,20241231,1,1,4,254878787.34,827189.6,983761056.71,22016044.22,,,,,,,,,,,,31927950.32,1037705051.25,196402467.55,223854738.4,63382092.8,,,,,,71582684.21,555221982.96,482483068.29,1344000000.0,,51843073.39,40500.0,,1395883573.39,143247412.01,,,874000000.0,,1017247412.01,378636161.38,,,,,534354994.5398,3800000.0,131590193.58,,458002197.8,593392391.38,-593392391.38,,267726838.29,765610892.43,1033337730.72,,,,1681594.25,123519697.28,8636188.49,,,,-170411.9,217495.46,-7980328.88,-38163645.51,758633.58,-1873481.27,888208.08,50073249.7,88586874.42,,482483068.29,,,,267726838.29,,,-3060752.79,3663770.44,,1033337730.72,741019544.85,,24591347.58,1
|
|
||||||
688334.SH,20241030,20241030,20240930,1,1,3,,,586698716.73,22088568.41,,,,,,,,,,,,23548081.27,632335366.41,85724910.55,133522960.41,48643989.86,,,,,,52036420.49,319928281.31,312407085.1,,759000000.0,45362446.5,40500.0,,804402946.5,61911374.44,854000000.0,,,,915911374.44,-111508427.94,,,,,-107674899.5256,,81518589.43,,455790095.0,537308684.43,-537308684.43,,-336410027.27,765610892.43,429200865.16,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20241030,20241030,20240930,1,1,3,,,586698716.73,22088568.41,,,,,,,,,,,,23548081.27,632335366.41,85724910.55,133522960.41,48643989.86,,,,,,52036420.49,319928281.31,312407085.1,,759000000.0,45362446.5,40500.0,,804402946.5,61911374.44,854000000.0,,,,915911374.44,-111508427.94,,,,,,,81518589.43,,455790095.0,537308684.43,-537308684.43,,-336410027.27,765610892.43,429200865.16,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20240830,20240830,20240630,1,1,2,99425201.28,281027.64,369774517.56,7088641.78,,,,,,,,,,,,16671194.09,393534353.43,40447652.23,78680049.53,27370220.22,,,,,,31174806.51,177672728.49,215861624.94,,350000000.0,3258111.11,40500.0,,353298611.11,41429027.98,280000000.0,,,,321429027.98,31869583.13,,,,,83791543.767,,81465842.76,,3248827.8,84714670.56,-84714670.56,,163016537.51,741019544.85,904036082.36,,,,288677.59,48844408.69,3817194.14,,,,-26759.27,112023.94,-3258111.11,-18566603.43,214391.77,-1503647.35,12677992.04,19660739.49,52506048.31,,215861624.94,,,,163016537.51,,,-371171.23,1760212.44,,904036082.36,741019544.85,,,1
|
|
||||||
688334.SH,20240830,20240830,20240630,1,1,2,99425201.28,281027.64,369774517.56,7088641.78,,,,,,,,,,,,16671194.09,393534353.43,40447652.23,78680049.53,27370220.22,,,,,,31174806.51,177672728.49,215861624.94,,350000000.0,3258111.11,40500.0,,353298611.11,41429027.98,280000000.0,,,,321429027.98,31869583.13,,,,,,,81465842.76,,3248827.8,84714670.56,-84714670.56,,163016537.51,741019544.85,904036082.36,,,,288677.59,48844408.69,3817194.14,,,,-26759.27,112023.94,-3258111.11,-18566603.43,214391.77,-1503647.35,12677992.04,19660739.49,52506048.31,,215861624.94,,,,163016537.51,,,-371171.23,1760212.44,,904036082.36,741019544.85,,,0
|
|
||||||
688334.SH,20240430,20240430,20240331,1,1,1,,,166188000.22,72524.19,,,,,,,,,,,,7537653.06,173798177.47,15584410.48,41908984.16,10669573.8,,,,,,10284422.91,78447391.35,95350786.12,,,1083444.45,40500.0,,1123944.45,16575270.63,280000000.0,,,,296575270.63,-295451326.18,,,,,-249354352.7298,,52173.33,,,52173.33,-52173.33,,-200152713.39,861019544.85,660866831.46,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20240430,20240430,20240331,1,1,1,,,166188000.22,72524.19,,,,,,,,,,,,7537653.06,173798177.47,15584410.48,41908984.16,10669573.8,,,,,,10284422.91,78447391.35,95350786.12,,,1083444.45,40500.0,,1123944.45,16575270.63,280000000.0,,,,296575270.63,-295451326.18,,,,,-284587270.95,,52173.33,,,52173.33,-52173.33,,-200152713.39,861019544.85,660866831.46,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20240411,20240411,20231231,1,1,4,162367945.17,713200.04,600195164.84,8009884.88,,,,,,,,,,,,56176476.99,664381526.71,107987796.36,179632614.58,40910384.42,,,,,,73227300.25,401758095.61,262623431.1,398267.15,,2364291.66,,,2762558.81,74704246.9,,,729941703.37,,804645950.27,-801883391.46,,,,1073577062.71,-222824316.9954,3800000.0,59427316.83,,16343697.89,79571014.72,994006047.99,,454746087.63,286273457.22,741019544.85,1073577062.71,,,3510950.88,101762265.23,7332258.98,,,,10569.28,55831.23,-398267.15,-31419549.3,-859535.58,-2088624.42,22348080.53,-25324156.69,19413912.27,,262623431.1,,,,454746087.63,,,1678125.7,3520424.93,,741019544.85,286273457.22,,,1
|
|
||||||
688334.SH,20231028,20231028,20230930,1,1,3,,,376633744.75,6953839.76,,,,,,,,,,,,43162663.38,426750247.89,52179074.94,109070591.22,25246285.97,,,,,,49867196.97,236363149.1,190387098.79,398267.15,,,,,398267.15,40427541.72,668000000.0,,,,708427541.72,-708029274.57,,,,1073577062.71,-235747854.7517,,59363743.5,,13359183.04,72722926.54,1000854136.17,,483211960.39,286273457.22,769485417.61,1073577062.71,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20231028,20231028,20230930,1,1,3,,,376633744.75,6953839.76,,,,,,,,,,,,43162663.38,426750247.89,52179074.94,109070591.22,25246285.97,,,,,,49867196.97,236363149.1,190387098.79,398267.15,,,,,398267.15,40427541.72,668000000.0,,,,708427541.72,-708029274.57,,,,1073577062.71,-337326385.21,,59363743.5,,13359183.04,72722926.54,1000854136.17,,483211960.39,286273457.22,769485417.61,1073577062.71,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,81056872.3,126700.0,270391560.73,96031.06,,,,,,,,,,,,20565909.92,291053501.71,38769580.43,71242874.48,17225083.24,,,,,,22468975.16,149706513.31,141346988.4,398267.15,,,,,398267.15,29354007.32,172000000.0,,,,201354007.32,-200955740.17,,,,1073577062.71,56111183.79,,59299343.5,,8791027.8,68090371.3,1005486691.41,,945877939.64,286273457.22,1232151396.86,1073577062.71,,,213075.71,51086533.66,3621816.07,,,,,,-398267.15,-12481130.36,321936.95,-1054729.3,12634839.41,30513689.19,-24965334.52,,141346988.4,,,,945877939.64,,,-944808.46,1615794.9,,1232151396.86,286273457.22,,,0
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,81056872.3,126700.0,270391560.73,96031.06,,,,,,,,,,,,20565909.92,291053501.71,38769580.43,71242874.48,17225083.24,,,,,,22468975.16,149706513.31,141346988.4,398267.15,,,,,398267.15,29354007.32,172000000.0,,,,201354007.32,-200955740.17,,,,1073577062.71,123960422.9711,,59299343.5,,8791027.8,68090371.3,1005486691.41,,945877939.64,286273457.22,1232151396.86,1073577062.71,,,213075.71,51086533.66,3621816.07,,,,,,-398267.15,-12481130.36,321936.95,-1054729.3,12634839.41,30513689.19,-24965334.52,,141346988.4,,,,945877939.64,,,-944808.46,1615794.9,,1232151396.86,286273457.22,,,1
|
|
||||||
688334.SH,20230530,20230530,20230331,1,1,1,,,134233045.5,,,,,,,,,,,,,11518507.26,145751552.76,16056249.35,36612197.19,3038908.02,,,,,,8115369.07,63822723.63,81928829.13,,,,,,,9685027.31,65000000.0,,,,74685027.31,-74685027.31,,,,,5975876.27,,63000.0,,2212102.8,2275102.8,-2275102.8,,4968699.02,286273457.22,291242156.24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688334.SH,20230530,20230530,20230331,1,1,1,,,134233045.5,,,,,,,,,,,,,11518507.26,145751552.76,16056249.35,36612197.19,3038908.02,,,,,,8115369.07,63822723.63,81928829.13,,,,,,,9685027.31,65000000.0,,,,74685027.31,-74685027.31,,,,,5975876.27,,63000.0,,2212102.8,2275102.8,-2275102.8,,4968699.02,286273457.22,291242156.24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688334.SH,20230530,20230530,20221231,1,1,4,130357286.3,300213.36,558499297.09,7351092.06,,,,,,,,,,,,32018689.81,597869078.96,114848268.63,171209107.98,46950289.54,,,,,,68229114.32,401236780.47,196632298.49,,,,214000.0,,214000.0,79069863.34,267600000.0,,,,346669863.34,-346455863.34,,,,,118663186.5472,3800000.0,10293945.96,,3564051.33,17657997.29,-17657997.29,,-167481562.14,453755019.36,286273457.22,,,,434760.93,110272543.93,6566550.99,,,,-85430.78,2413.37,,-15317939.81,677192.64,4401384.86,-3941889.35,-5442697.1,-35817959.84,,196632298.49,,,,-167481562.14,,,968749.15,3257119.84,,286273457.22,453755019.36,,,0
|
|
||||||
688334.SH,20230530,20230530,20221231,1,1,4,130357286.3,300213.36,558499297.09,7351092.06,,,,,,,,,,,,32018689.81,597869078.96,114848268.63,171209107.98,46950289.54,,,,,,68229114.32,401236780.47,196632298.49,,,,214000.0,,214000.0,79069863.34,267600000.0,,,,346669863.34,-346455863.34,,,,,118663186.5472,3800000.0,10293945.96,,3564051.33,17657997.29,-17657997.29,,-167481562.14,453755019.36,286273457.22,,,,434760.93,110272543.93,6566550.99,,,,-85430.78,2413.37,,-15317939.81,677192.64,4401384.86,-3941889.35,-5442697.1,-35817959.84,,196632298.49,,,,-167481562.14,,,968749.15,3257119.84,,286273457.22,453755019.36,,,1
|
|
||||||
688334.SH,20230530,20230530,20211231,1,1,4,81558517.63,346446.59,449746998.8,2561557.36,,,,,,,,,,,,6356333.92,458664890.08,100939541.43,136000715.07,33818050.22,,,,,,34112641.41,304870948.13,153793941.95,7968416.49,,,6941838.0,,14910254.49,58855318.35,400000000.0,,,,458855318.35,-443945063.86,,,,698106611.19,37546946.9887,3800000.0,133075323.61,,3818459.99,140693783.6,557412827.59,,267261705.68,186493313.68,453755019.36,698106611.19,,,-320791.32,103688280.14,3633048.44,,,,193967.58,68.72,,4021171.88,4626652.22,24212350.03,23196005.13,18635340.29,-104412361.99,,153793941.95,,,,267261705.68,,,-8841873.25,3257119.86,,453755019.36,186493313.68,,,0
|
|
||||||
688334.SH,20230530,20230530,20201231,1,1,4,65119883.5,392679.97,403398715.13,1223562.96,,,,,,,,,,,,12215794.18,416838072.27,103817136.9,117819356.58,25028111.67,,,,,,34565307.15,281229912.3,135608159.97,,,,354800.0,,354800.0,69365467.71,,,,,69365467.71,-69010667.71,,,,,203410377.8471,3800000.0,100409311.47,,,104209311.47,-104209311.47,,-37611819.21,224105132.89,186493313.68,,,,186316.54,91227563.22,2619559.62,,,,-72635.75,-66984.8,,4214541.74,-2947761.65,-763560.48,-26979773.68,-32238597.8,35560614.98,,135608159.97,,,,-37611819.21,,,-643685.44,,,186493313.68,224105132.89,,,0
|
|
||||||
688334.SH,20220630,20220630,20191231,1,1,4,95014029.03,438913.33,425558197.83,,,,,,,,,,,,,8502860.11,434061057.94,131712355.36,107867499.17,29481308.68,,,,,,33256680.78,302317843.99,131743213.95,,,,72600.0,,72600.0,48320152.59,,,,,48320152.59,-48247552.59,,,,,-19495335.564,3800000.0,66290180.0,,,70090180.0,-70090180.0,,13405481.36,210699651.53,224105132.89,,,,-153634.21,80262205.72,1338547.65,,,,-32012.38,72968.76,,,-4165884.58,3106038.3,14245857.23,-32989024.36,-22147173.97,,131743213.95,,,,13405481.36,,,-3247616.57,,,224105132.89,210699651.53,,,0
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
end_date,ex_date,div_proc,cash_div
|
|
||||||
20250630,,预案,0.0
|
|
||||||
20250630,20250912,实施,0.231
|
|
||||||
20241231,,预案,0.0
|
|
||||||
20241231,,股东大会通过,0.0
|
|
||||||
20241231,20250606,实施,0.14
|
|
||||||
20240930,,预案,0.0
|
|
||||||
20240930,,股东大会通过,0.0
|
|
||||||
20240930,20250115,实施,0.1
|
|
||||||
20240630,,预案,0.0
|
|
||||||
20240630,,股东提议,0.0
|
|
||||||
20240630,,股东大会通过,0.0
|
|
||||||
20240630,20241122,实施,0.158
|
|
||||||
20231231,,预案,0.0
|
|
||||||
20231231,,股东大会通过,0.0
|
|
||||||
20231231,20240531,实施,0.257
|
|
||||||
20230630,,预案,0.0
|
|
||||||
|
@ -1,558 +0,0 @@
|
|||||||
ts_code,trade_date,close,turnover_rate,turnover_rate_f,volume_ratio,pe,pe_ttm,pb,ps,ps_ttm,dv_ratio,dv_ttm,total_share,float_share,free_share,total_mv,circ_mv
|
|
||||||
688334.SH,20250930,19.28,2.0852,3.2723,1.2,26.6914,23.3003,2.1851,7.6452,6.7507,,,31657.9466,15690.4698,9998.6609,610365.2104,302512.2577
|
|
||||||
688334.SH,20250929,19.42,1.7175,2.6951,1.04,26.8853,23.4695,2.201,7.7008,6.7997,,,31657.9466,15690.4698,9998.6609,614797.323,304708.9235
|
|
||||||
688334.SH,20250926,19.15,1.7098,2.6832,1.1,26.5115,23.1432,2.1704,7.5937,6.7052,,,31657.9466,15690.4698,9998.6609,606249.6774,300472.4967
|
|
||||||
688334.SH,20250925,19.17,1.7357,2.7238,1.11,26.5392,23.1674,2.1726,7.6016,6.7122,,,31657.9466,15690.4698,9998.6609,606882.8363,300786.3061
|
|
||||||
688334.SH,20250924,19.0,1.5705,2.4645,1.01,26.3038,22.9619,2.1534,7.5342,6.6527,,,31657.9466,15690.4698,9998.6609,601500.9854,298118.9262
|
|
||||||
688334.SH,20250923,18.6,1.9373,3.0401,1.33,25.75,22.4785,2.108,7.3756,6.5126,,,31657.9466,15690.4698,9998.6609,588837.8068,291842.7383
|
|
||||||
688334.SH,20250922,18.77,1.3029,2.0447,0.77,25.9854,22.684,2.1273,7.443,6.5721,,,31657.9466,15690.4698,9998.6609,594219.6577,294510.1181
|
|
||||||
688334.SH,20250919,18.75,1.2294,1.9292,0.66,25.9577,22.6598,2.125,7.4351,6.5651,,,31657.9466,15690.4698,9998.6609,593586.4988,294196.3088
|
|
||||||
688334.SH,20250918,18.92,1.7614,2.7641,0.94,26.193,22.8653,2.1443,7.5025,6.6247,,,31657.9466,15690.4698,9998.6609,598968.3497,296863.6886
|
|
||||||
688334.SH,20250917,19.2,1.5285,2.3986,0.81,26.5807,23.2037,2.176,7.6135,6.7227,,,31657.9466,15690.4698,9998.6609,607832.5747,301257.0202
|
|
||||||
688334.SH,20250916,19.15,1.4494,2.2745,0.74,26.5115,23.1432,2.1704,7.5937,6.7052,,,31657.9466,15690.4698,9998.6609,606249.6774,300472.4967
|
|
||||||
688334.SH,20250915,19.25,2.4449,3.8366,1.16,26.6499,23.2641,2.1817,7.6333,6.7402,,,31657.9466,15690.4698,9998.6609,609415.4721,302041.5437
|
|
||||||
688334.SH,20250912,19.04,2.157,3.3848,1.06,26.3592,23.0103,2.1579,7.5501,6.6667,,,31657.9466,15690.4698,9998.6609,602767.3033,298746.545
|
|
||||||
688334.SH,20250911,19.25,1.8011,2.8265,0.87,26.6499,23.2641,2.126,7.6333,6.7402,,,31657.9466,15690.4698,9998.6609,609415.4721,302041.5437
|
|
||||||
688334.SH,20250910,19.19,1.533,2.4057,0.76,26.5668,23.1916,2.1194,7.6095,6.7192,,,31657.9466,15690.4698,9998.6609,607515.9953,301100.1155
|
|
||||||
688334.SH,20250909,19.32,1.8801,2.9504,0.91,26.7468,23.3487,2.1338,7.6611,6.7647,,,31657.9466,15690.4698,9998.6609,611631.5283,303139.8765
|
|
||||||
688334.SH,20250908,19.52,3.2078,5.0338,1.82,27.0237,23.5904,2.1559,7.7404,6.8347,,,31657.9466,15690.4698,9998.6609,617963.1176,306277.9705
|
|
||||||
688334.SH,20250905,18.82,1.7751,2.7855,0.94,26.0546,22.7444,2.0786,7.4628,6.5896,,,31657.9466,15690.4698,9998.6609,595802.555,295294.6416
|
|
||||||
688334.SH,20250904,18.47,1.9256,3.0217,0.89,25.5701,22.3214,2.0399,7.324,6.4671,,,31657.9466,15690.4698,9998.6609,584722.2737,289802.9772
|
|
||||||
688334.SH,20250903,18.57,1.3069,2.0509,0.51,25.7085,22.4423,2.0509,7.3637,6.5021,,,31657.9466,15690.4698,9998.6609,587888.0684,291372.0242
|
|
||||||
688334.SH,20250902,18.55,2.1127,3.3154,0.8,25.6808,22.4181,2.0487,7.3558,6.4951,,,31657.9466,15690.4698,9998.6609,587254.9094,291058.2148
|
|
||||||
688334.SH,20250901,18.89,1.7101,2.6837,0.57,26.1515,22.829,2.0863,7.4906,6.6141,,,31657.9466,15690.4698,9998.6609,598018.6113,296392.9745
|
|
||||||
688334.SH,20250829,18.78,2.3764,3.7292,0.7,25.9992,22.6961,2.0741,7.447,6.5756,,,31657.9466,15690.4698,9998.6609,594536.2371,294667.0228
|
|
||||||
688334.SH,20250828,18.7,3.3601,5.2728,0.83,25.8885,22.5994,2.0653,7.4152,6.5476,,,31657.9466,15690.4698,9998.6609,592003.6014,293411.7853
|
|
||||||
688334.SH,20250827,18.87,3.297,5.1738,0.88,26.1238,22.8048,2.0841,7.4827,6.6071,,,31657.9466,15690.4698,9998.6609,597385.4523,296079.1651
|
|
||||||
688334.SH,20250826,19.14,2.4025,3.7701,0.65,26.4976,23.1311,2.1139,7.5897,6.7017,,,31657.9466,15690.4698,9998.6609,605933.0979,300315.592
|
|
||||||
688334.SH,20250825,19.28,3.6619,5.7465,1.04,26.6914,23.3003,2.1294,7.6452,6.7507,,,31657.9466,15690.4698,9998.6609,610365.2104,302512.2577
|
|
||||||
688334.SH,20250822,19.12,4.1623,6.5318,1.32,26.4699,23.107,2.1117,7.5818,6.6947,,,31657.9466,15690.4698,9998.6609,605299.939,300001.7826
|
|
||||||
688334.SH,20250821,19.49,6.6536,10.4412,2.91,26.9822,23.5541,2.1526,7.7285,6.8242,,,31657.9466,15690.4698,9998.6609,617013.3792,305807.2564
|
|
||||||
688334.SH,20250820,19.16,1.9073,2.9931,0.85,26.5253,24.7525,2.1688,7.5977,7.1188,,,31657.9466,15690.4698,9998.6609,606566.2569,300629.4014
|
|
||||||
688334.SH,20250819,19.0,2.0686,3.2462,0.94,26.3038,24.5458,2.1507,7.5342,7.0594,,,31657.9466,15690.4698,9998.6609,601500.9854,298118.9262
|
|
||||||
688334.SH,20250818,19.11,2.8526,4.4765,1.37,26.4561,24.6879,2.1631,7.5778,7.1003,,,31657.9466,15690.4698,9998.6609,604983.3595,299844.8779
|
|
||||||
688334.SH,20250815,18.93,2.3315,3.6588,1.21,26.2069,24.4554,2.1428,7.5064,7.0334,,,31657.9466,15690.4698,9998.6609,599284.9291,297020.5933
|
|
||||||
688334.SH,20250814,18.63,2.2649,3.5542,1.25,25.7916,24.0678,2.1088,7.3875,6.9219,,,31657.9466,15690.4698,9998.6609,589787.5452,292313.4524
|
|
||||||
688334.SH,20250813,18.99,1.6885,2.6497,0.92,26.29,24.5329,2.1496,7.5302,7.0557,,,31657.9466,15690.4698,9998.6609,601184.4059,297962.0215
|
|
||||||
688334.SH,20250812,18.94,1.8812,2.952,1.05,26.2207,24.4683,2.1439,7.5104,7.0371,,,31657.9466,15690.4698,9998.6609,599601.5086,297177.498
|
|
||||||
688334.SH,20250811,19.02,2.2692,3.561,1.35,26.3315,24.5717,2.153,7.5421,7.0668,,,31657.9466,15690.4698,9998.6609,602134.1443,298432.7356
|
|
||||||
688334.SH,20250808,18.85,1.556,2.4418,0.9,26.0961,24.352,2.1337,7.4747,7.0037,,,31657.9466,15690.4698,9998.6609,596752.2934,295765.3557
|
|
||||||
688334.SH,20250807,18.75,1.6856,2.6451,0.79,25.9577,24.2229,2.1224,7.4351,6.9665,,,31657.9466,15690.4698,9998.6609,593586.4988,294196.3088
|
|
||||||
688334.SH,20250806,18.78,1.7602,2.7622,0.78,25.9992,24.2616,2.1258,7.447,6.9776,,,31657.9466,15690.4698,9998.6609,594536.2371,294667.0228
|
|
||||||
688334.SH,20250805,18.76,1.6893,2.6509,0.7,25.9715,24.2358,2.1235,7.439,6.9702,,,31657.9466,15690.4698,9998.6609,593903.0782,294353.2134
|
|
||||||
688334.SH,20250804,18.69,1.7232,2.7042,0.7,25.8746,24.1453,2.1156,7.4113,6.9442,,,31657.9466,15690.4698,9998.6609,591687.022,293254.8806
|
|
||||||
688334.SH,20250801,18.59,1.8196,2.8554,0.64,25.7362,24.0161,2.1043,7.3716,6.907,,,31657.9466,15690.4698,9998.6609,588521.2273,291685.8336
|
|
||||||
688334.SH,20250731,18.5,3.6886,5.7883,1.22,25.6116,23.8999,2.0941,7.3359,6.8736,,,31657.9466,15690.4698,9998.6609,585672.0121,290273.6913
|
|
||||||
688334.SH,20250730,18.97,2.319,3.639,0.54,26.2623,24.5071,2.1473,7.5223,7.0482,,,31657.9466,15690.4698,9998.6609,600551.247,297648.2121
|
|
||||||
688334.SH,20250729,19.03,2.4649,3.8681,0.43,26.3453,24.5846,2.1541,7.5461,7.0705,,,31657.9466,15690.4698,9998.6609,602450.7238,298589.6403
|
|
||||||
688334.SH,20250728,19.0,2.0424,3.2051,0.31,26.3038,24.5458,2.1507,7.5342,7.0594,,,31657.9466,15690.4698,9998.6609,601500.9854,298118.9262
|
|
||||||
688334.SH,20250725,18.93,3.6038,5.6553,0.58,26.2069,24.4554,2.1428,7.5064,7.0334,,,31657.9466,15690.4698,9998.6609,599284.9291,297020.5933
|
|
||||||
688334.SH,20250724,19.16,4.643,7.286,0.83,26.5253,24.7525,2.1688,7.5977,7.1188,,,31657.9466,15690.4698,9998.6609,606566.2569,300629.4014
|
|
||||||
688334.SH,20250723,19.3,8.6949,13.6445,2.05,26.7191,24.9334,2.1847,7.6532,7.1708,,,31657.9466,15690.4698,9998.6609,610998.3694,302826.0671
|
|
||||||
688334.SH,20250722,20.5,9.9796,15.6606,3.64,28.3804,26.4837,2.3205,8.129,7.6167,,,31657.9466,15690.4698,9998.6609,648987.9053,321654.6309
|
|
||||||
688334.SH,20250721,19.12,6.1109,9.5896,2.72,26.4699,24.7008,2.1643,7.5818,7.104,,,31657.9466,15690.4698,9998.6609,605299.939,300001.7826
|
|
||||||
688334.SH,20250718,18.06,1.5032,2.3589,0.67,25.0025,23.3314,2.0443,7.1615,6.7101,,,31657.9466,15690.4698,9998.6609,571742.5156,283369.8846
|
|
||||||
688334.SH,20250717,17.9,1.8144,2.8473,0.86,24.781,23.1247,2.0262,7.098,6.6507,,,31657.9466,15690.4698,9998.6609,566677.2441,280859.4094
|
|
||||||
688334.SH,20250716,17.73,1.7636,2.7732,0.84,24.5456,22.9051,2.0069,7.0306,6.5875,,,31657.9466,15690.4698,9978.6609,561295.3932,278192.0296
|
|
||||||
688334.SH,20250715,17.65,2.5105,3.9475,1.34,24.4348,22.8018,1.9979,6.9989,6.5578,,,31657.9466,15690.4698,9978.6609,558762.7575,276936.792
|
|
||||||
688334.SH,20250714,17.91,3.655,5.7472,2.48,24.7948,23.1377,2.0273,7.102,6.6544,,,31657.9466,15690.4698,9978.6609,566993.8236,281016.3141
|
|
||||||
688334.SH,20250711,17.48,1.5327,2.41,1.06,24.1995,22.5822,1.9786,6.9315,6.4946,,,31657.9466,15690.4698,9978.6609,553380.9066,274269.4121
|
|
||||||
688334.SH,20250710,17.4,1.1225,1.765,0.76,24.0887,22.4788,1.9696,6.8997,6.4649,,,31657.9466,15690.4698,9978.6609,550848.2708,273014.1745
|
|
||||||
688334.SH,20250709,17.37,1.6743,2.6327,1.17,24.0472,22.44,1.9662,6.8879,6.4538,,,31657.9466,15690.4698,9978.6609,549898.5324,272543.4604
|
|
||||||
688334.SH,20250708,17.34,1.3903,2.1861,0.88,24.0057,22.4013,1.9628,6.876,6.4426,,,31657.9466,15690.4698,9978.6609,548948.794,272072.7463
|
|
||||||
688334.SH,20250707,17.31,1.6515,2.5968,0.97,23.9641,22.3625,1.9594,6.8641,6.4315,,,31657.9466,15690.4698,9978.6609,547999.0556,271602.0322
|
|
||||||
688334.SH,20250704,17.04,1.3686,2.1521,0.78,23.5904,22.0137,1.9288,6.757,6.3312,,,31657.9466,15690.4698,9978.6609,539451.4101,267365.6054
|
|
||||||
688334.SH,20250703,17.18,1.2681,1.9939,0.71,23.7842,22.1946,1.9447,6.8125,6.3832,,,31657.9466,15690.4698,9978.6609,543883.5226,269562.2712
|
|
||||||
688334.SH,20250702,17.2,1.4471,2.2754,0.82,23.8119,22.2204,1.9469,6.8204,6.3906,,,31657.9466,15690.4698,9978.6609,544516.6815,269876.0806
|
|
||||||
688334.SH,20250701,17.2,2.1565,3.3909,1.31,23.8119,22.2204,1.9469,6.8204,6.3906,,,31657.9466,15690.4698,9978.6609,544516.6815,269876.0806
|
|
||||||
688334.SH,20250630,17.18,2.2596,3.553,1.7,23.7842,22.1946,1.9447,6.8125,6.3832,,,31657.9466,15690.4698,9978.6609,543883.5226,269562.2712
|
|
||||||
688334.SH,20250627,16.96,1.6481,2.5914,1.35,23.4796,21.9104,1.9198,6.7253,6.3014,,,31657.9466,15690.4698,9978.6609,536918.7743,266110.3678
|
|
||||||
688334.SH,20250626,16.84,1.4275,2.2446,1.2,23.3135,21.7553,1.9062,6.6777,6.2568,,,31657.9466,15690.4698,9978.6609,533119.8207,264227.5114
|
|
||||||
688334.SH,20250625,16.93,1.3335,2.0968,1.17,23.4381,21.8716,1.9164,6.7134,6.2903,,,31657.9466,15690.4698,9978.6609,535969.0359,265639.6537
|
|
||||||
688334.SH,20250624,16.85,1.5569,2.4481,1.42,23.3273,21.7683,1.9073,6.6817,6.2606,,,31657.9466,15690.4698,9978.6609,533436.4002,264384.4161
|
|
||||||
688334.SH,20250623,16.57,0.69,1.0978,0.51,22.9397,21.4065,1.8756,6.5706,6.1565,,,31657.9466,15373.8903,9662.0814,524572.1752,254745.3623
|
|
||||||
688334.SH,20250620,16.46,1.124,1.7884,0.72,22.7874,21.2644,1.8632,6.527,6.1157,,,31657.9466,15373.8903,9662.0814,521089.801,253054.2343
|
|
||||||
688334.SH,20250619,16.48,1.3018,2.0713,0.86,22.8151,21.2903,1.8654,6.5349,6.1231,,,31657.9466,15373.8903,9662.0814,521722.96,253361.7121
|
|
||||||
688334.SH,20250618,16.9,1.0995,1.7495,0.71,23.3965,21.8329,1.913,6.7015,6.2791,,,31657.9466,15373.8903,9662.0814,535019.2975,259818.7461
|
|
||||||
688334.SH,20250617,16.84,1.3848,2.2034,0.93,23.3135,21.7553,1.9062,6.6777,6.2568,,,31657.9466,15373.8903,9662.0814,533119.8207,258896.3127
|
|
||||||
688334.SH,20250616,16.96,1.8275,2.9967,1.38,23.4796,21.9104,1.9198,6.7253,6.3014,,,31657.9466,15373.8903,9375.5814,536918.7743,260741.1795
|
|
||||||
688334.SH,20250613,16.98,2.1786,3.5724,2.01,23.5073,21.9362,1.922,6.7332,6.3089,,,31657.9466,15373.8903,9375.5814,537551.9333,261048.6573
|
|
||||||
688334.SH,20250612,16.72,1.0686,1.7523,1.01,23.1473,21.6003,1.8926,6.6301,6.2123,,,31657.9466,15373.8903,9375.5814,529320.8672,257051.4458
|
|
||||||
688334.SH,20250611,16.82,1.29,2.1153,1.28,23.2858,21.7295,1.9039,6.6698,6.2494,,,31657.9466,15373.8903,9375.5814,532486.6618,258588.8348
|
|
||||||
688334.SH,20250610,16.72,1.0684,1.7519,1.07,23.1473,21.6003,1.8926,6.6301,6.2123,,,31657.9466,15373.8903,9375.5814,529320.8672,257051.4458
|
|
||||||
688334.SH,20250609,16.78,1.0272,1.6843,1.01,23.2304,21.6778,1.8994,6.6539,6.2345,,,31657.9466,15373.8903,9375.5814,531220.3439,257973.8792
|
|
||||||
688334.SH,20250606,16.65,0.9519,1.5609,0.85,23.0504,21.5099,1.8847,6.6023,6.1862,,,31657.9466,15373.8903,9375.5814,527104.8109,255975.2735
|
|
||||||
688334.SH,20250605,16.85,0.9667,1.5852,0.86,23.3273,21.7683,1.8776,6.6817,6.2606,,,31657.9466,15373.8903,9375.5814,533436.4002,259050.0516
|
|
||||||
688334.SH,20250604,16.9,1.0217,1.6753,0.94,23.3965,21.8329,1.8831,6.7015,6.2791,,,31657.9466,15373.8903,9375.5814,535019.2975,259818.7461
|
|
||||||
688334.SH,20250603,16.92,1.0297,1.6885,0.95,23.4242,21.8587,1.8854,6.7094,6.2866,,,31657.9466,15373.8903,9375.5814,535652.4565,260126.2239
|
|
||||||
688334.SH,20250530,16.9,1.1234,1.8422,1.03,23.3965,21.8329,1.8831,6.7015,6.2791,,,31657.9466,15373.8903,9375.5814,535019.2975,259818.7461
|
|
||||||
688334.SH,20250529,16.91,1.4648,2.402,1.33,23.4104,21.8458,1.8843,6.7054,6.2829,,,31657.9466,15373.8903,9375.5814,535335.877,259972.485
|
|
||||||
688334.SH,20250528,16.55,0.9989,1.638,0.75,22.912,21.3807,1.8441,6.5627,6.1491,,,31657.9466,15373.8903,9375.5814,523939.0162,254437.8845
|
|
||||||
688334.SH,20250527,16.63,0.8003,1.3123,0.55,23.0227,21.4841,1.8531,6.5944,6.1788,,,31657.9466,15373.8903,9375.5814,526471.652,255667.7957
|
|
||||||
688334.SH,20250526,16.75,1.012,1.6595,0.68,23.1889,21.6391,1.8664,6.642,6.2234,,,31657.9466,15373.8903,9375.5814,530270.6056,257512.6625
|
|
||||||
688334.SH,20250523,16.61,1.1844,1.9422,0.83,22.9951,21.4582,1.8508,6.5865,6.1714,,,31657.9466,15373.8903,9375.5814,525838.493,255360.3179
|
|
||||||
688334.SH,20250522,16.78,1.5108,2.5742,1.08,23.2304,21.6778,1.8698,6.6539,6.2345,,,31657.9466,15373.8903,9022.5148,531220.3439,257973.8792
|
|
||||||
688334.SH,20250521,17.04,2.1085,3.5928,1.73,23.5904,22.0137,1.8987,6.757,6.3312,,,31657.9466,15373.8903,9022.5148,539451.4101,261971.0907
|
|
||||||
688334.SH,20250520,16.9,1.5144,2.5805,1.32,23.3965,21.8329,1.8831,6.7015,6.2791,,,31657.9466,15373.8903,9022.5148,535019.2975,259818.7461
|
|
||||||
688334.SH,20250519,16.62,1.1764,2.0045,0.99,23.0089,21.4711,1.8519,6.5904,6.1751,,,31657.9466,15373.8903,9022.5148,526155.0725,255514.0568
|
|
||||||
688334.SH,20250516,16.53,0.8228,1.402,0.66,22.8843,21.3549,1.8419,6.5548,6.1417,,,31657.9466,15373.8903,9022.5148,523305.8573,254130.4067
|
|
||||||
688334.SH,20250515,16.54,1.3529,2.3053,1.09,22.8982,21.3678,1.843,6.5587,6.1454,,,31657.9466,15373.8903,9022.5148,523622.4368,254284.1456
|
|
||||||
688334.SH,20250514,16.65,1.2224,2.0829,0.92,23.0504,21.5099,1.8553,6.6023,6.1862,,,31657.9466,15373.8903,9022.5148,527104.8109,255975.2735
|
|
||||||
688334.SH,20250513,16.78,1.1492,1.9581,0.79,23.2304,21.6778,1.8698,6.6539,6.2345,,,31657.9466,15373.8903,9022.5148,531220.3439,257973.8792
|
|
||||||
688334.SH,20250512,16.87,1.3681,2.3312,0.94,23.355,21.7941,1.8798,6.6896,6.268,,,31657.9466,15373.8903,9022.5148,534069.5591,259357.5294
|
|
||||||
688334.SH,20250509,16.74,1.1446,1.9504,0.79,23.175,21.6262,1.8653,6.638,6.2197,,,31657.9466,15373.8903,9022.5148,529954.0261,257358.9236
|
|
||||||
688334.SH,20250508,16.87,1.323,2.2543,0.92,23.355,21.7941,1.8798,6.6896,6.268,,,31657.9466,15373.8903,9022.5148,534069.5591,259357.5294
|
|
||||||
688334.SH,20250507,16.78,1.6873,2.875,1.34,23.2304,21.6778,1.8698,6.6539,6.2345,,,31657.9466,15373.8903,9022.5148,531220.3439,257973.8792
|
|
||||||
688334.SH,20250506,16.95,1.792,3.0534,1.55,23.4658,21.8975,1.8887,6.7213,6.2977,,,31657.9466,15373.8903,9022.5148,536602.1949,260587.4406
|
|
||||||
688334.SH,20250430,16.53,1.3327,2.2708,1.25,22.8843,21.3549,1.8419,6.5548,6.1417,,,31657.9466,15373.8903,9022.5148,523305.8573,254130.4067
|
|
||||||
688334.SH,20250429,16.55,1.0759,1.8332,1.08,22.912,21.3807,1.8441,6.5627,6.1491,,,31657.9466,15373.8903,9022.5148,523939.0162,254437.8845
|
|
||||||
688334.SH,20250428,16.42,1.2831,2.1864,1.36,22.732,21.2128,1.8297,6.5111,6.1008,,,31657.9466,15373.8903,9022.5148,519823.4832,252439.2787
|
|
||||||
688334.SH,20250425,16.42,0.8278,1.4105,0.9,22.732,21.2128,1.8297,6.5111,6.1008,,,31657.9466,15373.8903,9022.5148,519823.4832,252439.2787
|
|
||||||
688334.SH,20250424,16.31,1.2486,2.1276,1.44,22.5797,21.0707,1.8174,6.4675,6.0599,,,31657.9466,15373.8903,9022.5148,516341.109,250748.1508
|
|
||||||
688334.SH,20250423,16.28,0.8981,1.5303,0.99,22.5382,21.0319,1.8141,6.4556,6.0488,,,31657.9466,15373.8903,9022.5148,515391.3706,250286.9341
|
|
||||||
688334.SH,20250422,16.12,0.7296,1.2431,0.74,22.3167,20.8252,1.7962,6.3922,5.9893,,,31657.9466,15373.8903,9022.5148,510326.0992,247827.1116
|
|
||||||
688334.SH,20250421,16.07,1.0201,1.7381,0.88,22.2475,20.7606,1.7907,6.3724,5.9708,,,31657.9466,15373.8903,9022.5148,508743.2019,247058.4171
|
|
||||||
688334.SH,20250418,15.9,0.7247,1.2349,0.46,22.0121,20.541,1.7717,6.3049,5.9076,,,31657.9466,15373.8903,9022.5148,503361.3509,244444.8558
|
|
||||||
688334.SH,20250417,15.88,0.9535,1.6247,0.52,21.9844,20.5151,1.7695,6.297,5.9002,,,31657.9466,15373.8903,9022.5148,502728.192,244137.378
|
|
||||||
688334.SH,20250416,15.85,1.1176,1.9043,0.54,21.9429,20.4764,1.7661,6.2851,5.889,,,31657.9466,15373.8903,9022.5148,501778.4536,243676.1613
|
|
||||||
688334.SH,20250415,15.96,1.1061,1.8848,0.43,22.0952,20.6185,1.7784,6.3287,5.9299,,,31657.9466,15373.8903,9022.5148,505260.8277,245367.2892
|
|
||||||
688334.SH,20250414,16.09,1.916,3.2648,0.69,22.2752,20.7864,1.7929,6.3803,5.9782,,,31657.9466,15373.8903,9022.5148,509376.3608,247365.8949
|
|
||||||
688334.SH,20250411,15.92,2.861,4.875,1.21,22.0398,20.5668,1.7739,6.3129,5.915,,,31657.9466,15373.8903,9022.5148,503994.5099,244752.3336
|
|
||||||
688334.SH,20250410,16.07,2.2541,3.8408,1.06,31.3327,22.2475,1.8751,8.4499,6.3724,,,31657.9466,15373.8903,9022.5148,508743.2019,247058.4171
|
|
||||||
688334.SH,20250409,15.48,2.3005,3.9199,1.23,30.1824,21.4307,1.8063,8.1397,6.1384,,,31657.9466,15373.8903,9022.5148,490065.0134,237987.8218
|
|
||||||
688334.SH,20250408,15.13,3.3845,5.767,2.29,29.5,20.9461,1.7654,7.9557,5.9996,,,31657.9466,15373.8903,9022.5148,478984.7321,232606.9602
|
|
||||||
688334.SH,20250407,15.1,3.0032,5.1173,2.57,29.4415,20.9046,1.7619,7.9399,5.9877,,,31657.9466,15373.8903,9022.5148,478034.9937,232145.7435
|
|
||||||
688334.SH,20250403,17.27,0.852,1.4518,0.65,33.6725,23.9088,2.0151,9.0809,6.8482,,,31657.9466,15373.8903,9022.5148,546732.7378,265507.0855
|
|
||||||
688334.SH,20250402,17.36,1.1333,1.931,0.75,33.8479,24.0334,2.0256,9.1283,6.8839,,,31657.9466,15373.8903,9022.5148,549581.953,266890.7356
|
|
||||||
688334.SH,20250401,17.2,0.9965,1.6981,0.65,33.536,23.8119,2.0069,9.0441,6.8204,,,31657.9466,15373.8903,9022.5148,544516.6815,264430.9132
|
|
||||||
688334.SH,20250331,16.94,1.3908,2.3699,0.86,33.029,23.4519,1.9766,8.9074,6.7173,,,31657.9466,15373.8903,9022.5148,536285.6154,260433.7017
|
|
||||||
688334.SH,20250328,17.08,1.4592,2.4864,0.88,33.302,23.6457,1.9929,8.981,6.7729,,,31657.9466,15373.8903,9022.5148,540717.7279,262586.0463
|
|
||||||
688334.SH,20250327,16.95,1.5716,2.678,0.95,33.0485,23.4658,1.9778,8.9127,6.7213,,,31657.9466,15373.8903,9022.5148,536602.1949,260587.4406
|
|
||||||
688334.SH,20250326,17.15,2.1453,3.6554,1.37,33.4385,23.7426,2.0011,9.0178,6.8006,,,31657.9466,15373.8903,9022.5148,542933.7842,263662.2186
|
|
||||||
688334.SH,20250325,17.42,1.1524,1.9636,0.71,33.9649,24.1164,2.0326,9.1598,6.9077,,,31657.9466,15373.8903,9022.5148,551481.4298,267813.169
|
|
||||||
688334.SH,20250324,17.43,1.7488,3.5385,1.12,33.9844,24.1303,2.0338,9.1651,6.9116,,,31657.9466,15373.8903,7597.9072,551798.0092,267966.9079
|
|
||||||
688334.SH,20250321,17.4,1.6674,3.3738,1.01,33.9259,24.0887,2.0303,9.1493,6.8997,,,31657.9466,15373.8903,7597.9072,550848.2708,267505.6912
|
|
||||||
688334.SH,20250320,17.62,1.5397,3.1155,0.84,34.3549,24.3933,2.056,9.265,6.987,,,31657.9466,15373.8903,7597.9072,557813.0191,270887.9471
|
|
||||||
688334.SH,20250319,17.88,1.7304,3.5013,0.85,34.8618,24.7533,2.0863,9.4017,7.0901,,,31657.9466,15373.8903,7597.9072,566044.0852,274885.1586
|
|
||||||
688334.SH,20250318,17.87,1.4482,2.9303,0.74,34.8423,24.7394,2.0851,9.3964,7.0861,,,31657.9466,15373.8903,7597.9072,565727.5057,274731.4197
|
|
||||||
688334.SH,20250317,17.61,1.4218,2.8769,0.71,34.3354,24.3795,2.0548,9.2597,6.983,,,31657.9466,15373.8903,7597.9072,557496.4396,270734.2082
|
|
||||||
688334.SH,20250314,17.74,2.0766,4.2018,1.1,34.5888,24.5594,2.07,9.3281,7.0346,,,31657.9466,15373.8903,7597.9072,561611.9727,272732.8139
|
|
||||||
688334.SH,20250313,17.79,2.4501,4.9577,1.37,34.6863,24.6287,2.0758,9.3544,7.0544,,,31657.9466,15373.8903,7597.9072,563194.87,273501.5084
|
|
||||||
688334.SH,20250312,17.83,2.7823,5.6298,1.83,34.7643,24.684,2.0805,9.3754,7.0703,,,31657.9466,15373.8903,7597.9072,564461.1879,274116.464
|
|
||||||
688334.SH,20250311,17.42,1.0811,2.1875,0.68,33.9649,24.1164,2.0326,9.1598,6.9077,,,31657.9466,15373.8903,7597.9072,551481.4298,267813.169
|
|
||||||
688334.SH,20250310,17.41,1.5877,3.2127,0.94,33.9454,24.1026,2.0314,9.1545,6.9037,,,31657.9466,15373.8903,7597.9072,551164.8503,267659.4301
|
|
||||||
688334.SH,20250307,17.34,1.5606,3.1577,0.91,33.8089,24.0057,2.0233,9.1177,6.876,,,31657.9466,15373.8903,7597.9072,548948.794,266583.2578
|
|
||||||
688334.SH,20250306,17.34,1.9504,3.9465,1.14,33.8089,24.0057,2.0233,9.1177,6.876,,,31657.9466,15373.8903,7597.9072,548948.794,266583.2578
|
|
||||||
688334.SH,20250305,17.18,1.408,2.849,0.73,33.497,23.7842,2.0046,9.0336,6.8125,,,31657.9466,15373.8903,7597.9072,543883.5226,264123.4354
|
|
||||||
688334.SH,20250304,17.14,1.5007,3.0365,0.63,33.419,23.7288,1.9999,9.0126,6.7966,,,31657.9466,15373.8903,7597.9072,542617.2047,263508.4797
|
|
||||||
688334.SH,20250303,16.94,2.0077,4.0624,0.86,33.029,23.4519,1.9766,8.9074,6.7173,,,31657.9466,15373.8903,7597.9072,536285.6154,260433.7017
|
|
||||||
688334.SH,20250228,16.65,1.7251,3.4907,0.72,32.4636,23.0504,1.9428,8.7549,6.6023,,,31657.9466,15373.8903,7597.9072,527104.8109,255975.2735
|
|
||||||
688334.SH,20250227,16.98,1.8955,3.8354,0.83,33.107,23.5073,1.9813,8.9284,6.7332,,,31657.9466,15373.8903,7597.9072,537551.9333,261048.6573
|
|
||||||
688334.SH,20250226,17.02,2.4694,4.9967,1.16,33.185,23.5627,1.9859,8.9495,6.7491,,,31657.9466,15373.8903,7597.9072,538818.2511,261663.6129
|
|
||||||
688334.SH,20250225,17.01,3.782,7.6526,2.2,33.1655,23.5488,1.9848,8.9442,6.7451,,,31657.9466,15373.8903,7597.9072,538501.6717,261509.874
|
|
||||||
688334.SH,20250224,16.77,1.7383,3.5174,1.03,32.6976,26.3898,1.9568,8.818,7.2649,,,31657.9466,15373.8903,7597.9072,530903.7645,257820.1403
|
|
||||||
688334.SH,20250221,16.74,2.0563,4.1609,1.41,32.6391,26.3426,1.9533,8.8022,7.2519,,,31657.9466,15373.8903,7597.9072,529954.0261,257358.9236
|
|
||||||
688334.SH,20250220,16.73,1.3627,2.7573,0.92,32.6196,26.3269,1.9521,8.797,7.2475,,,31657.9466,15373.8903,7597.9072,529637.4466,257205.1847
|
|
||||||
688334.SH,20250219,16.72,1.6886,3.4169,1.09,32.6001,26.3111,1.9509,8.7917,7.2432,,,31657.9466,15373.8903,7597.9072,529320.8672,257051.4458
|
|
||||||
688334.SH,20250218,16.4,1.7312,3.5029,1.14,31.9762,25.8076,1.9136,8.6235,7.1046,,,31657.9466,15373.8903,7597.9072,519190.3242,252131.8009
|
|
||||||
688334.SH,20250217,16.69,1.5716,3.1801,1.08,32.5416,26.2639,1.9474,8.776,7.2302,,,31657.9466,15373.8903,7597.9072,528371.1288,256590.2291
|
|
||||||
688334.SH,20250214,16.49,0.9261,1.8739,0.54,32.1516,25.9492,1.9241,8.6708,7.1436,,,31657.9466,15373.8903,7597.9072,522039.5394,253515.451
|
|
||||||
688334.SH,20250213,16.51,1.5002,3.0355,0.92,32.1906,25.9807,1.9264,8.6813,7.1522,,,31657.9466,15373.8903,7597.9072,522672.6984,253822.9289
|
|
||||||
688334.SH,20250212,16.74,2.0422,4.1322,1.43,32.6391,26.3426,1.9533,8.8022,7.2519,,,31657.9466,15373.8903,7597.9072,529954.0261,257358.9236
|
|
||||||
688334.SH,20250211,16.53,1.582,3.2012,1.26,32.2296,26.0121,1.9288,8.6918,7.1609,,,31657.9466,15373.8903,7597.9072,523305.8573,254130.4067
|
|
||||||
688334.SH,20250210,16.52,1.2081,2.4446,1.05,32.2101,25.9964,1.9276,8.6866,7.1566,,,31657.9466,15373.8903,7597.9072,522989.2778,253976.6678
|
|
||||||
688334.SH,20250207,16.44,2.2268,4.5058,2.49,32.0541,25.8705,1.9183,8.6445,7.1219,,,31657.9466,15373.8903,7597.9072,520456.6421,252746.7565
|
|
||||||
688334.SH,20250206,16.4,1.0997,2.2253,1.44,31.9762,25.8076,1.9136,8.6235,7.1046,,,31657.9466,15373.8903,7597.9072,519190.3242,252131.8009
|
|
||||||
688334.SH,20250205,16.32,1.0075,2.0386,1.44,31.8202,25.6817,1.9043,8.5814,7.0699,,,31657.9466,15373.8903,7597.9072,516657.6885,250901.8897
|
|
||||||
688334.SH,20250127,16.24,0.7539,1.5254,1.09,31.6642,25.5558,1.8949,8.5393,7.0353,,,31657.9466,15373.8903,7597.9072,514125.0528,249671.9785
|
|
||||||
688334.SH,20250124,16.32,0.6688,1.3533,0.95,31.8202,25.6817,1.9043,8.5814,7.0699,,,31657.9466,15373.8903,7597.9072,516657.6885,250901.8897
|
|
||||||
688334.SH,20250123,16.11,0.938,1.8981,1.44,31.4107,25.3512,1.8798,8.471,6.979,,,31657.9466,15373.8903,7597.9072,510009.5197,247673.3727
|
|
||||||
688334.SH,20250122,16.27,0.4486,0.9077,0.65,31.7227,25.603,1.8984,8.5551,7.0483,,,31657.9466,15373.8903,7597.9072,515074.7912,250133.1952
|
|
||||||
688334.SH,20250121,16.35,0.6822,1.3804,0.81,31.8787,25.7289,1.9078,8.5972,7.0829,,,31657.9466,15373.8903,7597.9072,517607.4269,251363.1064
|
|
||||||
688334.SH,20250120,16.26,0.72,1.4569,0.89,31.7032,25.5873,1.8973,8.5499,7.0439,,,31657.9466,15373.8903,7597.9072,514758.2117,249979.4563
|
|
||||||
688334.SH,20250117,16.15,0.7239,1.4648,0.94,31.4887,25.4142,1.8844,8.492,6.9963,,,31657.9466,15373.8903,7597.9072,511275.8376,248288.3283
|
|
||||||
688334.SH,20250116,15.96,0.6911,1.3983,0.96,31.1183,25.1152,1.8623,8.3921,6.914,,,31657.9466,15373.8903,7597.9072,505260.8277,245367.2892
|
|
||||||
688334.SH,20250115,15.86,0.6511,1.3174,0.83,30.9233,24.9578,1.8506,8.3395,6.8707,,,31657.9466,15373.8903,7597.9072,502095.0331,243829.9002
|
|
||||||
688334.SH,20250114,16.18,1.4055,2.8439,2.15,31.5472,25.4614,1.8662,8.5078,7.0093,,,31657.9466,15373.8903,7597.9072,512225.576,248749.5451
|
|
||||||
688334.SH,20250113,15.84,0.5804,1.1744,0.79,30.8843,24.9263,1.8269,8.329,6.862,,,31657.9466,15373.8903,7597.9072,501461.8741,243522.4224
|
|
||||||
688334.SH,20250110,15.79,0.5246,1.0616,0.59,30.7868,24.8477,1.8212,8.3027,6.8403,,,31657.9466,15373.8903,7597.9072,499878.9768,242753.7278
|
|
||||||
688334.SH,20250109,15.9,0.4358,0.8819,0.41,31.0013,25.0208,1.8339,8.3606,6.888,,,31657.9466,15373.8903,7597.9072,503361.3509,244444.8558
|
|
||||||
688334.SH,20250108,15.93,0.9973,2.018,0.89,31.0598,25.068,1.8373,8.3763,6.901,,,31657.9466,15373.8903,7597.9072,504311.0893,244906.0725
|
|
||||||
688334.SH,20250107,16.16,0.7377,1.4927,0.63,31.5082,25.4299,1.8638,8.4973,7.0006,,,31657.9466,15373.8903,7597.9072,511592.4171,248442.0672
|
|
||||||
688334.SH,20250106,16.14,0.9978,2.0191,0.84,31.4692,25.3984,1.8615,8.4868,6.992,,,31657.9466,15373.8903,7597.9072,510959.2581,248134.5894
|
|
||||||
688334.SH,20250103,15.92,1.2949,2.6201,1.07,31.0403,25.0522,1.8362,8.3711,6.8966,,,31657.9466,15373.8903,7597.9072,503994.5099,244752.3336
|
|
||||||
688334.SH,20250102,16.03,1.3421,2.7156,1.06,31.2547,25.2253,1.8489,8.4289,6.9443,,,31657.9466,15373.8903,7597.9072,507476.884,246443.4615
|
|
||||||
688334.SH,20241231,16.33,1.241,2.5111,0.97,31.8397,25.6974,1.8835,8.5867,7.0743,,,31657.9466,15373.8903,7597.9072,516974.268,251055.6286
|
|
||||||
688334.SH,20241230,16.64,0.9692,1.9612,0.68,32.4441,26.1852,1.9192,8.7497,7.2086,,,31657.9466,15373.8903,7597.9072,526788.2314,255821.5346
|
|
||||||
688334.SH,20241227,16.77,1.1221,2.2705,0.73,32.6976,26.3898,1.9342,8.818,7.2649,,,31657.9466,15373.8903,7597.9072,530903.7645,257820.1403
|
|
||||||
688334.SH,20241226,16.59,1.3529,2.7375,0.89,32.3466,26.1066,1.9134,8.7234,7.1869,,,31657.9466,15373.8903,7597.9072,525205.3341,255052.8401
|
|
||||||
688334.SH,20241225,16.39,1.631,3.3003,1.15,31.9567,25.7918,1.8904,8.6182,7.1003,,,31657.9466,15373.8903,7597.9072,518873.7448,251978.062
|
|
||||||
688334.SH,20241224,16.77,1.315,2.6608,0.92,32.6976,26.3898,1.9342,8.818,7.2649,,,31657.9466,15373.8903,7597.9072,530903.7645,257820.1403
|
|
||||||
688334.SH,20241223,16.61,1.6724,3.3841,1.25,32.3856,26.138,1.9157,8.7339,7.1956,,,31657.9466,15373.8903,7597.9072,525838.493,255360.3179
|
|
||||||
688334.SH,20241220,17.03,1.6925,3.4247,1.29,33.2045,26.799,1.9642,8.9547,7.3775,,,31657.9466,15373.8903,7597.9072,539134.8306,261817.3518
|
|
||||||
688334.SH,20241219,16.93,1.2692,2.568,0.85,33.0095,26.6416,1.9527,8.9022,7.3342,,,31657.9466,15373.8903,7597.9072,535969.0359,260279.9628
|
|
||||||
688334.SH,20241218,16.75,2.3538,2.3538,0.74,32.6586,26.3583,1.9319,8.8075,7.2562,,,31657.9466,7597.9072,7597.9072,530270.6056,127264.9456
|
|
||||||
688334.SH,20241217,16.49,2.704,2.704,0.76,32.1516,25.9492,1.9019,8.6708,7.1436,,,31657.9466,7597.9072,7597.9072,522039.5394,125289.4897
|
|
||||||
688334.SH,20241216,16.84,2.4935,2.4935,0.71,32.8341,26.5,1.9423,8.8548,7.2952,,,31657.9466,7597.9072,7597.9072,533119.8207,127948.7572
|
|
||||||
688334.SH,20241213,16.83,3.1834,3.1834,0.91,32.8146,26.4842,1.9411,8.8496,7.2909,,,31657.9466,7597.9072,7597.9072,532803.2413,127872.7782
|
|
||||||
688334.SH,20241212,17.16,4.2905,4.2905,1.43,33.458,27.0035,1.9792,9.0231,7.4338,,,31657.9466,7597.9072,7597.9072,543250.3637,130380.0876
|
|
||||||
688334.SH,20241211,16.96,3.1759,3.1759,1.1,33.068,26.6888,1.9561,8.9179,7.3472,,,31657.9466,7597.9072,7597.9072,536918.7743,128860.5061
|
|
||||||
688334.SH,20241210,16.72,4.63,4.63,1.88,32.6001,26.3111,1.9284,8.7917,7.2432,,,31657.9466,7597.9072,7597.9072,529320.8672,127037.0084
|
|
||||||
688334.SH,20241209,16.75,2.1976,2.1976,0.84,32.6586,26.3583,1.9319,8.8075,7.2562,,,31657.9466,7597.9072,7597.9072,530270.6056,127264.9456
|
|
||||||
688334.SH,20241206,16.76,3.2552,3.2552,1.33,32.6781,26.3741,1.9331,8.8128,7.2605,,,31657.9466,7597.9072,7597.9072,530587.185,127340.9247
|
|
||||||
688334.SH,20241205,16.76,1.7372,1.7372,0.69,32.6781,26.3741,1.9331,8.8128,7.2605,,,31657.9466,7597.9072,7597.9072,530587.185,127340.9247
|
|
||||||
688334.SH,20241204,16.65,2.6158,2.6158,1.0,32.4636,26.201,1.9204,8.7549,7.2129,,,31657.9466,7597.9072,7597.9072,527104.8109,126505.1549
|
|
||||||
688334.SH,20241203,16.9,2.5175,2.5175,1.03,32.951,26.5944,1.9492,8.8864,7.3212,,,31657.9466,7597.9072,7597.9072,535019.2975,128404.6317
|
|
||||||
688334.SH,20241202,16.97,2.9944,2.9944,1.32,33.0875,26.7045,1.9573,8.9232,7.3515,,,31657.9466,7597.9072,7597.9072,537235.3538,128936.4852
|
|
||||||
688334.SH,20241129,16.69,2.3314,2.3314,0.97,32.5416,26.2639,1.925,8.776,7.2302,,,31657.9466,7597.9072,7597.9072,528371.1288,126809.0712
|
|
||||||
688334.SH,20241128,16.48,2.1864,2.1864,0.84,32.1321,25.9335,1.9008,8.6655,7.1392,,,31657.9466,7597.9072,7597.9072,521722.96,125213.5107
|
|
||||||
688334.SH,20241127,16.51,3.0038,3.0038,1.11,32.1906,25.9807,1.9042,8.6813,7.1522,,,31657.9466,7597.9072,7597.9072,522672.6984,125441.4479
|
|
||||||
688334.SH,20241126,16.31,1.7565,1.7565,0.59,31.8007,25.666,1.8811,8.5761,7.0656,,,31657.9466,7597.9072,7597.9072,516341.109,123921.8664
|
|
||||||
688334.SH,20241125,16.5,2.0952,2.0952,0.65,32.1711,25.9649,1.9031,8.6761,7.1479,,,31657.9466,7597.9072,7597.9072,522356.1189,125365.4688
|
|
||||||
688334.SH,20241122,16.42,3.0215,3.0215,0.9,32.0152,25.8391,1.8938,8.634,7.1133,,,31657.9466,7597.9072,7597.9072,519823.4832,124757.6362
|
|
||||||
688334.SH,20241121,17.19,3.0781,3.0781,0.82,33.5165,27.0507,1.9472,9.0389,7.4468,,,31657.9466,7597.9072,7597.9072,544200.1021,130608.0248
|
|
||||||
688334.SH,20241120,17.29,3.5365,3.5365,0.93,33.7115,27.2081,1.9585,9.0915,7.4901,,,31657.9466,7597.9072,7597.9072,547365.8967,131367.8155
|
|
||||||
688334.SH,20241119,17.08,3.1549,3.1549,0.69,33.302,26.8776,1.9347,8.981,7.3992,,,31657.9466,7597.9072,7597.9072,540717.7279,129772.255
|
|
||||||
688334.SH,20241118,16.72,3.4002,3.4002,0.61,32.6001,26.3111,1.8939,8.7917,7.2432,,,31657.9466,7597.9072,7597.9072,529320.8672,127037.0084
|
|
||||||
688334.SH,20241115,17.11,3.6372,3.6372,0.59,33.3605,26.9249,1.9381,8.9968,7.4122,,,31657.9466,7597.9072,7597.9072,541667.4663,130000.1922
|
|
||||||
688334.SH,20241114,17.5,5.113,5.113,0.84,34.1209,27.5386,1.9823,9.2019,7.5811,,,31657.9466,7597.9072,7597.9072,554014.0655,132963.376
|
|
||||||
688334.SH,20241113,18.0,3.8001,3.8001,0.58,35.0958,28.3254,2.0389,9.4648,7.7977,,,31657.9466,7597.9072,7597.9072,569843.0388,136762.3296
|
|
||||||
688334.SH,20241112,17.96,6.9867,6.9867,1.1,35.0178,28.2624,2.0344,9.4438,7.7804,,,31657.9466,7597.9072,7597.9072,568576.7209,136458.4133
|
|
||||||
688334.SH,20241111,18.33,8.4805,8.4805,1.58,35.7392,28.8447,2.0763,9.6383,7.9407,,,31657.9466,7597.9072,7597.9072,580290.1612,139269.639
|
|
||||||
688334.SH,20241108,17.49,6.3555,6.3555,1.25,34.1014,27.5228,1.9811,9.1966,7.5768,,,31657.9466,7597.9072,7597.9072,553697.486,132887.3969
|
|
||||||
688334.SH,20241107,17.32,4.9648,4.9648,0.96,33.7699,27.2553,1.9619,9.1072,7.5031,,,31657.9466,7597.9072,7597.9072,548315.6351,131595.7527
|
|
||||||
688334.SH,20241106,17.0,6.0085,6.0085,1.11,33.146,26.7518,1.9256,8.939,7.3645,,,31657.9466,7597.9072,7597.9072,538185.0922,129164.4224
|
|
||||||
688334.SH,20241105,17.17,5.9285,5.9285,1.15,33.4775,27.0193,1.9449,9.0284,7.4382,,,31657.9466,7597.9072,7597.9072,543566.9431,130456.0666
|
|
||||||
688334.SH,20241104,16.78,3.5317,3.5317,0.66,32.7171,26.4056,1.9007,8.8233,7.2692,,,31657.9466,7597.9072,7597.9072,531220.3439,127492.8828
|
|
||||||
688334.SH,20241101,16.61,5.0871,5.0871,0.99,32.3856,26.138,1.8815,8.7339,7.1956,,,31657.9466,7597.9072,7597.9072,525838.493,126201.2386
|
|
||||||
688334.SH,20241031,17.21,5.2891,5.2891,1.1,33.5555,27.0822,1.9494,9.0494,7.4555,,,31657.9466,7597.9072,7597.9072,544833.261,130759.9829
|
|
||||||
688334.SH,20241030,17.05,7.2902,7.2902,1.61,33.2435,26.8304,1.9313,8.9653,7.3862,,,31657.9466,7597.9072,7597.9072,539767.9895,129544.3178
|
|
||||||
688334.SH,20241029,17.89,4.4859,4.4859,0.89,34.8813,31.3363,1.868,9.4069,8.869,,,31657.9466,7597.9072,7597.9072,566360.6647,135926.5598
|
|
||||||
688334.SH,20241028,17.89,4.5041,4.5041,0.8,34.8813,31.3363,1.868,9.4069,8.869,,,31657.9466,7597.9072,7597.9072,566360.6647,135926.5598
|
|
||||||
688334.SH,20241025,17.93,4.1548,4.1548,0.69,34.9593,31.4064,1.8722,9.428,8.8888,,,31657.9466,7597.9072,7597.9072,567626.9825,136230.4761
|
|
||||||
688334.SH,20241024,17.71,3.6209,3.6209,0.61,34.5304,31.021,1.8492,9.3123,8.7797,,,31657.9466,7597.9072,7597.9072,560662.2343,134558.9365
|
|
||||||
688334.SH,20241023,18.02,5.8727,5.8727,1.01,35.1348,31.564,1.8816,9.4753,8.9334,,,31657.9466,7597.9072,7597.9072,570476.1977,136914.2877
|
|
||||||
688334.SH,20241022,18.18,7.1334,7.1334,1.32,35.4467,31.8443,1.8983,9.5594,9.0127,,,31657.9466,7597.9072,7597.9072,575541.4692,138129.9529
|
|
||||||
688334.SH,20241021,17.75,7.4702,7.4702,1.56,34.6083,31.0911,1.8534,9.3333,8.7996,,,31657.9466,7597.9072,7597.9072,561928.5522,134862.8528
|
|
||||||
688334.SH,20241018,17.43,6.0764,6.0764,1.27,33.9844,30.5306,1.82,9.1651,8.6409,,,31657.9466,7597.9072,7597.9072,551798.0092,132431.5225
|
|
||||||
688334.SH,20241017,17.0,3.2384,3.2384,0.59,33.146,29.7774,1.7751,8.939,8.4278,,,31657.9466,7597.9072,7597.9072,538185.0922,129164.4224
|
|
||||||
688334.SH,20241016,17.12,5.1398,5.1398,0.82,33.38,29.9876,1.7876,9.0021,8.4872,,,31657.9466,7597.9072,7597.9072,541984.0458,130076.1713
|
|
||||||
688334.SH,20241015,16.59,5.0662,5.0662,0.57,32.3466,29.0592,1.7323,8.7234,8.2245,,,31657.9466,7597.9072,7597.9072,525205.3341,126049.2804
|
|
||||||
688334.SH,20241014,16.82,4.4154,4.4154,0.41,32.7951,29.4621,1.7563,8.8443,8.3385,,,31657.9466,7597.9072,7597.9072,532486.6618,127796.7991
|
|
||||||
688334.SH,20241011,16.66,6.0708,6.0708,0.57,32.4831,29.1818,1.7396,8.7602,8.2592,,,31657.9466,7597.9072,7597.9072,527421.3904,126581.134
|
|
||||||
688334.SH,20241010,17.72,6.543,6.543,0.65,34.5498,31.0385,1.8503,9.3176,8.7847,,,31657.9466,7597.9072,7597.9072,560978.8138,134634.9156
|
|
||||||
688334.SH,20241009,17.2,9.2871,9.2871,1.03,33.536,30.1277,1.796,9.0441,8.5269,,,31657.9466,7597.9072,7597.9072,544516.6815,130684.0038
|
|
||||||
688334.SH,20241008,19.06,17.9095,17.9095,2.94,37.1625,33.3857,1.9902,10.0222,9.449,,,31657.9466,7597.9072,7597.9072,603400.4622,144816.1112
|
|
||||||
688334.SH,20240930,17.66,14.6869,14.6869,4.23,34.4329,30.9334,1.844,9.286,8.755,,,31657.9466,7597.9072,7597.9072,559079.337,134179.0412
|
|
||||||
688334.SH,20240927,15.91,4.4744,4.4744,1.34,31.0208,27.8681,1.6613,8.3658,7.8874,,,31657.9466,7597.9072,7597.9072,503677.9304,120882.7036
|
|
||||||
688334.SH,20240926,15.31,4.0457,4.0457,1.25,29.8509,26.8171,1.5986,8.0503,7.5899,,,31657.9466,7597.9072,7597.9072,484683.1624,116323.9592
|
|
||||||
688334.SH,20240925,14.94,3.8976,3.8976,1.46,29.1295,26.1691,1.56,7.8558,7.4065,,,31657.9466,7597.9072,7597.9072,472969.7222,113512.7336
|
|
||||||
688334.SH,20240924,14.97,3.3437,3.3437,1.48,29.188,26.2216,1.5631,7.8715,7.4214,,,31657.9466,7597.9072,7597.9072,473919.4606,113740.6708
|
|
||||||
688334.SH,20240923,14.66,1.5794,1.5794,0.7,28.5836,25.6786,1.5307,7.7085,7.2677,,,31657.9466,7597.9072,7597.9072,464105.4972,111385.3196
|
|
||||||
688334.SH,20240920,14.71,3.8374,3.8374,2.36,28.6811,25.7662,1.536,7.7348,7.2925,,,31657.9466,7597.9072,7597.9072,465688.3945,111765.2149
|
|
||||||
688334.SH,20240919,14.64,3.5011,3.5011,3.26,28.5446,25.6436,1.5287,7.698,7.2578,,,31657.9466,7597.9072,7597.9072,463472.3382,111233.3614
|
|
||||||
688334.SH,20240918,14.26,1.092,1.092,1.09,27.8037,24.978,1.489,7.4982,7.0694,,,31657.9466,7597.9072,7597.9072,451442.3185,108346.1567
|
|
||||||
688334.SH,20240913,14.2,1.3201,1.3201,1.39,27.6867,24.8729,1.4827,7.4667,7.0397,,,31657.9466,7597.9072,7597.9072,449542.8417,107890.2822
|
|
||||||
688334.SH,20240912,14.36,1.5106,1.5106,1.86,27.9986,25.1531,1.4994,7.5508,7.119,,,31657.9466,7597.9072,7597.9072,454608.1132,109105.9474
|
|
||||||
688334.SH,20240911,14.21,0.7008,0.7008,0.77,27.7062,24.8904,1.4838,7.4719,7.0446,,,31657.9466,7597.9072,7597.9072,449859.4212,107966.2613
|
|
||||||
688334.SH,20240910,14.19,0.7451,0.7451,0.78,27.6672,24.8553,1.4817,7.4614,7.0347,,,31657.9466,7597.9072,7597.9072,449226.2623,107814.3032
|
|
||||||
688334.SH,20240909,14.11,0.7129,0.7129,0.69,27.5112,24.7152,1.4733,7.4193,6.995,,,31657.9466,7597.9072,7597.9072,446693.6265,107206.4706
|
|
||||||
688334.SH,20240906,13.95,1.0787,1.0787,0.93,27.1992,24.435,1.4566,7.3352,6.9157,,,31657.9466,7597.9072,7597.9072,441628.3551,105990.8054
|
|
||||||
688334.SH,20240905,14.28,0.8316,0.8316,0.67,27.8427,25.013,1.4911,7.5087,7.0793,,,31657.9466,7597.9072,7597.9072,452075.4774,108498.1148
|
|
||||||
688334.SH,20240904,14.25,1.161,1.161,0.99,27.7842,24.9604,1.4879,7.493,7.0644,,,31657.9466,7597.9072,7597.9072,451125.7391,108270.1776
|
|
||||||
688334.SH,20240903,14.23,1.0055,1.0055,0.95,27.7452,24.9254,1.4858,7.4824,7.0545,,,31657.9466,7597.9072,7597.9072,450492.5801,108118.2195
|
|
||||||
688334.SH,20240902,14.15,1.0997,1.0997,1.15,27.5892,24.7853,1.4775,7.4404,7.0149,,,31657.9466,7597.9072,7597.9072,447959.9444,107510.3869
|
|
||||||
688334.SH,20240830,14.45,1.7275,1.7275,2.15,28.1741,25.3108,1.5088,7.5981,7.1636,,,31657.9466,7597.9072,7597.9072,457457.3284,109789.759
|
|
||||||
688334.SH,20240829,14.25,1.186,1.186,1.34,27.7842,25.9063,1.5144,7.493,7.2824,,,31657.9466,7597.9072,7597.9072,451125.7391,108270.1776
|
|
||||||
688334.SH,20240828,13.97,0.8188,0.8188,0.99,27.2382,25.3973,1.4847,7.3457,7.1393,,,31657.9466,7597.9072,7597.9072,442261.514,106142.7636
|
|
||||||
688334.SH,20240827,13.86,0.4442,0.4442,0.48,27.0238,25.1973,1.473,7.2879,7.083,,,31657.9466,7597.9072,7597.9072,438779.1399,105306.9938
|
|
||||||
688334.SH,20240826,13.96,0.6126,0.6126,0.67,27.2187,25.3791,1.4836,7.3405,7.1341,,,31657.9466,7597.9072,7597.9072,441944.9345,106066.7845
|
|
||||||
688334.SH,20240823,13.87,0.9563,0.9563,1.0,27.0433,25.2155,1.4741,7.2931,7.0882,,,31657.9466,7597.9072,7597.9072,439095.7193,105382.9729
|
|
||||||
688334.SH,20240822,14.0,1.5994,1.5994,1.87,27.2967,25.4518,1.4879,7.3615,7.1546,,,31657.9466,7597.9072,7597.9072,443211.2524,106370.7008
|
|
||||||
688334.SH,20240821,14.31,0.5103,0.5103,0.59,27.9011,26.0154,1.5208,7.5245,7.313,,,31657.9466,7597.9072,7597.9072,453025.2158,108726.052
|
|
||||||
688334.SH,20240820,14.3,0.9319,0.9319,1.13,27.8817,25.9972,1.5198,7.5192,7.3079,,,31657.9466,7597.9072,7597.9072,452708.6364,108650.073
|
|
||||||
688334.SH,20240819,14.38,0.5629,0.5629,0.51,28.0376,26.1427,1.5283,7.5613,7.3488,,,31657.9466,7597.9072,7597.9072,455241.2721,109257.9055
|
|
||||||
688334.SH,20240816,14.34,1.199,1.199,1.2,27.9596,26.0699,1.524,7.5403,7.3283,,,31657.9466,7597.9072,7597.9072,453974.9542,108953.9892
|
|
||||||
688334.SH,20240815,14.56,1.0698,1.0698,1.13,28.3886,26.4699,1.5474,7.656,7.4408,,,31657.9466,7597.9072,7597.9072,460939.7025,110625.5288
|
|
||||||
688334.SH,20240814,14.47,0.5399,0.5399,0.47,28.2131,26.3063,1.5378,7.6086,7.3948,,,31657.9466,7597.9072,7597.9072,458090.4873,109941.7172
|
|
||||||
688334.SH,20240813,14.55,0.7474,0.7474,0.65,28.3691,26.4517,1.5463,7.6507,7.4357,,,31657.9466,7597.9072,7597.9072,460623.123,110549.5498
|
|
||||||
688334.SH,20240812,14.49,1.9622,1.9622,1.88,28.2521,26.3426,1.54,7.6192,7.405,,,31657.9466,7597.9072,7597.9072,458723.6462,110093.6753
|
|
||||||
688334.SH,20240809,14.35,0.6907,0.6907,0.61,27.9791,26.0881,1.5251,7.5455,7.3335,,,31657.9466,7597.9072,7597.9072,454291.5337,109029.9683
|
|
||||||
688334.SH,20240808,14.38,0.7845,0.7845,0.59,28.0376,26.1427,1.5283,7.5613,7.3488,,,31657.9466,7597.9072,7597.9072,455241.2721,109257.9055
|
|
||||||
688334.SH,20240807,14.56,1.5746,1.5746,1.12,28.3886,26.4699,1.5474,7.656,7.4408,,,31657.9466,7597.9072,7597.9072,460939.7025,110625.5288
|
|
||||||
688334.SH,20240806,14.42,0.7725,0.7725,0.51,28.1156,26.2154,1.5325,7.5823,7.3692,,,31657.9466,7597.9072,7597.9072,456507.59,109561.8218
|
|
||||||
688334.SH,20240805,14.23,1.3828,1.3828,0.94,27.7452,25.87,1.5123,7.4824,7.2721,,,31657.9466,7597.9072,7597.9072,450492.5801,108118.2195
|
|
||||||
688334.SH,20240802,14.57,1.1575,1.1575,0.81,28.4081,26.4881,1.5485,7.6612,7.4459,,,31657.9466,7597.9072,7597.9072,461256.282,110701.5079
|
|
||||||
688334.SH,20240801,14.75,1.7448,1.7448,1.26,28.759,26.8153,1.5676,7.7559,7.5379,,,31657.9466,7597.9072,7597.9072,466954.7124,112069.1312
|
|
||||||
688334.SH,20240731,14.86,1.9821,1.9821,1.64,28.9735,27.0153,1.5793,7.8137,7.5941,,,31657.9466,7597.9072,7597.9072,470437.0865,112904.901
|
|
||||||
688334.SH,20240730,14.52,1.2661,1.2661,0.96,28.3106,26.3972,1.5431,7.6349,7.4203,,,31657.9466,7597.9072,7597.9072,459673.3846,110321.6125
|
|
||||||
688334.SH,20240729,14.46,1.2333,1.2333,0.96,28.1936,26.2881,1.5368,7.6034,7.3897,,,31657.9466,7597.9072,7597.9072,457773.9078,109865.7381
|
|
||||||
688334.SH,20240726,14.46,0.9628,0.9628,0.71,28.1936,26.2881,1.5368,7.6034,7.3897,,,31657.9466,7597.9072,7597.9072,457773.9078,109865.7381
|
|
||||||
688334.SH,20240725,14.3,1.4613,1.4613,1.1,27.8817,25.9972,1.5198,7.5192,7.3079,,,31657.9466,7597.9072,7597.9072,452708.6364,108650.073
|
|
||||||
688334.SH,20240724,14.28,1.1228,1.1228,0.8,27.8427,25.9609,1.5176,7.5087,7.2977,,,31657.9466,7597.9072,7597.9072,452075.4774,108498.1148
|
|
||||||
688334.SH,20240723,14.41,1.7857,1.7857,1.36,28.0961,26.1972,1.5315,7.5771,7.3641,,,31657.9466,7597.9072,7597.9072,456191.0105,109485.8428
|
|
||||||
688334.SH,20240722,14.74,1.0923,1.0923,0.78,28.7395,26.7971,1.5665,7.7506,7.5328,,,31657.9466,7597.9072,7597.9072,466638.1329,111993.1521
|
|
||||||
688334.SH,20240719,14.71,1.2728,1.2728,0.89,28.6811,26.7426,1.5633,7.7348,7.5174,,,31657.9466,7597.9072,7597.9072,465688.3945,111765.2149
|
|
||||||
688334.SH,20240718,14.68,1.3711,1.3711,0.86,28.6226,26.6881,1.5601,7.7191,7.5021,,,31657.9466,7597.9072,7597.9072,464738.6561,111537.2777
|
|
||||||
688334.SH,20240717,14.57,1.4879,1.4879,0.86,28.4081,26.4881,1.5485,7.6612,7.4459,,,31657.9466,7597.9072,7597.9072,461256.282,110701.5079
|
|
||||||
688334.SH,20240716,14.76,1.3544,1.3544,0.71,28.7785,26.8335,1.5686,7.7611,7.543,,,31657.9466,7597.9072,7597.9072,467271.2918,112145.1103
|
|
||||||
688334.SH,20240715,14.75,1.555,1.555,0.79,28.759,26.8153,1.5676,7.7559,7.5379,,,31657.9466,7597.9072,7597.9072,466954.7124,112069.1312
|
|
||||||
688334.SH,20240712,15.11,1.4001,1.4001,0.69,29.461,27.4698,1.6058,7.9452,7.7218,,,31657.9466,7597.9072,7597.9072,478351.5731,114804.3778
|
|
||||||
688334.SH,20240711,15.19,2.141,2.141,1.03,29.6169,27.6152,1.6143,7.9872,7.7627,,,31657.9466,7597.9072,7597.9072,480884.2089,115412.2104
|
|
||||||
688334.SH,20240710,14.96,2.207,2.207,0.87,29.1685,27.1971,1.5899,7.8663,7.6452,,,31657.9466,7597.9072,7597.9072,473602.8811,113664.6917
|
|
||||||
688334.SH,20240709,15.05,2.2056,2.2056,0.83,29.344,27.3607,1.5995,7.9136,7.6912,,,31657.9466,7597.9072,7597.9072,476452.0963,114348.5034
|
|
||||||
688334.SH,20240708,14.6,1.909,1.909,0.65,28.4666,26.5426,1.5516,7.677,7.4612,,,31657.9466,7597.9072,7597.9072,462206.0204,110929.4451
|
|
||||||
688334.SH,20240705,15.0,1.6448,1.6448,0.46,29.2465,27.2698,1.5942,7.8873,7.6656,,,31657.9466,7597.9072,7597.9072,474869.199,113968.608
|
|
||||||
688334.SH,20240704,14.85,2.4737,2.4737,0.71,28.954,26.9971,1.5782,7.8084,7.589,,,31657.9466,7597.9072,7597.9072,470120.507,112828.9219
|
|
||||||
688334.SH,20240703,15.26,4.3938,4.3938,1.4,29.7534,27.7425,1.6218,8.024,7.7985,,,31657.9466,7597.9072,7597.9072,483100.2651,115944.0639
|
|
||||||
688334.SH,20240702,15.85,2.8217,2.8217,0.91,30.9038,28.8151,1.6845,8.3343,8.1,,,31657.9466,7597.9072,7597.9072,501778.4536,120426.8291
|
|
||||||
688334.SH,20240701,16.09,3.2992,3.2992,0.95,31.3717,29.2514,1.71,8.4605,8.2227,,,31657.9466,7597.9072,7597.9072,509376.3608,122250.3268
|
|
||||||
688334.SH,20240628,16.1,4.902,4.902,1.45,31.3912,29.2696,1.7111,8.4657,8.2278,,,31657.9466,7597.9072,7597.9072,509692.9403,122326.3059
|
|
||||||
688334.SH,20240627,15.6,1.9914,1.9914,0.47,30.4163,28.3606,1.6579,8.2028,7.9723,,,31657.9466,7597.9072,7597.9072,493863.967,118527.3523
|
|
||||||
688334.SH,20240626,15.87,2.7009,2.7009,0.6,30.9428,28.8515,1.6866,8.3448,8.1102,,,31657.9466,7597.9072,7597.9072,502411.6125,120578.7873
|
|
||||||
688334.SH,20240625,15.44,2.6617,2.6617,0.52,30.1044,28.0697,1.6409,8.1187,7.8905,,,31657.9466,7597.9072,7597.9072,488798.6955,117311.6872
|
|
||||||
688334.SH,20240624,15.6,5.0557,5.0557,0.88,30.4163,28.3606,1.6579,8.2028,7.9723,,,31657.9466,7597.9072,7597.9072,493863.967,118527.3523
|
|
||||||
688334.SH,20240621,16.18,4.5276,4.5276,0.66,31.5472,29.415,1.7196,8.5078,8.2687,,,31657.9466,7597.9072,7597.9072,512225.576,122934.1385
|
|
||||||
688334.SH,20240620,16.18,6.4173,6.4173,0.9,31.5472,29.415,1.7196,8.5078,8.2687,,,31657.9466,7597.9072,7597.9072,512225.576,122934.1385
|
|
||||||
688334.SH,20240619,16.01,3.7555,3.7555,0.56,31.2158,29.106,1.7015,8.4184,8.1818,,,31657.9466,7597.9072,7597.9072,506843.7251,121642.4943
|
|
||||||
688334.SH,20240618,16.22,5.8279,5.8279,0.99,31.6252,29.4878,1.7238,8.5288,8.2891,,,31657.9466,7597.9072,7597.9072,513491.8939,123238.0548
|
|
||||||
688334.SH,20240617,16.14,8.1138,8.1138,1.73,31.4692,29.3423,1.7153,8.4868,8.2482,,,31657.9466,7597.9072,7597.9072,510959.2581,122630.2222
|
|
||||||
688334.SH,20240614,15.93,10.1399,10.1399,2.76,31.0598,28.9605,1.693,8.3763,8.1409,,,31657.9466,7597.9072,7597.9072,504311.0893,121034.6617
|
|
||||||
688334.SH,20240613,15.89,7.9451,7.9451,2.72,30.9818,28.8878,1.6887,8.3553,8.1205,,,31657.9466,7597.9072,7597.9072,503044.7715,120730.7454
|
|
||||||
688334.SH,20240612,15.04,1.4249,1.4249,0.42,29.3245,27.3425,1.5984,7.9084,7.6861,,,31657.9466,7597.9072,7597.9072,476135.5169,114272.5243
|
|
||||||
688334.SH,20240611,15.02,1.6835,1.6835,0.48,29.2855,27.3062,1.5963,7.8978,7.6759,,,31657.9466,7597.9072,7597.9072,475502.3579,114120.5661
|
|
||||||
688334.SH,20240607,15.02,2.2759,2.2759,0.65,29.2855,27.3062,1.5963,7.8978,7.6759,,,31657.9466,7597.9072,7597.9072,475502.3579,114120.5661
|
|
||||||
688334.SH,20240606,14.9,5.0537,5.0537,1.62,29.0515,27.088,1.5835,7.8347,7.6145,,,31657.9466,7597.9072,7597.9072,471703.4043,113208.8173
|
|
||||||
688334.SH,20240605,15.36,4.1851,4.1851,1.36,29.9484,27.9243,1.6324,8.0766,7.8496,,,31657.9466,7597.9072,7597.9072,486266.0598,116703.8546
|
|
||||||
688334.SH,20240604,15.91,3.8372,3.8372,1.08,31.0208,28.9242,1.6909,8.3658,8.1307,,,31657.9466,7597.9072,7597.9072,503677.9304,120882.7036
|
|
||||||
688334.SH,20240603,15.53,2.0957,2.0957,0.48,30.2799,28.2333,1.6505,8.166,7.9365,,,31657.9466,7597.9072,7597.9072,491647.9107,117995.4988
|
|
||||||
688334.SH,20240531,15.63,2.4314,2.4314,0.55,30.4748,28.4151,1.6611,8.2186,7.9876,,,31657.9466,7597.9072,7597.9072,494813.7054,118755.2895
|
|
||||||
688334.SH,20240530,15.78,3.032,3.032,0.69,30.7673,28.6878,1.6325,8.2975,8.0642,,,31657.9466,7597.9072,7597.9072,499562.3973,119894.9756
|
|
||||||
688334.SH,20240529,15.98,3.9387,3.9387,1.01,31.1573,29.0514,1.6532,8.4026,8.1665,,,31657.9466,7597.9072,7597.9072,505893.9867,121414.5571
|
|
||||||
688334.SH,20240528,16.23,6.3017,6.3017,1.94,31.6447,29.5059,1.679,8.5341,8.2942,,,31657.9466,7597.9072,7597.9072,513808.4733,123314.0339
|
|
||||||
688334.SH,20240527,16.02,6.0534,6.0534,1.91,31.2352,29.1242,1.6573,8.4237,8.1869,,,31657.9466,7597.9072,7597.9072,507160.3045,121718.4733
|
|
||||||
688334.SH,20240524,15.52,2.8053,2.8053,0.9,30.2604,28.2152,1.6056,8.1607,7.9314,,,31657.9466,7597.9072,7597.9072,491331.3312,117919.5197
|
|
||||||
688334.SH,20240523,15.54,2.7559,2.7559,0.88,30.2994,28.2515,1.6076,8.1713,7.9416,,,31657.9466,7597.9072,7597.9072,491964.4902,118071.4779
|
|
||||||
688334.SH,20240522,15.83,1.6638,1.6638,0.47,30.8648,28.7787,1.6376,8.3238,8.0898,,,31657.9466,7597.9072,7597.9072,501145.2947,120274.871
|
|
||||||
688334.SH,20240521,15.8,2.9243,2.9243,0.79,30.8063,28.7242,1.6345,8.308,8.0745,,,31657.9466,7597.9072,7597.9072,500195.5563,120046.9338
|
|
||||||
688334.SH,20240520,16.14,5.7107,5.7107,1.49,31.4692,29.3423,1.6697,8.4868,8.2482,,,31657.9466,7597.9072,7597.9072,510959.2581,122630.2222
|
|
||||||
688334.SH,20240517,15.74,2.6152,2.6152,0.55,30.6893,28.6151,1.6283,8.2764,8.0438,,,31657.9466,7597.9072,7597.9072,498296.0795,119591.0593
|
|
||||||
688334.SH,20240516,15.6,2.6862,2.6862,0.56,30.4163,28.3606,1.6138,8.2028,7.9723,,,31657.9466,7597.9072,7597.9072,493863.967,118527.3523
|
|
||||||
688334.SH,20240515,15.6,3.7167,3.7167,0.72,30.4163,28.3606,1.6138,8.2028,7.9723,,,31657.9466,7597.9072,7597.9072,493863.967,118527.3523
|
|
||||||
688334.SH,20240514,15.89,3.7791,3.7791,0.75,30.9818,28.8878,1.6438,8.3553,8.1205,,,31657.9466,7597.9072,7597.9072,503044.7715,120730.7454
|
|
||||||
688334.SH,20240513,16.07,6.3412,6.3412,1.36,31.3327,29.2151,1.6625,8.4499,8.2124,,,31657.9466,7597.9072,7597.9072,508743.2019,122098.3687
|
|
||||||
688334.SH,20240510,16.2,7.1677,7.1677,1.7,31.5862,29.4514,1.6759,8.5183,8.2789,,,31657.9466,7597.9072,7597.9072,512858.7349,123086.0966
|
|
||||||
688334.SH,20240509,15.96,3.0801,3.0801,0.7,31.1183,29.0151,1.6511,8.3921,8.1562,,,31657.9466,7597.9072,7597.9072,505260.8277,121262.5989
|
|
||||||
688334.SH,20240508,15.84,5.5823,5.5823,1.37,30.8843,28.7969,1.6387,8.329,8.0949,,,31657.9466,7597.9072,7597.9072,501461.8741,120350.85
|
|
||||||
688334.SH,20240507,15.81,2.8815,2.8815,0.73,30.8258,28.7424,1.6356,8.3132,8.0796,,,31657.9466,7597.9072,7597.9072,500512.1357,120122.9128
|
|
||||||
688334.SH,20240506,15.77,4.5592,4.5592,1.3,30.7478,28.6697,1.6314,8.2922,8.0591,,,31657.9466,7597.9072,7597.9072,499245.8179,119818.9965
|
|
||||||
688334.SH,20240430,15.57,4.956,4.956,1.63,30.3579,28.3061,1.6107,8.187,7.9569,,,31657.9466,7597.9072,7597.9072,492914.2286,118299.4151
|
|
||||||
688334.SH,20240429,15.58,4.1595,4.1595,1.45,30.3774,30.3774,1.6367,8.1923,8.1923,,,31657.9466,7597.9072,7597.9072,493230.808,118375.3942
|
|
||||||
688334.SH,20240426,15.3,3.8356,3.8356,1.21,29.8314,29.8314,1.6073,8.0451,8.0451,,,31657.9466,7597.9072,7597.9072,484366.583,116247.9802
|
|
||||||
688334.SH,20240425,15.23,2.2862,2.2862,0.58,29.6949,29.6949,1.5999,8.0083,8.0083,,,31657.9466,7597.9072,7597.9072,482150.5267,115716.1267
|
|
||||||
688334.SH,20240424,15.24,2.3491,2.3491,0.51,29.7144,29.7144,1.601,8.0135,8.0135,,,31657.9466,7597.9072,7597.9072,482467.1062,115792.1057
|
|
||||||
688334.SH,20240423,15.08,2.6122,2.6122,0.52,29.4025,29.4025,1.5842,7.9294,7.9294,,,31657.9466,7597.9072,7597.9072,477401.8347,114576.4406
|
|
||||||
688334.SH,20240422,15.23,3.2495,3.2495,0.55,29.6949,29.6949,1.5999,8.0083,8.0083,,,31657.9466,7597.9072,7597.9072,482150.5267,115716.1267
|
|
||||||
688334.SH,20240419,15.44,5.3189,5.3189,0.89,30.1044,30.1044,1.622,8.1187,8.1187,,,31657.9466,7597.9072,7597.9072,488798.6955,117311.6872
|
|
||||||
688334.SH,20240418,15.72,6.2042,6.2042,1.01,30.6503,30.6503,1.6514,8.2659,8.2659,,,31657.9466,7597.9072,7597.9072,497662.9206,119439.1012
|
|
||||||
688334.SH,20240417,15.5,5.6088,5.6088,1.04,30.2214,30.2214,1.6283,8.1502,8.1502,,,31657.9466,7597.9072,7597.9072,490698.1723,117767.5616
|
|
||||||
688334.SH,20240416,14.88,4.7255,4.7255,1.0,29.0125,29.0125,1.5632,7.8242,7.8242,,,31657.9466,7597.9072,7597.9072,471070.2454,113056.8591
|
|
||||||
688334.SH,20240415,15.35,7.8993,7.8993,2.24,29.9289,29.9289,1.6125,8.0714,8.0714,,,31657.9466,7597.9072,7597.9072,485949.4803,116627.8755
|
|
||||||
688334.SH,20240412,15.03,5.4364,5.4364,1.94,29.305,29.305,1.5789,7.9031,7.9031,,,31657.9466,7597.9072,7597.9072,475818.9374,114196.5452
|
|
||||||
688334.SH,20240411,15.09,7.0245,7.0245,3.76,29.422,29.422,1.5852,7.9346,7.9346,,,31657.9466,7597.9072,7597.9072,477718.4142,114652.4196
|
|
||||||
688334.SH,20240410,14.62,1.9176,1.9176,0.88,35.5054,28.5056,1.5358,8.8816,7.6875,,,31657.9466,7597.9072,7597.9072,462839.1793,111081.4033
|
|
||||||
688334.SH,20240409,14.74,1.281,1.281,0.51,35.7969,28.7396,1.5485,8.9545,7.7506,,,31657.9466,7597.9072,7597.9072,466638.1329,111993.1521
|
|
||||||
688334.SH,20240408,14.48,1.9525,1.9525,0.68,35.1654,28.2326,1.5211,8.7966,7.6139,,,31657.9466,7597.9072,7597.9072,458407.0668,110017.6963
|
|
||||||
688334.SH,20240403,14.65,1.8553,1.8553,0.51,35.5783,28.5641,1.539,8.8998,7.7033,,,31657.9466,7597.9072,7597.9072,463788.9177,111309.3405
|
|
||||||
688334.SH,20240402,14.67,2.325,2.325,0.59,35.6269,28.6031,1.5411,8.912,7.7138,,,31657.9466,7597.9072,7597.9072,464422.0766,111461.2986
|
|
||||||
688334.SH,20240401,14.83,3.4813,3.4813,0.87,36.0154,28.915,1.5579,9.0092,7.7979,,,31657.9466,7597.9072,7597.9072,469487.3481,112676.9638
|
|
||||||
688334.SH,20240329,14.8,3.0529,3.0529,0.77,35.9426,28.8565,1.5548,8.991,7.7822,,,31657.9466,7597.9072,7597.9072,468537.6097,112449.0266
|
|
||||||
688334.SH,20240328,14.4,3.6566,3.6566,0.96,34.9712,28.0766,1.5127,8.748,7.5718,,,31657.9466,7597.9072,7597.9072,455874.431,109409.8637
|
|
||||||
688334.SH,20240327,14.04,5.8004,5.8004,1.74,34.0969,27.3747,1.4749,8.5293,7.3825,,,31657.9466,7597.9072,7597.9072,444477.5703,106674.6171
|
|
||||||
688334.SH,20240326,15.05,3.673,3.673,1.09,36.5497,29.344,1.581,9.1428,7.9136,,,31657.9466,7597.9072,7597.9072,476452.0963,114348.5034
|
|
||||||
688334.SH,20240325,15.45,3.9151,3.9151,1.2,37.5211,30.1239,1.623,9.3858,8.1239,,,31657.9466,7597.9072,7597.9072,489115.275,117387.6662
|
|
||||||
688334.SH,20240322,15.89,2.7323,2.7323,0.89,38.5897,30.9818,1.6693,9.6531,8.3553,,,31657.9466,7597.9072,7597.9072,503044.7715,120730.7454
|
|
||||||
688334.SH,20240321,16.0,2.8997,2.8997,0.94,38.8568,31.1963,1.6808,9.72,8.4131,,,31657.9466,7597.9072,7597.9072,506527.1456,121566.5152
|
|
||||||
688334.SH,20240320,16.01,3.424,3.424,1.05,38.8811,31.2158,1.6819,9.726,8.4184,,,31657.9466,7597.9072,7597.9072,506843.7251,121642.4943
|
|
||||||
688334.SH,20240319,16.01,3.8623,3.8623,1.33,38.8811,31.2158,1.6819,9.726,8.4184,,,31657.9466,7597.9072,7597.9072,506843.7251,121642.4943
|
|
||||||
688334.SH,20240318,16.18,3.4128,3.4128,1.23,39.294,31.5472,1.6997,9.8293,8.5078,,,31657.9466,7597.9072,7597.9072,512225.576,122934.1385
|
|
||||||
688334.SH,20240315,15.84,1.6988,1.6988,0.62,38.4683,30.8843,1.664,9.6228,8.329,,,31657.9466,7597.9072,7597.9072,501461.8741,120350.85
|
|
||||||
688334.SH,20240314,15.7,2.9785,2.9785,1.1,38.1283,30.6113,1.6493,9.5377,8.2554,,,31657.9466,7597.9072,7597.9072,497029.7616,119287.143
|
|
||||||
688334.SH,20240313,15.91,4.3694,4.3694,1.88,38.6383,31.0208,1.6714,9.6653,8.3658,,,31657.9466,7597.9072,7597.9072,503677.9304,120882.7036
|
|
||||||
688334.SH,20240312,15.65,2.1117,2.1117,0.89,38.0068,30.5138,1.644,9.5073,8.2291,,,31657.9466,7597.9072,7597.9072,495446.8643,118907.2477
|
|
||||||
688334.SH,20240311,15.6,2.6873,2.6873,1.05,37.8854,30.4164,1.6388,9.477,8.2028,,,31657.9466,7597.9072,7597.9072,493863.967,118527.3523
|
|
||||||
688334.SH,20240308,15.16,1.47,1.47,0.54,36.8169,29.5585,1.5926,9.2097,7.9715,,,31657.9466,7597.9072,7597.9072,479934.4705,115184.2732
|
|
||||||
688334.SH,20240307,15.02,2.9144,2.9144,1.1,36.4769,29.2855,1.5779,9.1246,7.8978,,,31657.9466,7597.9072,7597.9072,475502.3579,114120.5661
|
|
||||||
688334.SH,20240306,15.32,2.4361,2.4361,0.83,37.2054,29.8704,1.6094,9.3069,8.0556,,,31657.9466,7597.9072,7597.9072,484999.7419,116399.9383
|
|
||||||
688334.SH,20240305,15.17,2.3726,2.3726,0.79,36.8411,29.578,1.5936,9.2157,7.9767,,,31657.9466,7597.9072,7597.9072,480251.0499,115260.2522
|
|
||||||
688334.SH,20240304,15.65,3.5916,3.5916,1.24,38.0068,30.5138,1.644,9.5073,8.2291,,,31657.9466,7597.9072,7597.9072,495446.8643,118907.2477
|
|
||||||
688334.SH,20240301,15.46,2.3474,2.3474,0.8,37.5454,30.1434,1.6241,9.3919,8.1292,,,31657.9466,7597.9072,7597.9072,489431.8544,117463.6453
|
|
||||||
688334.SH,20240229,15.28,2.4551,2.4551,0.86,37.1083,29.7924,1.6052,9.2826,8.0346,,,31657.9466,7597.9072,7597.9072,483733.424,116096.022
|
|
||||||
688334.SH,20240228,14.83,3.987,3.987,1.51,36.0154,28.915,1.5579,9.0092,7.7979,,,31657.9466,7597.9072,7597.9072,469487.3481,112676.9638
|
|
||||||
688334.SH,20240227,15.58,2.6215,2.6215,1.06,37.8368,30.3774,1.6367,9.4648,8.1923,,,31657.9466,7597.9072,7597.9072,493230.808,118375.3942
|
|
||||||
688334.SH,20240226,15.3,3.0212,3.0212,1.27,37.1568,29.8314,1.6073,9.2947,8.0451,,,31657.9466,7597.9072,7597.9072,484366.583,116247.9802
|
|
||||||
688334.SH,20240223,15.2,2.5246,2.5246,1.02,36.914,28.4972,1.6175,9.234,8.4799,,,31657.9466,7597.9072,7597.9072,481200.7883,115488.1894
|
|
||||||
688334.SH,20240222,15.11,2.1437,2.1437,0.86,36.6954,28.3285,1.6079,9.1793,8.4297,,,31657.9466,7597.9072,7597.9072,478351.5731,114804.3778
|
|
||||||
688334.SH,20240221,14.93,2.8781,2.8781,1.2,36.2583,27.991,1.5888,9.0699,8.3292,,,31657.9466,7597.9072,7597.9072,472653.1427,113436.7545
|
|
||||||
688334.SH,20240220,14.79,1.754,1.754,0.69,35.9183,27.7286,1.5739,8.9849,8.2511,,,31657.9466,7597.9072,7597.9072,468221.0302,112373.0475
|
|
||||||
688334.SH,20240219,14.87,2.5883,2.5883,0.94,36.1126,27.8785,1.5824,9.0335,8.2958,,,31657.9466,7597.9072,7597.9072,470753.6659,112980.8801
|
|
||||||
688334.SH,20240208,14.75,3.0363,3.0363,1.19,35.8211,27.6536,1.5696,8.9606,8.2288,,,31657.9466,7597.9072,7597.9072,466954.7124,112069.1312
|
|
||||||
688334.SH,20240207,13.96,2.2624,2.2624,0.85,33.9026,26.1725,1.4855,8.4807,7.7881,,,31657.9466,7597.9072,7597.9072,441944.9345,106066.7845
|
|
||||||
688334.SH,20240206,14.2,2.3445,2.3445,0.87,34.4854,26.6224,1.5111,8.6265,7.922,,,31657.9466,7597.9072,7597.9072,449542.8417,107890.2822
|
|
||||||
688334.SH,20240205,13.48,2.5247,2.5247,0.84,32.7369,25.2726,1.4345,8.1891,7.5203,,,31657.9466,7597.9072,7597.9072,426749.1202,102419.7891
|
|
||||||
688334.SH,20240202,14.13,3.6694,3.6694,1.31,34.3154,26.4912,1.5036,8.5839,7.8829,,,31657.9466,7597.9072,7597.9072,447326.7855,107358.4287
|
|
||||||
688334.SH,20240201,14.7,1.9788,1.9788,0.63,35.6997,27.5598,1.5643,8.9302,8.2009,,,31657.9466,7597.9072,7597.9072,465371.815,111689.2358
|
|
||||||
688334.SH,20240131,14.76,2.7222,2.7222,0.84,35.8454,27.6723,1.5707,8.9667,8.2344,,,31657.9466,7597.9072,7597.9072,467271.2918,112145.1103
|
|
||||||
688334.SH,20240130,15.03,2.6043,2.6043,0.86,36.5011,28.1785,1.5994,9.1307,8.385,,,31657.9466,7597.9072,7597.9072,475818.9374,114196.5452
|
|
||||||
688334.SH,20240129,15.65,4.0726,4.0726,1.49,38.0068,29.3409,1.6654,9.5073,8.7309,,,31657.9466,7597.9072,7597.9072,495446.8643,118907.2477
|
|
||||||
688334.SH,20240126,15.53,2.6095,2.6095,1.02,37.7154,29.1159,1.6526,9.4344,8.664,,,31657.9466,7597.9072,7597.9072,491647.9107,117995.4988
|
|
||||||
688334.SH,20240125,15.74,3.6502,3.6502,1.5,38.2254,29.5096,1.675,9.562,8.7811,,,31657.9466,7597.9072,7597.9072,498296.0795,119591.0593
|
|
||||||
688334.SH,20240124,15.07,3.2217,3.2217,1.44,36.5983,28.2535,1.6037,9.155,8.4073,,,31657.9466,7597.9072,7597.9072,477085.2553,114500.4615
|
|
||||||
688334.SH,20240123,14.49,1.607,1.607,0.71,35.1897,27.1661,1.5419,8.8026,8.0838,,,31657.9466,7597.9072,7597.9072,458723.6462,110093.6753
|
|
||||||
688334.SH,20240122,14.44,2.5825,2.5825,1.24,35.0683,27.0724,1.5366,8.7723,8.0559,,,31657.9466,7597.9072,7597.9072,457140.7489,109713.78
|
|
||||||
688334.SH,20240119,15.31,1.6881,1.6881,0.74,37.1811,28.7035,1.6292,9.3008,8.5412,,,31657.9466,7597.9072,7597.9072,484683.1624,116323.9592
|
|
||||||
688334.SH,20240118,15.42,3.0884,3.0884,1.39,37.4483,28.9097,1.6409,9.3676,8.6026,,,31657.9466,7597.9072,7597.9072,488165.5366,117159.729
|
|
||||||
688334.SH,20240117,15.7,2.1994,2.1994,0.96,38.1283,29.4346,1.6707,9.5377,8.7588,,,31657.9466,7597.9072,7597.9072,497029.7616,119287.143
|
|
||||||
688334.SH,20240116,15.92,1.6913,1.6913,0.6,38.6625,29.8471,1.6941,9.6714,8.8816,,,31657.9466,7597.9072,7597.9072,503994.5099,120958.6826
|
|
||||||
688334.SH,20240115,15.95,1.7078,1.7078,0.59,38.7354,29.9034,1.6973,9.6896,8.8983,,,31657.9466,7597.9072,7597.9072,504944.2483,121186.6198
|
|
||||||
688334.SH,20240112,16.01,2.7264,2.7264,0.98,38.8811,30.0158,1.7037,9.726,8.9318,,,31657.9466,7597.9072,7597.9072,506843.7251,121642.4943
|
|
||||||
688334.SH,20240111,16.1,2.778,2.778,1.08,39.0997,30.1846,1.7133,9.7807,8.982,,,31657.9466,7597.9072,7597.9072,509692.9403,122326.3059
|
|
||||||
688334.SH,20240110,15.92,2.5536,2.5536,0.98,38.6625,29.8471,1.6941,9.6714,8.8816,,,31657.9466,7597.9072,7597.9072,503994.5099,120958.6826
|
|
||||||
688334.SH,20240109,16.14,4.3367,4.3367,1.82,39.1968,30.2596,1.7175,9.805,9.0043,,,31657.9466,7597.9072,7597.9072,510959.2581,122630.2222
|
|
||||||
688334.SH,20240108,16.45,2.0838,2.0838,0.7,39.9497,30.8408,1.7505,9.9933,9.1772,,,31657.9466,7597.9072,7597.9072,520773.2216,124985.5734
|
|
||||||
688334.SH,20240105,16.9,2.1326,2.1326,0.64,41.0425,31.6844,1.7984,10.2667,9.4283,,,31657.9466,7597.9072,7597.9072,535019.2975,128404.6317
|
|
||||||
688334.SH,20240104,17.22,1.7308,1.7308,0.52,41.8197,32.2844,1.8324,10.4611,9.6068,,,31657.9466,7597.9072,7597.9072,545149.8405,130835.962
|
|
||||||
688334.SH,20240103,17.15,2.7292,2.7292,0.86,41.6497,32.1531,1.825,10.4186,9.5678,,,31657.9466,7597.9072,7597.9072,542933.7842,130304.1085
|
|
||||||
688334.SH,20240102,17.3,3.2482,3.2482,1.1,42.014,32.4344,1.841,10.5097,9.6514,,,31657.9466,7597.9072,7597.9072,547682.4762,131443.7946
|
|
||||||
688334.SH,20231229,17.33,4.9828,4.9828,2.08,42.0868,32.4906,1.8442,10.5279,9.6682,,,31657.9466,7597.9072,7597.9072,548632.2146,131671.7318
|
|
||||||
688334.SH,20231228,16.89,3.972,3.972,1.74,41.0182,31.6657,1.7973,10.2606,9.4227,,,31657.9466,7597.9072,7597.9072,534702.7181,128328.6526
|
|
||||||
688334.SH,20231227,16.45,1.5814,1.5814,0.56,39.9497,30.8408,1.7505,9.9933,9.1772,,,31657.9466,7597.9072,7597.9072,520773.2216,124985.5734
|
|
||||||
688334.SH,20231226,16.29,2.0422,2.0422,0.58,39.5611,30.5408,1.7335,9.8961,9.088,,,31657.9466,7597.9072,7597.9072,515707.9501,123769.9083
|
|
||||||
688334.SH,20231225,16.28,2.1574,2.1574,0.6,39.5368,30.522,1.7324,9.8901,9.0824,,,31657.9466,7597.9072,7597.9072,515391.3706,123693.9292
|
|
||||||
688334.SH,20231222,16.4,2.2061,2.2061,0.61,39.8283,30.747,1.7452,9.963,9.1493,,,31657.9466,7597.9072,7597.9072,519190.3242,124605.6781
|
|
||||||
688334.SH,20231221,16.73,3.3959,3.3959,1.02,40.6297,31.3657,1.7803,10.1634,9.3334,,,31657.9466,7597.9072,7597.9072,529637.4466,127112.9875
|
|
||||||
688334.SH,20231220,16.49,4.2564,4.2564,1.3,40.0468,30.9158,1.7548,10.0176,9.1995,,,31657.9466,7597.9072,7597.9072,522039.5394,125289.4897
|
|
||||||
688334.SH,20231219,16.48,5.7302,5.7302,2.32,40.0225,30.897,1.7537,10.0116,9.194,,,31657.9466,7597.9072,7597.9072,521722.96,125213.5107
|
|
||||||
688334.SH,20231218,16.24,2.5395,2.5395,1.02,39.4397,30.4471,1.7282,9.8658,9.0601,,,31657.9466,7139.4479,7139.4479,514125.0528,115944.6339
|
|
||||||
688334.SH,20231215,16.67,2.4852,2.4852,1.01,40.484,31.2532,1.7739,10.127,9.3,,,31657.9466,7139.4479,7139.4479,527737.9698,119014.5965
|
|
||||||
688334.SH,20231214,16.98,1.9765,1.9765,0.8,41.2368,31.8344,1.8069,10.3153,9.4729,,,31657.9466,7139.4479,7139.4479,537551.9333,121227.8253
|
|
||||||
688334.SH,20231213,16.94,4.2637,4.2637,2.0,41.1397,31.7594,1.8027,10.291,9.4506,,,31657.9466,7139.4479,7139.4479,536285.6154,120942.2474
|
|
||||||
688334.SH,20231212,16.77,1.8672,1.8672,0.81,40.7268,31.4407,1.7846,10.1877,9.3558,,,31657.9466,7139.4479,7139.4479,530903.7645,119728.5413
|
|
||||||
688334.SH,20231211,16.91,1.8392,1.8392,0.69,41.0668,31.7032,1.7995,10.2728,9.4339,,,31657.9466,7139.4479,7139.4479,535335.877,120728.064
|
|
||||||
688334.SH,20231208,16.71,2.3393,2.3393,0.84,40.5811,31.3282,1.7782,10.1513,9.3223,,,31657.9466,7139.4479,7139.4479,529004.2877,119300.1744
|
|
||||||
688334.SH,20231207,16.84,2.0008,2.0008,0.67,40.8968,31.5719,1.792,10.2303,9.3948,,,31657.9466,7139.4479,7139.4479,533119.8207,120228.3026
|
|
||||||
688334.SH,20231206,17.0,2.6306,2.6306,0.8,41.2854,31.8719,1.809,10.3275,9.4841,,,31657.9466,7139.4479,7139.4479,538185.0922,121370.6143
|
|
||||||
688334.SH,20231205,17.12,2.7555,2.7555,0.69,41.5768,32.0969,1.8218,10.4004,9.551,,,31657.9466,7139.4479,7139.4479,541984.0458,122227.348
|
|
||||||
688334.SH,20231204,17.43,3.6318,3.6318,0.74,42.3297,32.6781,1.8548,10.5887,9.724,,,31657.9466,7139.4479,7139.4479,551798.0092,124440.5769
|
|
||||||
688334.SH,20231201,17.15,2.9339,2.9339,0.61,41.6497,32.1531,1.825,10.4186,9.5678,,,31657.9466,7139.4479,7139.4479,542933.7842,122441.5315
|
|
||||||
688334.SH,20231130,17.2,3.0759,3.0759,0.67,41.7711,32.2469,1.8303,10.449,9.5956,,,31657.9466,7139.4479,7139.4479,544516.6815,122798.5039
|
|
||||||
688334.SH,20231129,17.1,4.1266,4.1266,0.96,41.5282,32.0594,1.8197,10.3882,9.5399,,,31657.9466,7139.4479,7139.4479,541350.8869,122084.5591
|
|
||||||
688334.SH,20231128,17.46,6.1122,6.1122,1.64,42.4025,32.7343,1.858,10.6069,9.7407,,,31657.9466,7139.4479,7139.4479,552747.7476,124654.7603
|
|
||||||
688334.SH,20231127,17.33,8.1378,8.1378,3.14,42.0868,32.4906,1.8442,10.5279,9.6682,,,31657.9466,7139.4479,7139.4479,548632.2146,123726.6321
|
|
||||||
688334.SH,20231124,16.7,2.5027,2.5027,1.0,40.5568,31.3095,1.7771,10.1452,9.3167,,,31657.9466,7139.4479,7139.4479,528687.7082,119228.7799
|
|
||||||
688334.SH,20231123,17.01,1.9512,1.9512,0.73,41.3097,31.8907,1.8101,10.3335,9.4896,,,31657.9466,7139.4479,7139.4479,538501.6717,121442.0088
|
|
||||||
688334.SH,20231122,16.81,2.8354,2.8354,0.96,40.824,31.5157,1.7888,10.212,9.3781,,,31657.9466,7139.4479,7139.4479,532170.0823,120014.1192
|
|
||||||
688334.SH,20231121,17.09,3.1588,3.1588,1.06,41.504,32.0406,1.8186,10.3821,9.5343,,,31657.9466,7139.4479,7139.4479,541034.3074,122013.1646
|
|
||||||
688334.SH,20231120,17.23,2.5272,2.5272,0.79,41.844,32.3031,1.8335,10.4672,9.6124,,,31657.9466,7139.4479,7139.4479,545466.4199,123012.6873
|
|
||||||
688334.SH,20231117,17.25,2.0108,2.0108,0.5,41.8925,32.3406,1.8356,10.4793,9.6235,,,31657.9466,7139.4479,7139.4479,546099.5789,123155.4763
|
|
||||||
688334.SH,20231116,17.19,2.9204,2.9204,0.76,41.7468,32.2281,1.8293,10.4429,9.5901,,,31657.9466,7139.4479,7139.4479,544200.1021,122727.1094
|
|
||||||
688334.SH,20231115,17.4,4.114,4.114,1.06,42.2568,32.6218,1.8516,10.5705,9.7072,,,31657.9466,7139.4479,7139.4479,550848.2708,124226.3935
|
|
||||||
688334.SH,20231114,17.35,3.2689,3.2689,0.8,42.1354,32.5281,1.8463,10.5401,9.6793,,,31657.9466,7139.4479,7139.4479,549265.3735,123869.4211
|
|
||||||
688334.SH,20231113,17.26,3.7487,3.7487,0.94,41.9168,32.3594,1.8367,10.4854,9.6291,,,31657.9466,7139.4479,7139.4479,546416.1583,123226.8708
|
|
||||||
688334.SH,20231110,17.25,5.8702,5.8702,1.8,41.8925,32.3406,1.8356,10.4793,9.6235,,,31657.9466,7139.4479,7139.4479,546099.5789,123155.4763
|
|
||||||
688334.SH,20231109,16.9,2.3301,2.3301,0.73,41.0425,31.6844,1.7984,10.2667,9.4283,,,31657.9466,7139.4479,7139.4479,535019.2975,120656.6695
|
|
||||||
688334.SH,20231108,16.93,4.1104,4.1104,1.45,41.1154,31.7407,1.8016,10.2849,9.445,,,31657.9466,7139.4479,7139.4479,535969.0359,120870.8529
|
|
||||||
688334.SH,20231107,17.09,4.2725,4.2725,1.72,41.504,32.0406,1.8186,10.3821,9.5343,,,31657.9466,7139.4479,7139.4479,541034.3074,122013.1646
|
|
||||||
688334.SH,20231106,17.06,3.3159,3.3159,1.35,41.4311,31.9844,1.8154,10.3639,9.5175,,,31657.9466,7139.4479,7139.4479,540084.569,121798.9812
|
|
||||||
688334.SH,20231103,17.0,2.2582,2.2582,0.86,41.2854,31.8719,1.809,10.3275,9.4841,,,31657.9466,7139.4479,7139.4479,538185.0922,121370.6143
|
|
||||||
688334.SH,20231102,16.86,1.9387,1.9387,0.75,40.9454,31.6094,1.7941,10.2424,9.406,,,31657.9466,7139.4479,7139.4479,533752.9797,120371.0916
|
|
||||||
688334.SH,20231101,16.99,2.3494,2.3494,0.91,41.2611,31.8532,1.808,10.3214,9.4785,,,31657.9466,7139.4479,7139.4479,537868.5127,121299.2198
|
|
||||||
688334.SH,20231031,17.18,2.5914,2.5914,0.9,41.7225,32.2094,1.8282,10.4368,9.5845,,,31657.9466,7139.4479,7139.4479,543883.5226,122655.7149
|
|
||||||
688334.SH,20231030,17.05,3.1046,3.1046,0.99,41.4068,31.9657,1.8144,10.3578,9.512,,,31657.9466,7139.4479,7139.4479,539767.9895,121727.5867
|
|
||||||
688334.SH,20231027,16.75,3.1156,3.1156,1.02,40.6782,33.242,1.8086,10.1756,9.5754,,,31657.9466,7139.4479,7139.4479,530270.6056,119585.7523
|
|
||||||
688334.SH,20231026,16.42,1.7527,1.7527,0.54,39.8768,32.5871,1.7729,9.9751,9.3867,,,31657.9466,7139.4479,7139.4479,519823.4832,117229.7345
|
|
||||||
688334.SH,20231025,16.42,2.3198,2.3198,0.68,39.8768,32.5871,1.7729,9.9751,9.3867,,,31657.9466,7139.4479,7139.4479,519823.4832,117229.7345
|
|
||||||
688334.SH,20231024,16.47,4.1,4.1,1.19,39.9983,32.6863,1.7783,10.0055,9.4153,,,31657.9466,7139.4479,7139.4479,521406.3805,117586.7069
|
|
||||||
688334.SH,20231023,15.74,4.3676,4.3676,1.36,38.2254,31.2375,1.6995,9.562,8.998,,,31657.9466,7139.4479,7139.4479,498296.0795,112374.9099
|
|
||||||
688334.SH,20231020,16.61,2.7299,2.7299,0.82,40.3383,32.9641,1.7935,10.0905,9.4953,,,31657.9466,7139.4479,7139.4479,525838.493,118586.2296
|
|
||||||
688334.SH,20231019,16.78,2.8025,2.8025,0.87,40.7511,33.3015,1.8118,10.1938,9.5925,,,31657.9466,7139.4479,7139.4479,531220.3439,119799.9358
|
|
||||||
688334.SH,20231018,16.79,3.1271,3.1271,0.95,40.7754,33.3214,1.8129,10.1999,9.5982,,,31657.9466,7139.4479,7139.4479,531536.9234,119871.3302
|
|
||||||
688334.SH,20231017,17.11,4.1328,4.1328,1.38,41.5525,33.9564,1.8474,10.3943,9.7812,,,31657.9466,7139.4479,7139.4479,541667.4663,122155.9536
|
|
||||||
688334.SH,20231016,16.68,3.264,3.264,1.09,40.5082,33.1031,1.801,10.1331,9.5354,,,31657.9466,7139.4479,7139.4479,528054.5493,119085.991
|
|
||||||
688334.SH,20231013,16.92,3.2619,3.2619,1.02,41.0911,33.5794,1.8269,10.2789,9.6726,,,31657.9466,7139.4479,7139.4479,535652.4565,120799.4585
|
|
||||||
688334.SH,20231012,17.3,2.2385,2.2385,0.66,42.014,34.3335,1.868,10.5097,9.8898,,,31657.9466,7139.4479,7139.4479,547682.4762,123512.4487
|
|
||||||
688334.SH,20231011,17.36,3.6243,3.6243,1.09,42.1597,34.4526,1.8744,10.5462,9.9241,,,31657.9466,7139.4479,7139.4479,549581.953,123940.8155
|
|
||||||
688334.SH,20231010,17.24,2.6283,2.6283,0.8,41.8682,34.2144,1.8615,10.4733,9.8555,,,31657.9466,7139.4479,7139.4479,545782.9994,123084.0818
|
|
||||||
688334.SH,20231009,17.15,3.1669,3.1669,0.98,41.6497,34.0358,1.8518,10.4186,9.804,,,31657.9466,7139.4479,7139.4479,542933.7842,122441.5315
|
|
||||||
688334.SH,20230928,17.13,4.3287,4.3287,1.57,41.6011,33.9961,1.8496,10.4064,9.7926,,,31657.9466,7139.4479,7139.4479,542300.6253,122298.7425
|
|
||||||
688334.SH,20230927,16.83,3.1969,3.1969,1.29,40.8725,33.4007,1.8172,10.2242,9.6211,,,31657.9466,7139.4479,7139.4479,532803.2413,120156.9082
|
|
||||||
688334.SH,20230926,16.63,3.2451,3.2451,1.29,40.3868,33.0038,1.7956,10.1027,9.5068,,,31657.9466,7139.4479,7139.4479,526471.652,118729.0186
|
|
||||||
688334.SH,20230925,16.49,2.5383,2.5383,1.03,40.0468,32.726,1.7805,10.0176,9.4267,,,31657.9466,7139.4479,7139.4479,522039.5394,117729.4959
|
|
||||||
688334.SH,20230922,16.57,2.8278,2.8278,1.2,40.2411,32.8848,1.7891,10.0662,9.4725,,,31657.9466,7139.4479,7139.4479,524572.1752,118300.6517
|
|
||||||
688334.SH,20230921,16.24,2.0092,2.0092,0.77,39.4397,32.2298,1.7535,9.8658,9.2838,,,31657.9466,7139.4479,7139.4479,514125.0528,115944.6339
|
|
||||||
688334.SH,20230920,16.18,1.7569,1.7569,0.6,39.294,32.1108,1.747,9.8293,9.2495,,,31657.9466,7139.4479,7139.4479,512225.576,115516.267
|
|
||||||
688334.SH,20230919,16.31,3.4601,3.4601,1.27,39.6097,32.3688,1.7611,9.9083,9.3238,,,31657.9466,7139.4479,7139.4479,516341.109,116444.3952
|
|
||||||
688334.SH,20230918,16.64,2.2872,2.2872,0.73,40.4111,33.0237,1.7967,10.1088,9.5125,,,31657.9466,7139.4479,7139.4479,526788.2314,118800.4131
|
|
||||||
688334.SH,20230915,16.53,2.2278,2.2278,0.68,40.144,32.8054,1.7848,10.0419,9.4496,,,31657.9466,7139.4479,7139.4479,523305.8573,118015.0738
|
|
||||||
688334.SH,20230914,16.55,3.3276,3.3276,0.9,40.1925,32.8451,1.787,10.0541,9.461,,,31657.9466,7139.4479,7139.4479,523939.0162,118157.8627
|
|
||||||
688334.SH,20230913,16.9,3.2588,3.2588,0.86,41.0425,33.5397,1.8248,10.2667,9.6611,,,31657.9466,7139.4479,7139.4479,535019.2975,120656.6695
|
|
||||||
688334.SH,20230912,17.29,2.5151,2.5151,0.58,41.9897,34.3137,1.8669,10.5036,9.8841,,,31657.9466,7139.4479,7139.4479,547365.8967,123441.0542
|
|
||||||
688334.SH,20230911,17.42,4.2908,4.2908,0.88,42.3054,34.5717,1.8809,10.5826,9.9584,,,31657.9466,7139.4479,7139.4479,551481.4298,124369.1824
|
|
||||||
688334.SH,20230908,17.02,3.0356,3.0356,0.53,41.334,33.7778,1.8377,10.3396,9.7297,,,31657.9466,7139.4479,7139.4479,538818.2511,121513.4033
|
|
||||||
688334.SH,20230907,16.96,5.4172,5.4172,0.74,41.1882,33.6587,1.8312,10.3032,9.6954,,,31657.9466,7139.4479,7139.4479,536918.7743,121085.0364
|
|
||||||
688334.SH,20230906,17.69,3.6903,3.6903,0.42,42.9611,35.1075,1.9101,10.7466,10.1127,,,31657.9466,7139.4479,7139.4479,560029.0754,126296.8334
|
|
||||||
688334.SH,20230905,17.64,5.3384,5.3384,0.55,42.8397,35.0083,1.9047,10.7162,10.0842,,,31657.9466,7139.4479,7139.4479,558446.178,125939.861
|
|
||||||
688334.SH,20230904,17.83,6.8821,6.8821,0.69,43.3011,35.3853,1.9252,10.8317,10.1928,,,31657.9466,7139.4479,7139.4479,564461.1879,127296.3561
|
|
||||||
688334.SH,20230901,17.88,7.2269,7.2269,0.71,43.4225,35.4846,1.9306,10.862,10.2214,,,31657.9466,7139.4479,7139.4479,566044.0852,127653.3285
|
|
||||||
688334.SH,20230831,17.85,13.6489,13.6489,1.41,43.3497,35.425,1.9273,10.8438,10.2042,,,31657.9466,7139.4479,7139.4479,565094.3468,127439.145
|
|
||||||
688334.SH,20230830,17.83,10.9488,10.9488,1.21,43.3011,35.3853,1.9252,10.8317,10.1928,,,31657.9466,7139.4479,7139.4479,564461.1879,127296.3561
|
|
||||||
688334.SH,20230829,17.28,10.1877,10.1877,1.14,41.9654,35.2158,1.8574,10.4976,9.5794,,,31657.9466,7139.4479,7139.4479,547049.3172,123369.6597
|
|
||||||
688334.SH,20230828,16.06,8.1533,8.1533,0.88,39.0025,32.7295,1.7262,9.7564,8.9031,,,31657.9466,7139.4479,7139.4479,508426.6224,114659.5333
|
|
||||||
688334.SH,20230825,15.76,8.077,8.077,0.72,38.274,32.1181,1.694,9.5742,8.7368,,,31657.9466,7139.4479,7139.4479,498929.2384,112517.6989
|
|
||||||
688334.SH,20230824,16.84,10.9239,10.9239,1.07,40.8968,34.3191,1.8101,10.2303,9.3355,,,31657.9466,7139.4479,7139.4479,533119.8207,120228.3026
|
|
||||||
688334.SH,20230823,16.74,7.8543,7.8543,0.81,40.654,34.1153,1.7993,10.1695,9.2801,,,31657.9466,7139.4479,7139.4479,529954.0261,119514.3578
|
|
||||||
688334.SH,20230822,17.47,9.862,9.862,1.17,42.4268,35.603,1.8778,10.613,9.6848,,,31657.9466,7139.4479,7139.4479,553064.3271,124726.1548
|
|
||||||
688334.SH,20230821,17.75,9.5853,9.5853,1.29,43.1068,36.1736,1.9079,10.7831,9.84,,,31657.9466,7139.4479,7139.4479,561928.5522,126725.2002
|
|
||||||
688334.SH,20230818,17.95,18.0818,18.0818,3.65,43.5925,36.5812,1.9294,10.9046,9.9509,,,31657.9466,7139.4479,7139.4479,568260.1415,128153.0898
|
|
||||||
688334.SH,20230817,17.41,5.4894,5.4894,1.03,42.2811,35.4807,1.8713,10.5765,9.6515,,,31657.9466,7139.4479,7139.4479,551164.8503,124297.7879
|
|
||||||
688334.SH,20230816,17.13,5.2584,5.2584,0.9,41.6011,34.9101,1.8413,10.4064,9.4963,,,31657.9466,7139.4479,7139.4479,542300.6253,122298.7425
|
|
||||||
688334.SH,20230815,16.95,3.5963,3.5963,0.63,41.164,34.5432,1.8219,10.2971,9.3965,,,31657.9466,7139.4479,7139.4479,536602.1949,121013.6419
|
|
||||||
688334.SH,20230814,17.08,4.7632,4.7632,0.84,41.4797,34.8082,1.8359,10.3761,9.4686,,,31657.9466,7139.4479,7139.4479,540717.7279,121941.7701
|
|
||||||
688334.SH,20230811,17.12,5.6644,5.6644,1.09,41.5768,34.8897,1.8402,10.4004,9.4907,,,31657.9466,7139.4479,7139.4479,541984.0458,122227.348
|
|
||||||
688334.SH,20230810,17.55,7.4446,7.4446,1.57,42.6211,35.766,1.8864,10.6616,9.7291,,,31657.9466,7139.4479,7139.4479,555596.9628,125297.3106
|
|
||||||
688334.SH,20230809,17.36,7.7918,7.7918,1.55,42.1597,35.3788,1.866,10.5462,9.6238,,,31657.9466,7139.4479,7139.4479,549581.953,123940.8155
|
|
||||||
688334.SH,20230808,17.01,2.8013,2.8013,0.56,41.3097,34.6655,1.8284,10.3335,9.4298,,,31657.9466,7139.4479,7139.4479,538501.6717,121442.0088
|
|
||||||
688334.SH,20230807,16.9,4.7017,4.7017,0.99,41.0425,34.4413,1.8165,10.2667,9.3688,,,31657.9466,7139.4479,7139.4479,535019.2975,120656.6695
|
|
||||||
688334.SH,20230804,17.18,3.3593,3.3593,0.58,41.7225,35.012,1.8466,10.4368,9.524,,,31657.9466,7139.4479,7139.4479,543883.5226,122655.7149
|
|
||||||
688334.SH,20230803,17.09,4.9996,4.9996,0.88,41.504,34.8286,1.837,10.3821,9.4741,,,31657.9466,7139.4479,7139.4479,541034.3074,122013.1646
|
|
||||||
688334.SH,20230802,17.38,9.2563,9.2563,2.0,42.2082,35.4196,1.8681,10.5583,9.6349,,,31657.9466,7139.4479,7139.4479,550215.1119,124083.6045
|
|
||||||
688334.SH,20230801,17.07,2.7068,2.7068,0.52,41.4554,34.7878,1.8348,10.37,9.463,,,31657.9466,7139.4479,7139.4479,540401.1485,121870.3757
|
|
||||||
688334.SH,20230731,17.15,3.512,3.512,0.67,41.6497,34.9508,1.8434,10.4186,9.5074,,,31657.9466,7139.4479,7139.4479,542933.7842,122441.5315
|
|
||||||
688334.SH,20230728,17.12,8.5607,8.5607,1.86,41.5768,34.8897,1.8402,10.4004,9.4907,,,31657.9466,7139.4479,7139.4479,541984.0458,122227.348
|
|
||||||
688334.SH,20230727,17.23,4.2701,4.2701,0.88,41.844,35.1139,1.852,10.4672,9.5517,,,31657.9466,7139.4479,7139.4479,545466.4199,123012.6873
|
|
||||||
688334.SH,20230726,17.24,4.0478,4.0478,0.81,41.8682,35.1343,1.8531,10.4733,9.5573,,,31657.9466,7139.4479,7139.4479,545782.9994,123084.0818
|
|
||||||
688334.SH,20230725,17.48,5.8562,5.8562,1.06,42.4511,35.6234,1.8789,10.619,9.6903,,,31657.9466,7139.4479,7139.4479,553380.9066,124797.5493
|
|
||||||
688334.SH,20230724,17.04,3.3041,3.3041,0.52,41.3825,34.7267,1.8316,10.3518,9.4464,,,31657.9466,7139.4479,7139.4479,539451.4101,121656.1922
|
|
||||||
688334.SH,20230721,17.18,5.5546,5.5546,0.84,41.7225,35.012,1.8466,10.4368,9.524,,,31657.9466,7139.4479,7139.4479,543883.5226,122655.7149
|
|
||||||
688334.SH,20230720,17.5,5.4096,5.4096,0.77,42.4997,35.6641,1.881,10.6312,9.7014,,,31657.9466,7139.4479,7139.4479,554014.0655,124940.3383
|
|
||||||
688334.SH,20230719,17.86,4.9121,4.9121,0.63,43.3739,36.3978,1.9197,10.8499,9.901,,,31657.9466,7139.4479,7139.4479,565410.9263,127510.5395
|
|
||||||
688334.SH,20230718,17.81,8.4596,8.4596,1.12,43.2525,36.2959,1.9143,10.8195,9.8732,,,31657.9466,7139.4479,7139.4479,563828.0289,127153.5671
|
|
||||||
688334.SH,20230717,18.15,7.2875,7.2875,0.88,44.0782,36.9888,1.9509,11.0261,10.0617,,,31657.9466,7139.4479,7139.4479,574591.7308,129580.9794
|
|
||||||
688334.SH,20230714,18.23,6.9803,6.9803,0.83,44.2725,37.1518,1.9595,11.0747,10.1061,,,31657.9466,7139.4479,7139.4479,577124.3665,130152.1352
|
|
||||||
688334.SH,20230713,18.27,7.6966,7.6966,0.91,44.3696,37.2333,1.9638,11.099,10.1283,,,31657.9466,7139.4479,7139.4479,578390.6844,130437.7131
|
|
||||||
688334.SH,20230712,18.03,8.7046,8.7046,1.06,43.7868,36.7442,1.938,10.9532,9.9952,,,31657.9466,7139.4479,7139.4479,570792.7772,128724.2456
|
|
||||||
688334.SH,20230711,18.41,7.1476,7.1476,0.89,44.7096,37.5187,1.9788,11.184,10.2059,,,31657.9466,7139.4479,7139.4479,582822.7969,131437.2358
|
|
||||||
688334.SH,20230710,18.45,11.0064,11.0064,1.43,44.8068,37.6002,1.9831,11.2083,10.228,,,31657.9466,7139.4479,7139.4479,584089.1148,131722.8138
|
|
||||||
688334.SH,20230707,17.84,7.3353,7.3353,0.88,43.3254,36.357,1.9176,10.8377,9.8899,,,31657.9466,7139.4479,7139.4479,564777.7673,127367.7505
|
|
||||||
688334.SH,20230706,18.18,8.2955,8.2955,0.94,44.1511,37.0499,1.9541,11.0443,10.0784,,,31657.9466,7139.4479,7139.4479,575541.4692,129795.1628
|
|
||||||
688334.SH,20230705,17.87,7.2389,7.2389,0.69,43.3982,36.4182,1.9208,10.856,9.9065,,,31657.9466,7139.4479,7139.4479,565727.5057,127581.934
|
|
||||||
688334.SH,20230704,18.16,6.4172,6.4172,0.51,44.1025,37.0092,1.952,11.0321,10.0673,,,31657.9466,7139.4479,7139.4479,574908.3103,129652.3739
|
|
||||||
688334.SH,20230703,18.07,9.3156,9.3156,0.64,43.8839,36.8257,1.9423,10.9775,10.0174,,,31657.9466,7139.4479,7139.4479,572059.0951,129009.8236
|
|
||||||
688334.SH,20230630,17.96,10.2767,10.2767,0.53,43.6168,36.6016,1.9305,10.9106,9.9564,,,31657.9466,7139.4479,7139.4479,568576.7209,128224.4843
|
|
||||||
688334.SH,20230629,17.78,10.7835,10.7835,0.41,43.1797,36.2347,1.9111,10.8013,9.8566,,,31657.9466,7139.4479,7139.4479,562878.2905,126939.3837
|
|
||||||
688334.SH,20230628,17.48,15.7032,15.7032,0.42,42.4511,35.6234,1.8789,10.619,9.6903,,,31657.9466,7139.4479,7139.4479,553380.9066,124797.5493
|
|
||||||
688334.SH,20230627,18.16,17.3551,17.3551,,44.1025,37.0092,1.952,11.0321,10.0673,,,31657.9466,7139.4479,7139.4479,574908.3103,129652.3739
|
|
||||||
688334.SH,20230626,18.41,19.0348,19.0348,,44.7096,37.5187,1.9788,11.184,10.2059,,,31657.9466,7139.4479,7139.4479,582822.7969,131437.2358
|
|
||||||
688334.SH,20230621,18.2,34.0342,34.0342,,44.1996,37.0907,1.9563,11.0564,10.0895,,,31657.9466,7139.4479,7139.4479,576174.6281,129937.9518
|
|
||||||
688334.SH,20230620,19.76,46.7683,46.7683,,47.9882,40.2699,2.1239,12.0041,10.9543,,,31657.9466,7139.4479,7139.4479,625561.0248,141075.4905
|
|
||||||
688334.SH,20230619,20.73,71.6977,71.6977,,50.3439,42.2467,2.2282,12.5934,11.492,,,31657.9466,7139.4479,7139.4479,656269.233,148000.755
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
688334.SH,20250821,20250630,12225
|
|
||||||
688334.SH,20250411,20250331,12082
|
|
||||||
688334.SH,20250411,20241231,12364
|
|
||||||
688334.SH,20241030,20240930,12979
|
|
||||||
688334.SH,20240830,20240630,14145
|
|
||||||
688334.SH,20240411,20240331,14265
|
|
||||||
688334.SH,20240430,20240331,14265
|
|
||||||
688334.SH,20240411,20231231,15965
|
|
||||||
688334.SH,20240103,20231229,15965
|
|
||||||
688334.SH,20231028,20230930,22857
|
|
||||||
688334.SH,20230830,20230630,30695
|
|
||||||
688334.SH,20230616,20230619,66464
|
|
||||||
688334.SH,20220630,20220630,7
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,basic_eps,diluted_eps,total_revenue,revenue,int_income,prem_earned,comm_income,n_commis_income,n_oth_income,n_oth_b_income,prem_income,out_prem,une_prem_reser,reins_income,n_sec_tb_income,n_sec_uw_income,n_asset_mg_income,oth_b_income,fv_value_chg_gain,invest_income,ass_invest_income,forex_gain,total_cogs,oper_cost,int_exp,comm_exp,biz_tax_surchg,sell_exp,admin_exp,fin_exp,assets_impair_loss,prem_refund,compens_payout,reser_insur_liab,div_payt,reins_exp,oper_exp,compens_payout_refu,insur_reser_refu,reins_cost_refund,other_bus_cost,operate_profit,non_oper_income,non_oper_exp,nca_disploss,total_profit,income_tax,n_income,n_income_attr_p,minority_gain,oth_compr_income,t_compr_income,compr_inc_attr_p,compr_inc_attr_m_s,ebit,ebitda,insurance_exp,undist_profit,distable_profit,rd_exp,fin_exp_int_exp,fin_exp_int_inc,transfer_surplus_rese,transfer_housing_imprest,transfer_oth,adj_lossgain,withdra_legal_surplus,withdra_legal_pubfund,withdra_biz_devfund,withdra_rese_fund,withdra_oth_ersu,workers_welfare,distr_profit_shrhder,prfshare_payable_dvd,comshare_payable_dvd,capit_comstock_div,continued_net_profit,update_flag
|
|
||||||
688334.SH,20251022,20251022,20250930,1,1,3,0.6239,0.6239,650928346.79,650928346.79,,,,,,,,,,,,,,,4282314.86,22417831.22,300843.72,,430002960.18,292302064.23,,,11598249.2,12183961.08,67365968.79,-4364779.24,534840.44,,,,,,,,,,,259006799.27,115512.44,6434.47,,259115877.24,38302712.1,220813165.14,197506230.52,23306934.62,-80000.0,220733165.14,197426230.52,23306934.62,227692606.27,,,,,51514223.99,879973.15,5443168.92,,,,,,,,,,,,,,,220813165.14,1
|
|
||||||
688334.SH,20250821,20250821,20250630,1,1,2,0.42,0.42,419623079.26,419623079.26,,,,,,,,,,,,,,,3467377.36,14924721.67,92608.67,,277636654.25,184804671.88,,,7665463.62,7817218.07,44352361.16,-2552341.25,534840.44,,,,,,,,,,,167817468.43,54401.18,,,167871869.61,20334431.99,147537437.62,132706246.05,14831191.57,-80000.0,147457437.62,132626246.05,14831191.57,147040976.05,217570064.16,,,,36145033.64,555025.1,3283581.16,,,,,,,,,,,,,,,147537437.62,1
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,0.1989,0.1989,206756354.67,206756354.67,,,,,,,,,,,,,,,1741712.09,7534287.96,175598.24,,135139040.57,86318004.19,,,3783667.91,3430147.52,21741769.35,-1124806.13,,,,,,,,,,,,84628035.02,24000.0,,,84652035.02,12342298.03,72309736.99,62974203.43,9335533.56,,72309736.99,62974203.43,9335533.56,74227163.74,,,,,20900477.98,196510.24,1330048.93,,,,,,,,,,,,,,,72309736.99,1
|
|
||||||
688334.SH,20250411,20250411,20250331,1,1,1,0.1989,0.1989,206756354.67,206756354.67,,,,,,,,,,,,,,,1741712.09,7534287.96,175598.24,,135139040.57,86318004.19,,,3783667.91,3430147.52,21741769.35,-1124806.13,,,,,,,,,,,,84628035.02,24000.0,,,84652035.02,12342298.03,72309736.99,62974203.43,9335533.56,,72309736.99,62974203.43,9335533.56,,,,,,20900477.98,196510.24,1330048.93,,,,,,,,,,,,,,,72309736.99,0
|
|
||||||
688334.SH,20250411,20250411,20241231,1,1,4,0.72,0.72,798360089.94,798360089.94,,,,,,,,,,,,,,,7980328.88,38163645.51,287443.13,,581055254.99,377454368.38,,,14204407.44,18886907.07,94111657.2,-7020855.88,-1681594.25,,,,,,,,,,,280724694.8,1270062.04,244915.45,,281749841.39,26871054.05,254878787.34,228674536.06,26204251.28,-610000.0,254268787.34,228064536.06,26204251.28,227786108.6,363605764.81,,,,84797929.32,208319.98,7986656.16,,,,,,,,,,,,,,,254878787.34,1
|
|
||||||
688334.SH,20250411,20250411,20241231,1,1,4,0.72,0.72,798360089.94,798360089.94,,,,,,,,,,,,,,,7980328.88,38163645.51,287443.13,,581055254.99,377454368.38,,,14204407.44,18886907.07,94111657.2,-7020855.88,-1681594.25,,,,,,,,,,,280724694.8,1270062.04,244915.45,,281749841.39,26871054.05,254878787.34,228674536.06,26204251.28,-610000.0,254268787.34,228064536.06,26204251.28,,,,,,84797929.32,208319.98,7986656.16,,,,,,,,,,,,,,,254878787.34,0
|
|
||||||
688334.SH,20241030,20241030,20240930,1,1,3,0.51,0.51,565786465.77,565786465.77,,,,,,,,,,,,,,,4673435.32,31057688.73,260943.05,,404218248.14,273758214.39,,,9914364.17,12235052.61,60542850.75,-6285116.49,1636733.99,,,,,,,,,,,209443030.21,1048057.74,14576.86,,210476511.09,33685327.76,176791183.33,162857549.03,13933634.3,250000.0,177041183.33,163107549.03,13933634.3,165607286.21,,,,,56382034.34,396109.0,6859792.03,,,,,,,,,,,,,,,176791183.33,1
|
|
||||||
688334.SH,20241030,20241030,20240930,1,1,3,0.51,0.51,565786465.77,565786465.77,,,,,,,,,,,,,,,4673435.32,31057688.73,260943.05,,404218248.14,273758214.39,,,9914364.17,12235052.61,60542850.75,-6285116.49,1636733.99,,,,,,,,,,,209443030.21,1048057.74,14576.86,,210476511.09,33685327.76,176791183.33,162857549.03,13933634.3,250000.0,177041183.33,163107549.03,13933634.3,,,,,,56382034.34,396109.0,6859792.03,,,,,,,,,,,,,,,176791183.33,0
|
|
||||||
688334.SH,20240830,20240830,20240630,1,1,2,0.31,0.31,313832249.43,313832249.43,,,,,,,,,,,,,,,3258111.11,21824714.54,260943.05,,234433096.41,153688348.11,,,5365155.75,7042121.06,37367982.95,-4530314.44,-368713.39,,,,,,,,,,,111750468.72,1047057.73,139443.93,,112658082.52,13232881.24,99425201.28,99425201.28,,250000.0,99675201.28,99675201.28,,82555578.7,136977393.97,,,,35502260.82,281027.64,4971335.41,,,,,,,,,,,,,,,99425201.28,1
|
|
||||||
688334.SH,20240430,20240430,20240331,1,1,1,0.1472,0.1472,153057582.2,153057582.2,,,,,,,,,,,,,,,,11039341.1,130048.87,,113226855.56,74585449.43,,,2569587.04,3045904.37,16984416.67,-2195220.9,59836.03,,,,,,,,,,,54677559.74,24676.46,4743.75,,54697492.45,8101040.01,46596452.44,46596452.44,,,46596452.44,46596452.44,,41358347.63,,,,,18296634.98,52173.33,2349427.92,,,,,,,,,,,,,,,46596452.44,1
|
|
||||||
688334.SH,20240411,20240411,20231231,1,1,4,0.59,0.59,602066631.72,602066631.72,,,,,,,,,,,,,,,398267.15,31419549.3,-601145.13,,483744128.96,315047213.5,,,10789443.47,14174729.32,85920344.4,-8302986.15,-3510950.88,,,,,,,,,,,181771172.62,520851.55,56571.28,,182235452.89,19867507.72,162367945.17,162367945.17,,-70000.0,162297945.17,162297945.17,,142321580.33,254936529.47,,,,60926307.84,253980.0,9920161.99,,,,,,,,,,,,,,,162367945.17,1
|
|
||||||
688334.SH,20231028,20231028,20230930,1,1,3,0.47,0.47,437071257.98,437071257.98,,,,,,,,,,,,,,,398267.15,20226240.33,33884.07,,334458654.35,223931605.53,,,7765766.91,8070306.49,55233022.21,-4604805.06,-376072.97,,,,,,,,,,,139538496.66,515501.53,,,140053998.19,16005975.96,124048022.23,124048022.23,,-350000.0,123698022.23,123698022.23,,,,,,,44659596.79,191100.0,5412759.16,,,,,,,,,,,,,,,124048022.23,0
|
|
||||||
688334.SH,20231028,20231028,20230930,1,1,3,0.47,0.47,437071257.98,437071257.98,,,,,,,,,,,,,,,398267.15,20226240.33,33884.07,,334458654.35,223931605.53,,,7765766.91,8070306.49,55233022.21,-4604805.06,-376072.97,,,,,,,,,,,139538496.66,515501.53,,,140053998.19,16005975.96,124048022.23,124048022.23,,-350000.0,123698022.23,123698022.23,,114685257.09,,,,,44659596.79,191100.0,5412759.16,,,,,,,,,,,,,,,124048022.23,1
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,0.34,0.34,277312590.06,277312590.06,,,,,,,,,,,,,,,398267.15,12481130.36,44871.7,,210102204.79,145168829.95,,,5228330.18,5163089.07,37711180.59,-1880533.56,-213075.71,,,,,,,,,,,91214859.97,512351.38,,,91727211.35,10670339.05,81056872.3,81056872.3,,-350000.0,80706872.3,80706872.3,,,,,,,19443041.31,126700.0,2487779.07,,,,,,,,,,,,,,,81056872.3,0
|
|
||||||
688334.SH,20230830,20230830,20230630,1,1,2,0.34,0.34,277312590.06,277312590.06,,,,,,,,,,,,,,,398267.15,12481130.36,44871.7,,210102204.79,145168829.95,,,5228330.18,5163089.07,37711180.59,-1880533.56,-213075.71,,,,,,,,,,,91214859.97,512351.38,,,91727211.35,10670339.05,81056872.3,81056872.3,,-350000.0,80706872.3,80706872.3,,76780923.39,133105068.02,,,,19443041.31,126700.0,2487779.07,,,,,,,,,,,,,,,81056872.3,1
|
|
||||||
688334.SH,20230530,20230530,20230331,1,1,1,0.15,0.15,135646091.08,135646091.08,,,,,,,,,,,,,,,,5764109.65,182536.14,,106763339.97,76951676.21,,,2652693.06,2352259.65,16747308.62,-1061709.54,,,,,,,,,,,,40762387.2,217001.02,,,40979388.22,6152340.85,34827047.37,34827047.37,,,34827047.37,34827047.37,,,,,,,9091504.35,63000.0,1282156.81,,,,,,,,,,,,,,,34827047.37,1
|
|
||||||
688334.SH,20230530,20230530,20221231,1,1,4,0.55,0.55,521120917.43,521120917.43,,,,,,,,,,,,,,,,15317939.81,-2393515.42,,416977429.03,270026666.32,,,10421990.25,11808796.4,79657756.31,-6134873.57,-434760.93,,,,,,,,,,,147749365.67,1133133.55,8049587.53,,140832911.69,10475625.39,130357286.3,130357286.3,,930000.0,131287286.3,131287286.3,,127300297.19,247396511.95,,,,49793583.24,300213.36,7483362.4,,,,,,,,,,,,,,,130357286.3,1
|
|
||||||
688334.SH,20230530,20230530,20211231,1,1,4,0.52,0.52,447149196.35,447149196.35,,,,,,,,,,,,,,,,-4021171.88,-5756727.44,,373055338.85,271356072.45,,,8584782.3,7121786.29,63408541.26,-2889222.82,320791.32,,,,,,,,,,,92793119.41,3389741.68,1361675.52,,94821185.57,13262667.94,81558517.63,81558517.63,,-850000.0,80708517.63,80708517.63,,95495484.97,206073933.41,,,,34636043.94,346446.59,3502102.36,,,,,,,,,,,,,,,81558517.63,1
|
|
||||||
688334.SH,20230530,20230530,20201231,1,1,4,,,344720148.09,344720148.09,,,,,,,,,,,,,,,,-4214541.74,-4214541.74,,286830815.37,193223026.04,,,5620891.98,6846460.56,57521633.59,-2338529.26,-186316.54,,,,,,,,,,,74070416.85,1957692.85,,,76028109.7,10908226.2,65119883.5,65119883.5,,100000.0,65219883.5,65219883.5,,76288325.71,170135448.55,,,,26414701.36,392679.97,2782635.98,,,,,,,,,,,,,,,65119883.5,1
|
|
||||||
688334.SH,20220630,20220630,20191231,1,1,4,,,399943120.3,399943120.3,,,,,,,,,,,,,,,,,,,310126801.69,224560843.62,,,2368448.89,6549725.99,57063243.97,-1301053.88,153634.21,,,,,,,,,,,109114799.65,2399846.81,405076.76,,111109569.7,16095540.67,95014029.03,95014029.03,,530000.0,95544029.03,95544029.03,,107628099.18,189228852.55,,,,24286843.88,438913.33,2049710.96,,,,,,,,,,,,,,,95014029.03,1
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,trade_date,close,turnover_rate,turnover_rate_f,volume_ratio,pe,pe_ttm,pb,ps,ps_ttm,dv_ratio,dv_ttm,total_share,float_share,free_share,total_mv,circ_mv
|
|
||||||
688334.SH,20251231,19.36,0.9076,1.4243,0.73,26.8022,23.2755,2.1444,7.677,6.9371,,,31657.9466,15690.4698,9998.6609,612897.8462,303767.4953
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
688334.SH,20251022,20250930,11192
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
name,list_date
|
|
||||||
西高院,20230619
|
|
||||||
|
@ -1,445 +0,0 @@
|
|||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>688334.SH Financial Report</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f6fa;
|
|
||||||
--card-bg: #ffffff;
|
|
||||||
--header-bg: #f7f8fb;
|
|
||||||
--section-bg: #f0f2f5;
|
|
||||||
--border: #e5e7eb;
|
|
||||||
--text-primary: #111827;
|
|
||||||
--text-secondary: #6b7280;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 32px;
|
|
||||||
background: var(--bg);
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
color: var(--text-primary);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-container {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 32px 40px;
|
|
||||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 24px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: var(--card-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-align: right;
|
|
||||||
background: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:first-child,
|
|
||||||
td:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.company-table th,
|
|
||||||
.company-table td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
background: var(--card-bg);
|
|
||||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th:first-child {
|
|
||||||
left: 0;
|
|
||||||
z-index: 4;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table th:first-child,
|
|
||||||
.metrics-table td:first-child {
|
|
||||||
width: 180px;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
background: var(--card-bg);
|
|
||||||
font-weight: 600;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.04);
|
|
||||||
z-index: 2;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:not(:first-child) {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td:first-child {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody tr:hover td {
|
|
||||||
background: #f4efff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-row td {
|
|
||||||
background: #eef1f6;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-row td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-label {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-spacer {
|
|
||||||
background: #eef1f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-name {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container table {
|
|
||||||
margin-bottom: 0;
|
|
||||||
min-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-gap {
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data {
|
|
||||||
margin-top: 24px;
|
|
||||||
padding: 32px;
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-green { background-color: #e6f7eb !important; }
|
|
||||||
.bg-red { background-color: #ffeef0 !important; }
|
|
||||||
.font-red { color: #d32f2f !important; }
|
|
||||||
.font-green { color: #1b873f !important; }
|
|
||||||
.font-blue { color: #2563eb !important; }
|
|
||||||
.italic { font-style: italic !important; }
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body { padding: 16px; }
|
|
||||||
.report-container { padding: 24px; }
|
|
||||||
table { font-size: 0.85rem; }
|
|
||||||
th,
|
|
||||||
td { padding: 10px 12px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="report-container">
|
|
||||||
<h1>西高院 (688334.SH) - Financial Report</h1>
|
|
||||||
<p><em>Report generated on: 2026-01-03</em></p>
|
|
||||||
|
|
||||||
<table class="company-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>代码</th>
|
|
||||||
<th>简称</th>
|
|
||||||
<th>上市日期</th>
|
|
||||||
<th>PE</th>
|
|
||||||
<th>PB</th>
|
|
||||||
<th>股息率(%)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>688334.SH</td>
|
|
||||||
<td>西高院</td>
|
|
||||||
<td>2023-06-19</td>
|
|
||||||
<td>26.80</td>
|
|
||||||
<td>2.14</td>
|
|
||||||
<td>0.00%</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="table-gap"></div>
|
|
||||||
|
|
||||||
<table class="metrics-table" data-table="metrics" data-scrollable="true">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>指标</th>
|
|
||||||
<th>2025Q3</th><th>2024A</th><th>2023A</th><th>2022A</th><th>2021A</th><th>2020A</th><th>2019A</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="section-row"><td class="section-label">主要指标</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">ROE</td><td>6.91%</td><td>8.23%</td><td>5.39%</td><td>7.04%</td><td>4.74%</td><td>9.54%</td><td>18.05%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROA</td><td>5.36%</td><td>6.45%</td><td>4.73%</td><td>5.78%</td><td>3.76%</td><td>5.10%</td><td>9.45%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROCE/ROIC</td><td>7.86%</td><td>8.18%</td><td>4.71%</td><td>6.85%</td><td>5.53%</td><td>11.12%</td><td>20.30%</td></tr>
|
|
||||||
<tr><td class="metric-name">毛利率</td><td>55.09%</td><td>52.72%</td><td>47.67%</td><td>48.18%</td><td>39.31%</td><td>43.95%</td><td>43.85%</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润率</td><td>30.34%</td><td>28.64%</td><td>26.97%</td><td>25.01%</td><td>18.24%</td><td>18.89%</td><td>23.76%</td></tr>
|
|
||||||
<tr><td class="metric-name">收入(亿)</td><td>6.51</td><td>7.98</td><td>6.02</td><td>5.21</td><td>4.47</td><td>3.45</td><td>4.00</td></tr>
|
|
||||||
<tr><td class="metric-name">收入增速</td><td>15.05%</td><td>32.60%</td><td>15.53%</td><td>16.54%</td><td>29.71%</td><td>-13.81%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润(亿)</td><td>1.98</td><td>2.29</td><td>1.62</td><td>1.30</td><td>0.82</td><td>0.65</td><td>0.95</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润增速</td><td>21.28%</td><td>40.84%</td><td>24.56%</td><td>59.83%</td><td>25.24%</td><td>-31.46%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">经营净现金流(亿)</td><td>3.53</td><td>4.82</td><td>2.63</td><td>1.97</td><td>1.54</td><td>1.36</td><td>1.32</td></tr>
|
|
||||||
<tr><td class="metric-name">资本开支(亿)</td><td>0.98</td><td>1.43</td><td>0.75</td><td>0.79</td><td>0.59</td><td>0.69</td><td>0.48</td></tr>
|
|
||||||
<tr><td class="metric-name">自由现金流(亿)</td><td>2.55</td><td>3.39</td><td>1.88</td><td>1.18</td><td>0.95</td><td>0.66</td><td>0.83</td></tr>
|
|
||||||
<tr><td class="metric-name">分红(亿)</td><td>-</td><td>1.26</td><td>0.81</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">回购(亿)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产(亿)</td><td>36.81</td><td>35.48</td><td>34.36</td><td>22.55</td><td>21.72</td><td>12.78</td><td>10.06</td></tr>
|
|
||||||
<tr><td class="metric-name">净资产(亿)</td><td>28.58</td><td>27.78</td><td>30.14</td><td>18.51</td><td>17.19</td><td>6.82</td><td>5.26</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉(亿)</td><td>0.24</td><td>0.24</td><td>0.24</td><td>0.24</td><td>0.26</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">费用指标</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">销售费用率</td><td>1.87%</td><td>2.37%</td><td>2.35%</td><td>2.27%</td><td>1.59%</td><td>1.99%</td><td>1.64%</td></tr>
|
|
||||||
<tr><td class="metric-name">管理费用率</td><td>10.35%</td><td>11.79%</td><td>14.27%</td><td>15.29%</td><td>14.18%</td><td>16.69%</td><td>14.27%</td></tr>
|
|
||||||
<tr><td class="metric-name">SG&A比例</td><td>12.22%</td><td>14.15%</td><td>16.63%</td><td>17.55%</td><td>15.77%</td><td>18.67%</td><td>15.91%</td></tr>
|
|
||||||
<tr><td class="metric-name">研发费用率</td><td>7.91%</td><td>10.62%</td><td>10.12%</td><td>9.56%</td><td>7.75%</td><td>7.66%</td><td>6.07%</td></tr>
|
|
||||||
<tr><td class="metric-name">其他费用率</td><td>4.62%</td><td>-0.70%</td><td>-6.04%</td><td>-3.94%</td><td>-2.44%</td><td>-1.28%</td><td>-1.88%</td></tr>
|
|
||||||
<tr><td class="metric-name">折旧费用占比</td><td>-</td><td>15.47%</td><td>16.90%</td><td>21.16%</td><td>23.19%</td><td>26.46%</td><td>20.07%</td></tr>
|
|
||||||
<tr><td class="metric-name">所得税率</td><td>14.78%</td><td>9.54%</td><td>10.90%</td><td>7.44%</td><td>13.99%</td><td>14.35%</td><td>14.49%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">资产占比</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">现金占比</td><td>26.03%</td><td>29.72%</td><td>25.14%</td><td>12.70%</td><td>20.97%</td><td>14.62%</td><td>22.31%</td></tr>
|
|
||||||
<tr><td class="metric-name">库存占比</td><td>1.52%</td><td>1.46%</td><td>1.57%</td><td>3.51%</td><td>3.43%</td><td>7.21%</td><td>6.39%</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款占比</td><td>3.34%</td><td>2.74%</td><td>1.04%</td><td>2.56%</td><td>3.46%</td><td>4.14%</td><td>4.45%</td></tr>
|
|
||||||
<tr><td class="metric-name">预付款占比</td><td>0.29%</td><td>0.19%</td><td>0.14%</td><td>0.94%</td><td>0.47%</td><td>0.49%</td><td>0.35%</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产占比</td><td>-</td><td>30.55%</td><td>24.03%</td><td>38.67%</td><td>42.10%</td><td>57.06%</td><td>56.15%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期投资占比</td><td>0.91%</td><td>0.94%</td><td>0.96%</td><td>1.49%</td><td>1.66%</td><td>3.27%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉占比</td><td>0.64%</td><td>0.67%</td><td>0.69%</td><td>1.08%</td><td>1.18%</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="other-assets-row"><td class="metric-name">其他资产占比</td><td>67.27%</td><td>33.74%</td><td>46.43%</td><td>39.05%</td><td>26.73%</td><td>13.21%</td><td>10.36%</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款占比</td><td>2.00%</td><td>3.51%</td><td>1.12%</td><td>1.97%</td><td>1.82%</td><td>2.90%</td><td>7.02%</td></tr>
|
|
||||||
<tr><td class="metric-name">预收款占比</td><td>7.97%</td><td>7.96%</td><td>5.54%</td><td>7.20%</td><td>7.46%</td><td>13.49%</td><td>12.66%</td></tr>
|
|
||||||
<tr><td class="metric-name">短期借款占比</td><td>0.13%</td><td>0.21%</td><td>0.22%</td><td>0.31%</td><td>0.31%</td><td>0.30%</td><td>0.38%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期借款占比</td><td>0.91%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">运营资产占比</td><td>-4.82%</td><td>-7.08%</td><td>-3.91%</td><td>-2.17%</td><td>-1.92%</td><td>-4.55%</td><td>-8.49%</td></tr>
|
|
||||||
<tr><td class="metric-name">有息负债率</td><td>1.05%</td><td>0.21%</td><td>0.22%</td><td>0.31%</td><td>0.31%</td><td>0.30%</td><td>0.38%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">周转能力</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">存货周转天数</td><td>69</td><td>50</td><td>62</td><td>107</td><td>100</td><td>174</td><td>104</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款周转天数</td><td>68</td><td>44</td><td>21</td><td>40</td><td>61</td><td>55</td><td>40</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款周转天数</td><td>92</td><td>120</td><td>44</td><td>60</td><td>53</td><td>70</td><td>114</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产周转率</td><td>-</td><td>0.74</td><td>0.73</td><td>0.60</td><td>0.49</td><td>0.47</td><td>0.71</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产周转率</td><td>0.18</td><td>0.23</td><td>0.18</td><td>0.23</td><td>0.21</td><td>0.27</td><td>0.40</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">人均效率</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">员工人数</td><td>-</td><td>700</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创收(万)</td><td>-</td><td>114.05</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创利(万)</td><td>-</td><td>32.67</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均薪酬(万)</td><td>-</td><td>31.98</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">市场表现</td><td class="section-spacer" colspan="7"></td></tr>
|
|
||||||
<tr><td class="metric-name">股价</td><td>19.36</td><td>16.33</td><td>17.33</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">市值(亿)</td><td>61.29</td><td>51.70</td><td>54.86</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PE</td><td>26.80</td><td>31.84</td><td>42.09</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PB</td><td>2.14</td><td>1.88</td><td>1.84</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">股东户数</td><td>11,192</td><td>12,364</td><td>15,965</td><td>7</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const scrollableTables = document.querySelectorAll('table[data-scrollable="true"]');
|
|
||||||
scrollableTables.forEach(table => {
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'table-container';
|
|
||||||
table.parentNode.insertBefore(container, table);
|
|
||||||
container.appendChild(table);
|
|
||||||
});
|
|
||||||
|
|
||||||
const parseValue = (text) => {
|
|
||||||
if (!text || text.trim() === '-') return null;
|
|
||||||
return parseFloat(text.replace(/%|,/g, ''));
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightIfOverThirtyPercent = (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 30) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleRules = {
|
|
||||||
'ROE': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 15) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'ROA': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 10) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'毛利率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 50) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'净利润率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 20) {
|
|
||||||
cell.classList.add('bg-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'收入增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'净利润增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'经营净现金流(亿)': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value < 0) cell.classList.add('bg-red', 'font-red');
|
|
||||||
},
|
|
||||||
'应收款周转天数': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 90) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'现金占比': highlightIfOverThirtyPercent,
|
|
||||||
'库存占比': highlightIfOverThirtyPercent,
|
|
||||||
'应收款占比': highlightIfOverThirtyPercent,
|
|
||||||
'预付款占比': highlightIfOverThirtyPercent,
|
|
||||||
'固定资产占比': highlightIfOverThirtyPercent,
|
|
||||||
'长期投资占比': highlightIfOverThirtyPercent,
|
|
||||||
'商誉占比': highlightIfOverThirtyPercent,
|
|
||||||
'其他资产占比': highlightIfOverThirtyPercent
|
|
||||||
};
|
|
||||||
|
|
||||||
const metricsTables = document.querySelectorAll('table[data-table="metrics"]');
|
|
||||||
metricsTables.forEach(table => {
|
|
||||||
let netProfitValues = [];
|
|
||||||
let fcfRow = null;
|
|
||||||
const rows = table.querySelectorAll('tbody tr');
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
if (metricName === '净利润(亿)') {
|
|
||||||
row.querySelectorAll('td:not(:first-child)').forEach(cell => {
|
|
||||||
netProfitValues.push(parseValue(cell.textContent));
|
|
||||||
});
|
|
||||||
} else if (metricName === '自由现金流(亿)') {
|
|
||||||
fcfRow = row;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
const cells = row.querySelectorAll('td:not(:first-child)');
|
|
||||||
if (styleRules[metricName]) {
|
|
||||||
cells.forEach(cell => {
|
|
||||||
styleRules[metricName](cell);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (row === fcfRow && netProfitValues.length > 0) {
|
|
||||||
cells.forEach((cell, index) => {
|
|
||||||
const fcfValue = parseValue(cell.textContent);
|
|
||||||
const netProfitValue = netProfitValues[index];
|
|
||||||
if (fcfValue !== null) {
|
|
||||||
if (fcfValue < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else if (netProfitValue !== null && fcfValue > netProfitValue) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# 西高院 (688334.SH) - Financial Report
|
|
||||||
*Report generated on: 2026-01-03*
|
|
||||||
|
|
||||||
| 代码 | 简称 | 上市日期 | PE | PB | 股息率(%) |
|
|
||||||
|:---|:---|:---|:---|:---|:---|
|
|
||||||
| 688334.SH | 西高院 | 2023-06-19 | 26.80 | 2.14 | 0.00% |
|
|
||||||
|
|
||||||
|
|
||||||
## 主要指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| ROE | 6.91% | 8.23% | 5.39% | 7.04% | 4.74% | 9.54% | 18.05% |
|
|
||||||
| ROA | 5.36% | 6.45% | 4.73% | 5.78% | 3.76% | 5.10% | 9.45% |
|
|
||||||
| ROCE/ROIC | 7.86% | 8.18% | 4.71% | 6.85% | 5.53% | 11.12% | 20.30% |
|
|
||||||
| 毛利率 | 55.09% | 52.72% | 47.67% | 48.18% | 39.31% | 43.95% | 43.85% |
|
|
||||||
| 净利润率 | 30.34% | 28.64% | 26.97% | 25.01% | 18.24% | 18.89% | 23.76% |
|
|
||||||
| 收入(亿) | 6.51 | 7.98 | 6.02 | 5.21 | 4.47 | 3.45 | 4.00 |
|
|
||||||
| 收入增速 | 15.05% | 32.60% | 15.53% | 16.54% | 29.71% | -13.81% | - |
|
|
||||||
| 净利润(亿) | 1.98 | 2.29 | 1.62 | 1.30 | 0.82 | 0.65 | 0.95 |
|
|
||||||
| 净利润增速 | 21.28% | 40.84% | 24.56% | 59.83% | 25.24% | -31.46% | - |
|
|
||||||
| 经营净现金流(亿) | 3.53 | 4.82 | 2.63 | 1.97 | 1.54 | 1.36 | 1.32 |
|
|
||||||
| 资本开支(亿) | 0.98 | 1.43 | 0.75 | 0.79 | 0.59 | 0.69 | 0.48 |
|
|
||||||
| 自由现金流(亿) | 2.55 | 3.39 | 1.88 | 1.18 | 0.95 | 0.66 | 0.83 |
|
|
||||||
| 分红(亿) | - | 1.26 | 0.81 | - | - | - | - |
|
|
||||||
| 回购(亿) | - | - | - | - | - | - | - |
|
|
||||||
| 总资产(亿) | 36.81 | 35.48 | 34.36 | 22.55 | 21.72 | 12.78 | 10.06 |
|
|
||||||
| 净资产(亿) | 28.58 | 27.78 | 30.14 | 18.51 | 17.19 | 6.82 | 5.26 |
|
|
||||||
| 商誉(亿) | 0.24 | 0.24 | 0.24 | 0.24 | 0.26 | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 费用指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 销售费用率 | 1.87% | 2.37% | 2.35% | 2.27% | 1.59% | 1.99% | 1.64% |
|
|
||||||
| 管理费用率 | 10.35% | 11.79% | 14.27% | 15.29% | 14.18% | 16.69% | 14.27% |
|
|
||||||
| SG&A比例 | 12.22% | 14.15% | 16.63% | 17.55% | 15.77% | 18.67% | 15.91% |
|
|
||||||
| 研发费用率 | 7.91% | 10.62% | 10.12% | 9.56% | 7.75% | 7.66% | 6.07% |
|
|
||||||
| 其他费用率 | 4.62% | -0.70% | -6.04% | -3.94% | -2.44% | -1.28% | -1.88% |
|
|
||||||
| 折旧费用占比 | - | 15.47% | 16.90% | 21.16% | 23.19% | 26.46% | 20.07% |
|
|
||||||
| 所得税率 | 14.78% | 9.54% | 10.90% | 7.44% | 13.99% | 14.35% | 14.49% |
|
|
||||||
|
|
||||||
|
|
||||||
## 资产占比
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 现金占比 | 26.03% | 29.72% | 25.14% | 12.70% | 20.97% | 14.62% | 22.31% |
|
|
||||||
| 库存占比 | 1.52% | 1.46% | 1.57% | 3.51% | 3.43% | 7.21% | 6.39% |
|
|
||||||
| 应收款占比 | 3.34% | 2.74% | 1.04% | 2.56% | 3.46% | 4.14% | 4.45% |
|
|
||||||
| 预付款占比 | 0.29% | 0.19% | 0.14% | 0.94% | 0.47% | 0.49% | 0.35% |
|
|
||||||
| 固定资产占比 | - | 30.55% | 24.03% | 38.67% | 42.10% | 57.06% | 56.15% |
|
|
||||||
| 长期投资占比 | 0.91% | 0.94% | 0.96% | 1.49% | 1.66% | 3.27% | - |
|
|
||||||
| 商誉占比 | 0.64% | 0.67% | 0.69% | 1.08% | 1.18% | - | - |
|
|
||||||
| 其他资产占比 | 67.27% | 33.74% | 46.43% | 39.05% | 26.73% | 13.21% | 10.36% |
|
|
||||||
| 应付款占比 | 2.00% | 3.51% | 1.12% | 1.97% | 1.82% | 2.90% | 7.02% |
|
|
||||||
| 预收款占比 | 7.97% | 7.96% | 5.54% | 7.20% | 7.46% | 13.49% | 12.66% |
|
|
||||||
| 短期借款占比 | 0.13% | 0.21% | 0.22% | 0.31% | 0.31% | 0.30% | 0.38% |
|
|
||||||
| 长期借款占比 | 0.91% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
|
|
||||||
| 运营资产占比 | -4.82% | -7.08% | -3.91% | -2.17% | -1.92% | -4.55% | -8.49% |
|
|
||||||
| 有息负债率 | 1.05% | 0.21% | 0.22% | 0.31% | 0.31% | 0.30% | 0.38% |
|
|
||||||
|
|
||||||
|
|
||||||
## 周转能力
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 存货周转天数 | 69 | 50 | 62 | 107 | 100 | 174 | 104 |
|
|
||||||
| 应收款周转天数 | 68 | 44 | 21 | 40 | 61 | 55 | 40 |
|
|
||||||
| 应付款周转天数 | 92 | 120 | 44 | 60 | 53 | 70 | 114 |
|
|
||||||
| 固定资产周转率 | - | 0.74 | 0.73 | 0.60 | 0.49 | 0.47 | 0.71 |
|
|
||||||
| 总资产周转率 | 0.18 | 0.23 | 0.18 | 0.23 | 0.21 | 0.27 | 0.40 |
|
|
||||||
|
|
||||||
|
|
||||||
## 人均效率
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 员工人数 | - | 700 | - | - | - | - | - |
|
|
||||||
| 人均创收(万) | - | 114.05 | - | - | - | - | - |
|
|
||||||
| 人均创利(万) | - | 32.67 | - | - | - | - | - |
|
|
||||||
| 人均薪酬(万) | - | 31.98 | - | - | - | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 市场表现
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 股价 | 19.36 | 16.33 | 17.33 | - | - | - | - |
|
|
||||||
| 市值(亿) | 61.29 | 51.70 | 54.86 | - | - | - | - |
|
|
||||||
| PE | 26.80 | 31.84 | 42.09 | - | - | - | - |
|
|
||||||
| PB | 2.14 | 1.88 | 1.84 | - | - | - | - |
|
|
||||||
| 股东户数 | 11,192 | 12,364 | 15,965 | 7 | - | - | - |
|
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
date_str,Price,PE,PB,MarketCap,Shareholders
|
|
||||||
20250930,83.9,85.7029,4.8332,42343581864.0,14720.0
|
|
||||||
20241231,45.64,36.4088,2.2251,19203988486.0,14740.0
|
|
||||||
20240930,36.74,29.3089,1.8186,15459126577.000002,13770.0
|
|
||||||
20231231,39.64,14.885,1.9711,16679362480.0,13732.0
|
|
||||||
20221231,77.68,42.0398,2.934,23346779541.000004,14462.0
|
|
||||||
20211231,103.35,103.7733,7.2703,25999993794.0,15688.0
|
|
||||||
20201231,,,,,
|
|
||||||
20191231,,,,,
|
|
||||||
20181231,,,,,
|
|
||||||
20171231,,,,,
|
|
||||||
20161231,,,,,
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,total_share,cap_rese,undistr_porfit,surplus_rese,special_rese,money_cap,trad_asset,notes_receiv,accounts_receiv,oth_receiv,prepayment,div_receiv,int_receiv,inventories,amor_exp,nca_within_1y,sett_rsrv,loanto_oth_bank_fi,premium_receiv,reinsur_receiv,reinsur_res_receiv,pur_resale_fa,oth_cur_assets,total_cur_assets,fa_avail_for_sale,htm_invest,lt_eqt_invest,invest_real_estate,time_deposits,oth_assets,lt_rec,fix_assets,cip,const_materials,fixed_assets_disp,produc_bio_assets,oil_and_gas_assets,intan_assets,r_and_d,goodwill,lt_amor_exp,defer_tax_assets,decr_in_disbur,oth_nca,total_nca,cash_reser_cb,depos_in_oth_bfi,prec_metals,deriv_assets,rr_reins_une_prem,rr_reins_outstd_cla,rr_reins_lins_liab,rr_reins_lthins_liab,refund_depos,ph_pledge_loans,refund_cap_depos,indep_acct_assets,client_depos,client_prov,transac_seat_fee,invest_as_receiv,total_assets,lt_borr,st_borr,cb_borr,depos_ib_deposits,loan_oth_bank,trading_fl,notes_payable,acct_payable,adv_receipts,sold_for_repur_fa,comm_payable,payroll_payable,taxes_payable,int_payable,div_payable,oth_payable,acc_exp,deferred_inc,st_bonds_payable,payable_to_reinsurer,rsrv_insur_cont,acting_trading_sec,acting_uw_sec,non_cur_liab_due_1y,oth_cur_liab,total_cur_liab,bond_payable,lt_payable,specific_payables,estimated_liab,defer_tax_liab,defer_inc_non_cur_liab,oth_ncl,total_ncl,depos_oth_bfi,deriv_liab,depos,agency_bus_liab,oth_liab,prem_receiv_adva,depos_received,ph_invest,reser_une_prem,reser_outstd_claims,reser_lins_liab,reser_lthins_liab,indept_acc_liab,pledge_borr,indem_payable,policy_div_payable,total_liab,treasury_share,ordin_risk_reser,forex_differ,invest_loss_unconf,minority_int,total_hldr_eqy_exc_min_int,total_hldr_eqy_inc_min_int,total_liab_hldr_eqy,lt_payroll_payable,oth_comp_income,oth_eqt_tools,oth_eqt_tools_p_shr,lending_funds,acc_receivable,st_fin_payable,payables,hfs_assets,hfs_sales,cost_fin_assets,fair_value_fin_assets,contract_assets,contract_liab,accounts_receiv_bill,accounts_pay,oth_rcv_total,fix_assets_total,cip_total,oth_pay_total,long_pay_total,debt_invest,oth_debt_invest,update_flag
|
|
||||||
688778.SH,20251025,20251025,20250930,1,1,3,504691083.0,5818208533.03,2479844878.66,214820118.68,12282305.61,1545793268.02,500442636.26,1839327.09,3274558318.21,,130703889.23,,,4569106828.6,,,,,,,,,355007697.24,11039334912.82,,,415510546.21,,,,,,,,,,,370513677.49,,,44411168.29,220019183.01,,16911220.86,6373569230.97,,,,,,,,,,,,,,,,,17412904143.79,447616071.43,120400122.89,,,,,3665057664.16,3066752513.67,,,,55164809.04,98888075.08,,,,,,,,,,,64654828.5,20669849.14,7304476725.81,,,,,4384868.99,224181221.79,,681175461.69,,,,,,,,,,,,,,,,,7985652187.5,40681250.74,,,,418377886.29,9008874070.0,9427251956.29,17412904143.79,,19708401.76,,,,,,,,,,,,153327226.04,3276397645.3,6731810177.83,15278233.65,4073431901.54,1223761602.64,59561637.29,,,,0
|
|
||||||
688778.SH,20250821,20250821,20250630,1,1,2,420771001.0,5980998615.03,2254580025.92,214820118.68,10986948.86,1925619331.91,452848488.37,862810.22,2653122909.26,13857820.73,29731089.94,,,3406881668.77,,,,,,,,,331675486.73,9590168002.06,,,415470604.91,,,,,4160461453.53,1024036414.83,1521025.67,,,,373670278.51,,,48384794.99,205801152.05,,26518522.99,6262709682.38,,,,,,,,,,,,,,,,,15852877684.44,462823571.43,1000555.56,,,,,2632467734.77,2587599845.49,,,,37008036.65,73624358.13,0.0,167840164.8,177335582.28,,,,,,,,122969832.77,8200676.86,5865761534.39,,15051000.0,0.0,,4841118.48,225708875.21,,711016587.65,,,,,,,,,,,,,,,,,6576778122.04,40681250.74,,,,414332884.58,8861766677.82,9276099562.4,15852877684.44,,20291219.07,,,,,,,,,,,,57714747.08,2653985719.48,5220067580.26,13857820.73,4160461453.53,1025557440.5,345175747.08,15051000.0,,,0
|
|
||||||
688778.SH,20250426,20250426,20250331,1,1,1,420771001.0,6021816631.03,2240482843.24,214820118.68,9689859.87,1707849630.67,496376102.55,947690.59,1809824299.93,,8768184.65,,,2542453622.12,,,,,,,,,232860256.56,8423965478.58,,,415977451.35,,,,,,,,,,,365729961.7,,,10418654.65,169439229.74,,22718264.2,6136492636.01,,,,,,,,,,,,,,,,,14560458114.59,506008571.43,51015472.22,,,,,2366407210.72,1736793518.57,,,,19501146.6,39430771.84,,,,,,,,,,,98350032.57,29607629.45,4615008442.36,,,,,4473686.47,226952588.46,,755140858.02,,,,,,,,,,,,,,,,,5370149300.38,40681250.74,,,,326391709.65,8863917104.56,9190308814.21,14560458114.59,,-2982098.52,,,,,,,,,,,,220943898.1,1810771990.52,4103200729.29,7837927.77,3610087029.75,1533301175.73,52958762.29,15005500.0,,,0
|
|
||||||
688778.SH,20250426,20250426,20241231,1,1,4,420771001.0,6021816631.03,2123803846.04,214820118.68,6590712.99,1635067409.62,502771663.1,1195272.09,2347613108.04,6351202.73,11962195.59,,,2475618756.49,,,,,,,,,266851450.49,8571406980.55,,,416662417.57,,,,,3521133209.36,1668282052.68,4557771.37,,,,368656890.1,,,11786299.66,159606804.46,,14312989.12,6175794737.1,,,,,,,,,,,,,,,,,14747201717.65,466008571.43,135113287.0,,,,,2507864315.54,2158602215.76,,,,2083891.9,29878259.78,,,50188008.72,,,,,,,,100767693.29,1505170.56,4988619782.67,,15051000.0,0.0,,5563194.82,206843010.88,,696165327.24,,,,,,,,,,,,,,,,,5684785109.91,35686512.11,,,,325036212.13,8737380395.61,9062416607.74,14747201717.65,,-14735402.02,,,,,,,,,,,,2616940.12,2348808380.13,4666466531.3,6351202.73,3521133209.36,1672839824.05,50188008.72,15051000.0,,,0
|
|
||||||
688778.SH,20241026,20241026,20240930,1,1,3,420771001.0,6021798952.03,2012208604.84,199832907.64,10068766.81,1575690496.69,501121089.25,219480.0,2856712366.32,,10319732.67,,,2490601595.32,,,,,,,,,251842832.02,8627631043.92,,,400022531.92,,,,,,,,,,,371662761.09,,,13153944.67,140145132.64,,18549619.2,5984108197.64,,,,,,,,,,,,,,,,,14611739241.56,477808571.43,375258965.26,,,,,2431711657.85,2053239580.59,,,,53861753.51,28513417.24,,,,,,,,,,,94536142.76,3880350.22,5093967391.38,,,,,5558134.61,118401717.01,,632184028.57,,,,,,,,,,,,,,,,,5726151419.95,35686512.11,,,,255136815.67,8630451005.94,8885587821.61,14611739241.56,,1457285.73,,,,,,,,,,,,32054045.53,2856931846.32,4484951238.44,7343219.92,3433040248.22,1594762223.28,20911478.42,24008000.0,,,0
|
|
||||||
688778.SH,20240803,20240803,20240630,1,1,2,420771001.0,6021772433.53,1883807423.11,199832907.64,7580205.59,1745078933.9,460608386.58,2991201.81,2720076645.72,6602374.42,18230598.96,,,2531115018.13,,,,,,,,,285296221.94,8048971243.32,,,400637570.06,,,,,3523795961.19,1456687005.18,2021527.74,,,,371524116.23,,,14521589.67,140060389.38,,21526079.92,5945521409.8,,,,,,,,,,,,,,,,,13994492653.12,429808571.0,670445231.38,,,,,1685385560.02,2129124673.92,,,,35524893.5,28152239.11,,,28790370.09,,,,,,,,45634235.02,5157181.8,4645039378.61,,24054000.0,0.0,,5967980.05,123371606.98,,590972034.78,,,,,,,,,,,,,,,,,5236011413.39,30686900.84,,,,257818217.35,8500663022.38,8758481239.73,13994492653.12,,-2414047.65,,,,,,,,,,,,16824993.77,2723067847.53,3814510233.94,6602374.42,3523795961.19,1458708532.92,28790370.09,24054000.0,,,0
|
|
||||||
688778.SH,20240418,20240418,20240331,1,1,1,420771001.0,6021745915.03,2049921950.92,199832907.64,5177982.21,2275740582.93,500876430.82,,2893769412.77,,16115381.88,,,2078364225.01,,,,,,,,,200580185.86,8595404790.72,,,400755898.78,,,,,,,,,,,374519366.27,,,15889234.65,126804886.81,,14926708.33,5805701621.21,,,,,,,,,,,,,,,,,14401106411.93,760779999.58,815587998.1,,,,,1406075604.9,2178811908.46,,,,21352165.21,19329571.22,,,,,,,,,,,45089308.04,4733223.6,4556879306.42,,,,,6515006.29,123386496.95,,924497513.02,,,,,,,,,,,,,,,,,5481376819.44,30686900.84,,,,257393694.76,8662335897.73,8919729592.49,14401106411.93,,-4426958.23,,,,,,,,,,,,33670026.01,2893769412.77,3584887513.36,11471053.58,3410187410.45,1446324786.87,32229500.88,24008800.0,,,0
|
|
||||||
688778.SH,20240418,20240418,20231231,1,1,4,420771001.0,6021719396.53,1938633235.51,199832907.64,804629.39,1199576265.64,504162210.94,,3498587724.59,5769293.18,10075576.63,,,1963826719.94,,,,,,,,,176475707.88,7832748733.17,,,397211336.32,,,,,3499556801.18,1155352545.11,22698144.44,,,,377542166.79,,,17256879.63,125590126.18,,34889569.2,5648294785.75,,,,,,,,,,,,,,,,,13481043518.92,704659999.58,,,,,,1399871073.03,2274599472.5,,,,4525017.82,14386237.35,,,25636686.53,,,,,,,,33144082.03,13114504.06,3769581831.51,,24054300.0,0.0,,8172130.69,124477636.92,,872111628.59,,,,,,,,,,,,,,,,,4641693460.1,,,,,257787975.43,8581562083.39,8839350058.82,13481043518.92,,-199086.68,,,,,,,,,,,,4304758.19,3498587724.59,3674470545.53,5769293.18,3499556801.18,1178050689.55,25636686.53,24054300.0,,,1
|
|
||||||
688778.SH,20240418,20240418,20231231,1,1,4,420771001.0,6021719396.53,1938633235.51,199832907.64,804629.39,1199576265.64,504162210.94,,3498587724.59,5769293.18,10075576.63,,,1963826719.94,,,,,,,,,176475707.88,7832748733.17,,,397211336.32,,,,,3499556801.18,1155352545.11,22698144.44,,,,377542166.79,,,17256879.63,125590126.18,,34889569.2,5648294785.75,,,,,,,,,,,,,,,,,13481043518.92,704659999.58,,,,,,1399871073.03,2274599472.5,,,,4525017.82,14386237.35,,,25636686.53,,,,,,,,33144082.03,13114504.06,3769581831.51,,24054300.0,0.0,,8172130.69,124477636.92,,872111628.59,,,,,,,,,,,,,,,,,4641693460.1,,,,,257787975.43,8581562083.39,8839350058.82,13481043518.92,,-199086.68,,,,,,,,,,,,4304758.19,3498587724.59,3674470545.53,5769293.18,3499556801.18,1178050689.55,25636686.53,24054300.0,,,0
|
|
||||||
688778.SH,20231025,20231025,20230930,1,1,3,420771001.0,6021660466.54,1868696597.11,154709975.68,,1334892684.78,451014937.1,,3530900109.56,,77740591.6,,,2134257378.86,,,,,,,,,121639085.14,8534952133.7,,,399737910.46,,,,,,,,,,,333458007.05,,,7572011.58,113898110.65,,96203507.43,5351742851.11,,,,,,,,,,,,,,,,,13886694984.81,1103819090.86,50029166.67,,,,,820248680.43,2480723671.52,,,,38275773.38,77731416.82,,,,,,,,,,,375788341.59,16245211.98,3894934129.86,,,,,3090658.55,131347747.61,,1273514422.6,,,,,,,,,,,,,,,,,5168448552.46,,,,,256431441.01,8461814991.34,8718246432.35,13886694984.81,,-4023048.99,,,,,,,,,,,,7814535.69,3530900109.56,3300972351.95,21771032.42,3467272141.06,916958863.04,28077331.78,24008000.0,,,0
|
|
||||||
688778.SH,20230825,20230825,20230630,1,1,2,420771001.0,6021601536.55,1710967174.89,154709975.68,,1597900433.09,201454664.57,,2987388341.95,21258146.22,39772945.39,,,1960109005.71,,,,,,,,,44360472.61,7875924190.64,,,400535887.11,,,,,3553312964.53,384767917.18,1162538.94,,,,336130016.01,,,8908249.62,103824860.97,,224221106.99,5026351337.09,,,,,,,,,,,,,,,,,12902275527.73,1501151405.57,,,,,,295981433.63,2031720276.28,,,,27885610.43,37020714.04,,,30168093.89,,,,,,,,239537917.18,13881292.69,2688589686.47,,24054000.0,0.0,,3230476.91,115320486.84,,1653049356.56,,,,,,,,,,,,,,,,,4341639043.03,,,,,256138870.58,8304497614.12,8560636484.7,12902275527.73,,-3552074.0,,,,,,,,,,,,12394348.33,2987388341.95,2327701709.91,21258146.22,3553312964.53,385930456.12,30168093.89,24054000.0,,,0
|
|
||||||
688778.SH,20230825,20230825,20230630,1,1,2,420771001.0,6021601536.55,1710967174.89,154709975.68,,1597900433.09,201454664.57,,2987388341.95,21258146.22,39772945.39,,,1960109005.71,,,,,,,,,44360472.61,7875924190.64,,,400535887.11,,,,,3553312964.53,384767917.18,1162538.94,,,,336130016.01,,,8908249.62,103824860.97,,224221106.99,5026351337.09,,,,,,,,,,,,,,,,,12902275527.73,1501151405.57,,,,,,295981433.63,2031720276.28,,,,27885610.43,37020714.04,,,30168093.89,,,,,,,,239537917.18,13881292.69,2688589686.47,,24054000.0,0.0,,3230476.91,115320486.84,,1653049356.56,,,,,,,,,,,,,,,,,4341639043.03,,,,,256138870.58,8304497614.12,8560636484.7,12902275527.73,,-3552074.0,,,,,,,,,,,,12394348.33,2987388341.95,2327701709.91,21258146.22,3553312964.53,385930456.12,30168093.89,24054000.0,,,1
|
|
||||||
688778.SH,20230422,20230422,20230331,1,1,1,300550715.0,6141762892.56,1722150085.25,154709975.68,,1580482702.21,300087805.56,,3039266760.95,,43286831.55,,,2771028896.03,,,,,,,,,26621468.78,8997505460.62,,,400909859.42,,,,,,,,,,,280367962.48,,,10244491.66,104818195.73,,77003350.59,4674203817.25,,,,,,,,,,,,,,,,,13671709277.87,1165804246.29,0.0,,,,,1057685550.04,2093879855.28,,,,20253611.29,88165196.59,,,,,,,,,,,581748338.58,13198672.55,3881989545.25,,,,,3370295.26,119821959.31,,1327371143.85,,,,,,,,,,,,,,,,,5209360689.1,,,,,150216133.25,8312132455.52,8462348588.77,13671709277.87,,-7041212.97,,,,,,,,,,,,4289999.49,3039266760.95,3151565405.32,10498623.19,3586978678.53,193481765.22,22768321.43,24008800.0,,,0
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,300550715.0,6141703962.57,1606576984.32,154709975.68,,1016518212.28,450225555.56,,4954899159.13,6117940.83,17145274.8,,,3351688644.71,,,,,,,,,65190158.73,11052268211.11,,,100264507.77,,,,,3637033016.57,177340923.55,2044274.04,,,,280225858.46,,,,105148736.62,,9520705.23,4328097105.81,,,,,,,,,,,,,,,,,15380365316.92,870785472.33,70057750.0,,,,,3038568961.1,2095600006.69,,,,5510765.63,96853300.33,,,23623245.07,,,,,,,,627113259.93,39336009.35,6002179181.29,,24054300.0,0.0,,3510113.61,119336271.79,,1028026698.17,,,,,,,,,,,,,,,,,7030205879.46,,,,,150616320.93,8199543116.53,8350159437.46,15380365316.92,,-3998521.04,,,,,,,,,,,,5515883.19,4954899159.13,5134168967.79,6117940.83,3637033016.57,179385197.59,23623245.07,24054300.0,,,1
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,300550715.0,6141703962.57,1606576984.32,154709975.68,,1016518212.28,450225555.56,,4954899159.13,6117940.83,17145274.8,,,3351688644.71,,,,,,,,,65190158.73,11052268211.11,,,100264507.77,,,,,3637033016.57,177340923.55,2044274.04,,,,280225858.46,,,,105148736.62,,9520705.23,4328097105.81,,,,,,,,,,,,,,,,,15380365316.92,870785472.33,70057750.0,,,,,3038568961.1,2095600006.69,,,,5510765.63,96853300.33,,,23623245.07,,,,,,,,627113259.93,39336009.35,6002179181.29,,24054300.0,0.0,,3510113.61,119336271.79,,1028026698.17,,,,,,,,,,,,,,,,,7030205879.46,,,,,150616320.93,8199543116.53,8350159437.46,15380365316.92,,-3998521.04,,,,,,,,,,,,5515883.19,4954899159.13,5134168967.79,6117940.83,3637033016.57,179385197.59,23623245.07,24054300.0,,,0
|
|
||||||
688778.SH,20221027,20221027,20220930,1,1,3,300550715.0,6185087323.97,1389990119.99,86447320.65,,2351453876.42,,,5073953535.1,,112551416.26,,,3714034719.4,,,,,,,,,101871929.46,12043107989.06,,,,,,,,,,,,,,265836531.66,,,,100162482.43,,30919090.07,4093445621.21,,,,,,,,,,,,,,,,,16136553610.27,1428072507.13,70052500.0,,,,,3603322999.67,2348868061.23,,,,32088069.27,104309459.74,,,,,,,,,,,193831766.39,47642521.6,6448527606.02,,,,,3649931.97,119377319.94,,1582430402.87,,,,,,,,,,,,,,,,,8030958008.89,,,,,148244549.24,7957351052.14,8105595601.38,16136553610.27,,-4724427.47,,,,,,,,,,,,21725775.98,5073953535.1,5952191060.9,15424019.56,3372393995.64,309960485.39,26686452.14,24008000.0,,,0
|
|
||||||
688778.SH,20220728,20220728,20220630,1,1,2,251572267.0,2740472177.12,1063438583.49,86447320.65,,712228108.61,,,4529376013.18,13110490.42,34145657.81,,,3560832200.78,,,,,,,,,173933995.77,9480020802.6,,,,,,,,3379939953.31,205035401.3,6443630.61,,,,240026250.67,,,,99671046.9,,22422124.48,3956497956.45,,,,,,,,,,,,,,,,,13436518759.05,1539492298.61,221255739.79,,,,,3441042930.79,3452596850.72,,,,23348040.85,72855709.38,,,30220087.67,,,,,,,,190636034.1,25847512.55,7462985434.39,,24054000.0,0.0,,3789750.32,120602784.94,,1688550777.33,,,,,,,,,,,,,,,,,9151536211.72,,,,,146095140.38,4138887406.95,4284982547.33,13436518759.05,,-3042941.31,,,,,,,,,,,,5182528.54,4529376013.18,6893639781.51,13110490.42,3379939953.31,211479031.91,30220087.67,24054000.0,,,0
|
|
||||||
688778.SH,20220427,20220427,20220331,1,1,1,251572267.0,2740345477.61,863714904.27,86447320.65,,1101069754.39,100542222.22,,3436873278.72,,50089551.2,,,3597928149.36,,,,,,,,,292908756.7,9049396562.79,,,,,,,,,,,,,,241406634.79,,,,84634501.16,,9379079.79,3931466576.56,,,,,,,,,,,,,,,,,12980863139.35,1762067980.56,252279643.85,,,,,2860307852.01,3522177792.5,,,,16500173.33,46037389.26,,,,,,,,,,,255172170.07,32859202.09,7026278156.39,,,,,3929568.67,115899122.44,,1907123524.78,,,,,,,,,,,,,,,,,8933401681.17,,,,,108255417.25,3939206040.93,4047461458.18,12980863139.35,,-2873928.6,,,,,,,,,,,,10624906.52,3436873278.72,6382485644.51,19602600.19,3041653212.69,550841689.11,30319026.76,24008800.0,,,0
|
|
||||||
688778.SH,20220331,20220331,20211231,1,1,4,251572267.0,2740218778.11,656816278.43,86447320.65,,425014387.51,200542222.22,,2953734709.32,17747849.68,16872654.29,,,2795347589.34,,,,,,,,,279581019.99,6799751280.56,,,,,,,,2796332676.46,473200177.8,40179437.26,,,,242333479.09,,,,85886312.47,,74618577.85,3716694029.79,,,,,,,,,,,,,,,,,10516445310.35,1383336129.18,6380208.52,,,,,1297720378.95,3484571286.14,,,,8728513.13,62796306.83,,,27153295.52,,,,,,,,254635446.17,38469299.5,5190947432.49,,24064300.0,0.0,,4069387.02,120001104.94,,1533289305.71,,,,,,,,,,,,,,,,,6724236738.2,,,,,56325166.9,3735883405.25,3792208572.15,10516445310.35,,828761.06,,,,,,,,,,,,10492697.73,2953734709.32,4782291665.09,17747849.68,2796332676.46,513379615.06,27153295.52,24064300.0,,,0
|
|
||||||
688778.SH,20211029,20211029,20210930,1,1,3,251572267.0,2739821000.61,556697264.25,30211210.62,,1435013449.1,,,1864210088.39,,14772623.97,,,1902430656.58,,,,,,,,,180285784.85,5777108826.95,,,0.0,,,,,,,,,,,243702801.28,,,,66507494.12,,45232940.44,3452190028.33,,,,,,,,,,,,,,,,,9229298855.28,1027414645.85,600591666.67,,,,,995342099.92,2429404927.79,,,,8014959.58,27427598.19,,,,,,,,,,,258823325.86,34270433.81,4418389246.11,,,,,4209205.38,124934337.26,,1180566188.49,,,,,,,,,,,,,,,,,5598955434.6,,,,,54162859.17,3576180561.51,3630343420.68,9229298855.28,,-2121180.97,,,,,,,,,,,,29750463.8,1864210088.39,3424747027.71,26915414.97,2585975097.63,510166188.45,34763770.49,24008000.0,,,1
|
|
||||||
688778.SH,20211029,20211029,20210930,1,1,3,251572267.0,2739821000.61,556697264.25,30211210.62,,1435013449.1,,,1864210088.39,,14772623.97,,,1902430656.58,,,,,,,,,180285784.85,5777108826.95,,,0.0,,,,,,,,,,,243702801.28,,,,66507494.12,,45232940.44,3452190028.33,,,,,,,,,,,,,,,,,9229298855.28,1027414645.85,600591666.67,,,,,995342099.92,2429404927.79,,,,8014959.58,27427598.19,,,,,,,,,,,258823325.86,34270433.81,4418389246.11,,,,,4209205.38,124934337.26,,1180566188.49,,,,,,,,,,,,,,,,,5598955434.6,,,,,54162859.17,3576180561.51,3630343420.68,9229298855.28,,-2121180.97,,,,,,,,,,,,29750463.8,1864210088.39,3424747027.71,26915414.97,2585975097.63,510166188.45,34763770.49,24008000.0,,,0
|
|
||||||
688778.SH,20210804,20210804,20210630,1,1,2,188679200.0,1355637100.18,408613668.14,30211210.62,,165891758.98,,,1790399271.32,,32576460.7,,,1685741587.99,,,,,,,,,165851148.12,4096114781.6,,,,,,,,,,,,,,245071182.29,,,,65770790.58,,82877230.64,3293744972.26,,,,,,,,,,,,,,,,,7389859753.86,949633960.11,1106316183.92,,,,,897748189.53,1874404379.84,,,,5578055.18,28181937.82,,,,,,,,,,,269813191.41,35518184.06,4255579697.55,,,,,4349023.73,122663403.1,,1100700386.94,,,,,,,,,,,,,,,,,5356280084.49,,,,,50538798.04,1983040871.33,2033579669.37,7389859753.86,,-100307.61,,,,,,,,,,,,9745456.37,1790399271.32,2772152569.37,38911829.45,2282206035.24,616608720.69,28274119.42,24054000.0,,,0
|
|
||||||
688778.SH,20210719,20210719,20210331,1,1,1,188679200.0,1372187447.23,269497926.04,30211210.62,,302698033.33,,,1369143049.46,42416555.99,27000108.55,,,1859683758.59,,,,,,,,,137204483.53,4214041918.61,,,4168399.11,,,,,2326394609.57,375425028.94,64870978.92,,,,246441445.66,,,,64093629.07,,37758555.23,3120981891.73,,,,,,,,,,,,,,,,,7335023810.34,1115380614.61,1178463331.84,,,,,509486444.4,2042485978.64,,,,20968157.43,25521091.65,,,87244225.56,,,,,,,,244330122.64,34012396.86,4148909533.59,,24008800.0,,,4488842.08,126437885.61,,1270316142.3,,,,,,,,,,,,,,,,,5419225675.89,,,,,59355861.51,1856442272.94,1915798134.45,7335023810.34,,-4133510.95,,,,,,,,,,,,6397784.57,1369143049.46,2551972423.04,42416555.99,2326394609.57,440296007.86,87244225.56,24008800.0,,,1
|
|
||||||
688778.SH,20210719,20210719,20210331,1,1,1,188679200.0,1372187447.23,269497926.04,30211210.62,,302698033.33,,,1369143049.46,42416555.99,27000108.55,,,1859683758.59,,,,,,,,,137204483.53,4214041918.61,,,4168399.11,,,,,2326394609.57,375425028.94,64870978.92,,,,246441445.66,,,,64093629.07,,37758555.23,3120981891.73,,,,,,,,,,,,,,,,,7335023810.34,1115380614.61,1178463331.84,,,,,509486444.4,2042485978.64,,,,20968157.43,25521091.65,,,87244225.56,,,,,,,,244330122.64,34012396.86,4148909533.59,,24008800.0,,,4488842.08,126437885.61,,1270316142.3,,,,,,,,,,,,,,,,,5419225675.89,,,,,59355861.51,1856442272.94,1915798134.45,7335023810.34,,-4133510.95,,,,,,,,,,,,6397784.57,1369143049.46,2551972423.04,42416555.99,2326394609.57,440296007.86,87244225.56,24008800.0,,,0
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,188679200.0,1372187447.23,157703141.03,30211210.62,,277915563.42,,,1234540796.12,44045894.07,77834786.48,,,1214093975.17,,,,,,,,,143646449.56,3199682391.8,,,4168399.11,,,,,2379475585.04,287718240.5,3034635.28,,,,247810767.85,,,,60071924.12,,39863485.51,3022143037.41,,,,,,,,,,,,,,,,,6221825429.21,1135256887.11,1042688943.47,,,,,426997585.58,1216933928.46,,,,17259766.01,10322947.11,,,150656168.85,,,,,,,,243571130.43,11948922.68,3122315655.13,,24054300.0,,,4628660.43,130361118.12,,1294300965.66,,,,,,,,,,,,,,,,,4416616620.79,,,,,57099191.26,1748109617.16,1805208808.42,6221825429.21,,-671381.72,,,,,,,,,,,,1936262.54,1234540796.12,1643931514.04,44045894.07,2379475585.04,290752875.78,150656168.85,24054300.0,,,0
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,188679200.0,1372187447.23,157703141.03,30211210.62,,277915563.42,,,1234540796.12,44045894.07,77834786.48,,,1214093975.17,,,,,,,,,143646449.56,3199682391.8,,,4168399.11,,,,,2379475585.04,287718240.5,3034635.28,,,,247810767.85,,,,60071924.12,,39863485.51,3022143037.41,,,,,,,,,,,,,,,,,6221825429.21,1135256887.11,1042688943.47,,,,,426997585.58,1216933928.46,,,,17259766.01,10322947.11,,,150656168.85,,,,,,,,243571130.43,11948922.68,3122315655.13,,24054300.0,,,4628660.43,130361118.12,,1294300965.66,,,,,,,,,,,,,,,,,4416616620.79,,,,,57099191.26,1748109617.16,1805208808.42,6221825429.21,,-671381.72,,,,,,,,,,,,1936262.54,1234540796.12,1643931514.04,44045894.07,2379475585.04,290752875.78,150656168.85,24054300.0,,,1
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,188679200.0,1372187447.23,28280871.19,4434618.18,,335696803.63,,,544877820.67,15209476.98,33333664.82,,,726728765.89,,,,,,,,,154141521.79,2376594686.77,,,4168399.11,,,,,2170886245.9,421366951.36,20528085.7,,,,250549412.23,,,,57612913.43,,3408956.24,2928520963.97,,,,,,,,,,,,,,,,,5305115650.74,235081766.61,1766444838.88,,,,,305044327.22,685608476.74,,,,12630193.37,2630804.62,,,262162841.06,,,,,,,,199334066.73,5422390.4,3239517887.46,,45102000.0,,,4908297.14,134409182.93,,419501246.68,,,,,,,,,,,,,,,,,3659019134.14,,,,,52996426.23,1593100090.37,1646096516.6,5305115650.74,,-482046.23,,,,,,,,,,,,239948.44,544877820.67,990652803.96,15209476.98,2170886245.9,441895037.06,262162841.06,45102000.0,,,1
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,188679200.0,1372187447.23,28280871.19,4434618.18,,335696803.63,,,544877820.67,15209476.98,33333664.82,,,726728765.89,,,,,,,,,154141521.79,2376594686.77,,,4168399.11,,,,,2170886245.9,421366951.36,20528085.7,,,,250549412.23,,,,57612913.43,,3408956.24,2928520963.97,,,,,,,,,,,,,,,,,5305115650.74,235081766.61,1766444838.88,,,,,305044327.22,685608476.74,,,,12630193.37,2630804.62,,,262162841.06,,,,,,,,199334066.73,5422390.4,3239517887.46,,45102000.0,,,4908297.14,134409182.93,,419501246.68,,,,,,,,,,,,,,,,,3659019134.14,,,,,52996426.23,1593100090.37,1646096516.6,5305115650.74,,-482046.23,,,,,,,,,,,,239948.44,544877820.67,990652803.96,15209476.98,2170886245.9,441895037.06,262162841.06,45102000.0,,,0
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,170013678.78,950602909.7,349705428.69,44420543.12,,51441116.28,,,659595746.14,29934557.63,21015750.51,,,859942113.12,,,,,,,,,153255848.88,2522597549.44,,,3591492.88,,,,,1997148158.52,502545983.97,2279045.74,,,,253288056.61,,,,56895322.56,,9635842.43,2825383902.71,,,,,,,,,,,,,,,,,5347981452.15,167037351.99,1751453791.66,,,,,338210765.0,881064981.51,2462418.17,,,24634198.68,2707700.97,,,331207875.32,,,,,,,,57197129.74,22579471.5,3411518332.55,,55136000.0,,,5187933.84,141293807.82,,368655093.65,,,,,,,,,,,,,,,,,3780173426.2,,,,,55769691.16,1512038334.79,1567808025.95,5347981452.15,,-2704225.5,,,,,,,,,,,,,659595746.14,1219275746.51,29934557.63,1997148158.52,504825029.71,331207875.32,55136000.0,,,0
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,170013678.78,950602909.7,349705428.69,44420543.12,,51441116.28,,,659595746.14,29934557.63,21015750.51,,,859942113.12,,,,,,,,,153255848.88,2522597549.44,,,3591492.88,,,,,1997148158.52,502545983.97,2279045.74,,,,253288056.61,,,,56895322.56,,9635842.43,2825383902.71,,,,,,,,,,,,,,,,,5347981452.15,167037351.99,1751453791.66,,,,,338210765.0,881064981.51,2462418.17,,,24634198.68,2707700.97,,,331207875.32,,,,,,,,57197129.74,22579471.5,3411518332.55,,55136000.0,,,5187933.84,141293807.82,,368655093.65,,,,,,,,,,,,,,,,,3780173426.2,,,,,55769691.16,1512038334.79,1567808025.95,5347981452.15,,-2704225.5,,,,,,,,,,,,,659595746.14,1219275746.51,29934557.63,1997148158.52,504825029.71,331207875.32,55136000.0,,,1
|
|
||||||
688778.SH,20190823,20190823,20190630,1,1,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5740547900.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5740547900.0,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20210719,20210719,20181231,1,1,4,100000000.0,402185198.9,217826054.09,26218943.16,466267.74,164511275.72,,318627912.61,881078987.04,73443987.02,343962447.38,,,1590230889.3,,,,,,,,,155741898.13,3527597397.2,,,,,,,,1080492751.4,696414181.64,3701724.88,,,,139440219.17,,,,43234619.26,,58259900.28,2021543396.63,,,,,,,,,,,,,,,,,5549140793.83,104000000.0,1300431310.06,,,,,1094788400.0,675646379.34,7934511.12,,,22060535.29,10957949.8,5731442.31,,1281704588.72,,,,,,,,10000000.0,54183951.66,4463439068.3,,60000000.0,,,5161758.34,106147526.33,,275309284.67,,,,,,,,,,,,,,,,,4738748352.97,,,,,63695976.97,746696463.89,810392440.86,5549140793.83,,,,,,,,,,,,,,,1199706899.65,1770434779.34,73443987.02,1080492751.4,700115906.52,1287436031.03,60000000.0,,,1
|
|
||||||
688778.SH,20190312,20190312,20180630,1,1,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3754183300.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3036854500.0,,,,,,717328800.0,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20200804,20200804,20171231,1,1,4,100000000.0,400777224.5,144855758.11,19083139.03,2134017.42,109515935.46,,525443273.42,499240298.89,10672021.07,122918781.49,,,1233213290.29,,,,,,,,,78541878.32,2579545478.94,,,,,,,,575026245.5,421709250.76,2887782.05,,,,140451654.77,,,,16080990.15,,38102970.11,1194258893.34,,,,,,,,,,,,,,,,,3773804372.28,4000000.0,390000000.0,,,,,271834000.0,584552099.74,13721502.86,,,21525467.17,49509441.09,2458125.0,,1532674550.5,,,,,,,,,38485672.46,2904760858.82,,60000000.0,,,,75415721.95,,139415721.95,,,,,,,,,,,,,,,,,3044176580.77,,,,,62777652.45,666850139.06,729627791.51,3773804372.28,,,,,,,,,,,,,,,1024683572.31,856386099.74,10672021.07,575026245.5,424597032.81,1535132675.5,60000000.0,,,1
|
|
||||||
688778.SH,20170810,20170810,20170630,1,1,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2683034200.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2683034200.0,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20170427,20170427,20161231,1,1,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0.0,,,,,,100000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,comp_type,report_type,end_type,net_profit,finan_exp,c_fr_sale_sg,recp_tax_rends,n_depos_incr_fi,n_incr_loans_cb,n_inc_borr_oth_fi,prem_fr_orig_contr,n_incr_insured_dep,n_reinsur_prem,n_incr_disp_tfa,ifc_cash_incr,n_incr_disp_faas,n_incr_loans_oth_bank,n_cap_incr_repur,c_fr_oth_operate_a,c_inf_fr_operate_a,c_paid_goods_s,c_paid_to_for_empl,c_paid_for_taxes,n_incr_clt_loan_adv,n_incr_dep_cbob,c_pay_claims_orig_inco,pay_handling_chrg,pay_comm_insur_plcy,oth_cash_pay_oper_act,st_cash_out_act,n_cashflow_act,oth_recp_ral_inv_act,c_disp_withdrwl_invest,c_recp_return_invest,n_recp_disp_fiolta,n_recp_disp_sobu,stot_inflows_inv_act,c_pay_acq_const_fiolta,c_paid_invest,n_disp_subs_oth_biz,oth_pay_ral_inv_act,n_incr_pledge_loan,stot_out_inv_act,n_cashflow_inv_act,c_recp_borrow,proc_issue_bonds,oth_cash_recp_ral_fnc_act,stot_cash_in_fnc_act,free_cashflow,c_prepay_amt_borr,c_pay_dist_dpcp_int_exp,incl_dvd_profit_paid_sc_ms,oth_cashpay_ral_fnc_act,stot_cashout_fnc_act,n_cash_flows_fnc_act,eff_fx_flu_cash,n_incr_cash_cash_equ,c_cash_equ_beg_period,c_cash_equ_end_period,c_recp_cap_contrib,incl_cash_rec_saims,uncon_invest_loss,prov_depr_assets,depr_fa_coga_dpba,amort_intang_assets,lt_amort_deferred_exp,decr_deferred_exp,incr_acc_exp,loss_disp_fiolta,loss_scr_fa,loss_fv_chg,invest_loss,decr_def_inc_tax_assets,incr_def_inc_tax_liab,decr_inventories,decr_oper_payable,incr_oper_payable,others,im_net_cashflow_oper_act,conv_debt_into_cap,conv_copbonds_due_within_1y,fa_fnc_leases,im_n_incr_cash_equ,net_dism_capital_add,net_cash_rece_sec,credit_impa_loss,use_right_asset_dep,oth_loss_asset,end_bal_cash,beg_bal_cash,end_bal_cash_equ,beg_bal_cash_equ,update_flag
|
|
||||||
688778.SH,20251025,20251025,20250930,1,1,3,,,10198355511.47,42112018.27,,,,,,,,,,,,103893746.14,10344361275.88,8785709021.19,395263775.52,127038127.25,,,,,,139332215.72,9447343139.68,897018136.2,,1214238740.52,3986919.45,,,1218225659.97,488668506.2,1221497257.98,,,,1710165764.18,-491940104.21,210394634.0,,98362983.64,308757617.64,-111814516.7372,277401514.27,288502329.34,,280453605.93,846357449.54,-537599831.9,29680956.41,-102840843.5,1648634111.52,1545793268.02,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20250821,20250821,20250630,1,1,2,305884620.09,5156493.57,6103527439.3,19265719.47,,,,,,,,,,,,75895448.25,6198688607.02,5139678679.61,249266842.54,72206183.52,,,,,,89501913.76,5550653619.43,648034987.59,,560019199.23,3476739.72,,,563495938.95,299592858.22,550997257.98,,,,850590116.2,-287094177.25,91000000.0,,98362983.64,189362983.64,445136670.4675,204109014.27,9743333.22,,79795638.3,293647985.79,-104285002.15,33227198.15,289883006.34,1635736325.57,1925619331.91,,,,8969614.42,201161886.06,6473115.66,3354158.16,,,,1697657.7,-4053631.27,17917613.43,-33837535.8,-1396523.82,-916706646.85,205001371.03,824021972.52,,648034987.59,,,,289883006.34,,,16144384.04,3950867.88,,1925619331.91,1635736325.57,,,1
|
|
||||||
688778.SH,20250426,20250426,20250331,1,1,1,,,2785591853.31,23781.98,,,,,,,,,,,,49611893.93,2835227529.22,2397138799.28,113586952.79,16986063.56,,,,,,34141530.65,2561853346.28,273374182.94,,408998000.0,3476739.72,,,412474739.72,165019949.24,403999000.0,,,,569018949.24,-156544209.52,91000000.0,,,91000000.0,-100528504.8981,136523300.0,4858885.06,0.0,6053881.28,147436066.34,-56436066.34,12388313.97,72782221.05,1635067409.62,1707849630.67,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20250426,20250426,20250331,1,1,1,,,2785591853.31,23781.98,,,,,,,,,,,,49611893.93,2835227529.22,2397138799.28,113586952.79,16986063.56,,,,,,34141530.65,2561853346.28,273374182.94,,408998000.0,3476739.72,,,412474739.72,165019949.24,403999000.0,,,,569018949.24,-156544209.52,91000000.0,,,91000000.0,,136523300.0,4858885.06,0.0,6053881.28,147436066.34,-56436066.34,12388313.97,72782221.05,1635067409.62,1707849630.67,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20250426,20250426,20241231,1,1,4,488321118.14,46743354.39,9519912802.79,57517.49,,,,,,,,,,,,224636301.88,9744606622.16,7254835304.6,511330436.91,102468158.73,,,,,,122737060.76,7991370961.0,1753235661.16,,1988996000.0,12595707.32,,,2001591707.32,965807934.63,2007967970.68,,,,2973775905.31,-972184197.99,990023300.0,,,1065684200.0,678719158.6646,1035805714.27,326425093.53,,44280325.11,1406511132.91,-340826932.91,-4733386.28,435491143.98,1199576265.64,1635067409.62,75660900.0,75660900.0,,194158465.59,367807450.38,12057787.74,5470579.97,,,,5877278.79,-7518003.31,18178379.54,-31470994.78,-2608935.87,-705950502.14,385685141.37,1023052385.03,,1753235661.16,,,,435491143.98,,,-60327208.5,7973281.22,,1635067409.62,1199576265.64,,,1
|
|
||||||
688778.SH,20241026,20241026,20240930,1,1,3,,,7087639973.57,57632.97,,,,,,,,,,,,71494166.09,7159191772.63,5370289813.86,337422151.57,71701945.51,,,,,,107755773.7,5887169684.64,1272022087.99,,1779997000.0,11752273.54,,,1791749273.54,758350709.3,1779997000.0,,,,2538347709.3,-746598435.76,990023300.0,,,990023300.0,183405487.5758,778845714.27,320429058.26,,42889722.06,1142164494.59,-152141194.59,2831773.41,376114231.05,1199576265.64,1575690496.69,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20240803,20240803,20240630,1,1,2,238436027.58,31281783.4,4766567808.97,39791.27,,,,,,,,,,,,57121136.84,4823728737.08,3524984588.47,219140169.6,50814498.08,,,,,,86102693.1,3881041949.25,942686787.83,,1269998000.0,9558662.57,,,1279556662.57,506228536.57,1229998760.0,,,,1736227296.57,-456670634.0,885023300.0,,,885023300.0,,479060000.0,312656120.78,,32728210.92,824444331.7,60578968.3,-1092453.87,545502668.26,1199576265.64,1745078933.9,,,,60538331.13,183242526.76,6018050.56,2735289.96,,,,394179.22,-3540044.35,4413115.89,-14634231.77,-2204150.64,-627826629.32,891599972.16,202275019.26,,942686787.83,,,,545502668.26,,,-40840441.78,4022413.57,,1745078933.9,1199576265.64,,,0
|
|
||||||
688778.SH,20240803,20240803,20240630,1,1,2,238436027.58,31281783.4,4766567808.97,39791.27,,,,,,,,,,,,57121136.84,4823728737.08,3524984588.47,219140169.6,50814498.08,,,,,,86102693.1,3881041949.25,942686787.83,,1269998000.0,9558662.57,,,1279556662.57,506228536.57,1229998760.0,,,,1736227296.57,-456670634.0,885023300.0,,,885023300.0,472368050.5964,479060000.0,312656120.78,,32728210.92,824444331.7,60578968.3,-1092453.87,545502668.26,1199576265.64,1745078933.9,,,,60538331.13,183242526.76,6018050.56,2735289.96,,,,394179.22,-3540044.35,4413115.89,-14634231.77,-2204150.64,-627826629.32,891599972.16,202275019.26,,942686787.83,,,,545502668.26,,,-40840441.78,4022413.57,,1745078933.9,1199576265.64,,,1
|
|
||||||
688778.SH,20240418,20240418,20240331,1,1,1,,,2460273540.2,16901.69,,,,,,,,,,,,31643533.83,2491933975.72,1822253426.8,104522641.89,26731404.58,,,,,,34246115.37,1987753588.64,504180387.08,,499999000.0,6701922.18,,,506700922.18,275683706.59,500000250.0,,0.0,,775683956.59,-268983034.41,885023300.0,,0.0,885023300.0,132764488.8373,3000000.0,8901222.69,0.0,30830900.84,42732123.53,842291176.47,-1324211.85,1076164317.29,1199576265.64,2275740582.93,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20240418,20240418,20231231,1,1,4,529491777.15,106270457.08,13544969185.54,189783.19,,,,,,,,,,,,139163127.59,13684322096.32,10211449407.98,415120201.27,345390598.57,,,,,,132162183.06,11104122390.88,2580199705.44,,1050811416.67,4622338.92,,,1055433755.59,1145249533.56,1394739000.0,,,,2539988533.56,-1484554777.97,872800000.0,,,977800000.0,1715756451.248,1704400000.0,198164326.08,,6215437.98,1908779764.06,-930979764.06,18392889.95,183058053.36,1016518212.28,1199576265.64,105000000.0,105000000.0,,178565661.45,349928190.47,9219518.08,2969417.87,,,,5904759.36,-4163210.94,-7107457.5,-18139113.45,1427889.22,1209296263.32,2158853595.45,-1873055678.24,,2580199705.44,,,,183058053.36,,,-76517812.99,6450819.72,,1199576265.64,1016518212.28,,,1
|
|
||||||
688778.SH,20231025,20231025,20230930,1,1,3,,,10467104062.85,146609.24,,,,,,,,,,,,110926774.7,10578177446.79,8404738982.67,273972895.77,286569851.36,,,,,,114356238.84,9079637968.64,1498539478.15,,1050811416.67,4622338.92,,,1055433755.59,783327220.89,1344740000.0,,,,2128067220.89,-1072633465.3,852000000.0,,,957000000.0,210758519.33,888600000.0,186159345.83,,5831704.98,1080591050.81,-123591050.81,16059510.46,318374472.5,1016518212.28,1334892684.78,105000000.0,105000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20231025,20231025,20230930,1,1,3,,,10467104062.85,146609.24,,,,,,,,,,,,110926774.7,10578177446.79,8404738982.67,273972895.77,286569851.36,,,,,,114356238.84,9079637968.64,1498539478.15,,1050811416.67,4622338.92,,,1055433755.59,783327220.89,1344740000.0,,,,2128067220.89,-1072633465.3,852000000.0,,,957000000.0,804172713.5816,888600000.0,186159345.83,,5831704.98,1080591050.81,-123591050.81,16059510.46,318374472.5,1016518212.28,1334892684.78,105000000.0,105000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20230825,20230825,20230630,1,1,2,255266071.62,54601385.4,7554353431.31,107955.04,,,,,,,,,,,,66692050.39,7621153436.74,6015882586.56,178481285.98,257006985.32,,,,,,79167789.01,6530538646.87,1090614789.87,,550811416.67,2232282.1,,,553043698.77,584062162.33,594740000.0,,,,1178802162.33,-625758463.56,742000000.0,,,847000000.0,541892847.5576,568200000.0,174474825.72,,2379471.32,745054297.04,101945702.96,14580191.54,581382220.81,1016518212.28,1597900433.09,105000000.0,105000000.0,,95487727.3,173924512.39,3747673.8,1781654.72,,,,2068957.5,,-9631902.28,1452840.51,-279636.7,1296091911.7,2147122539.72,-2830501685.41,,1090614789.87,,,,581382220.81,,,-103548548.23,3031287.83,,1597900433.09,1016518212.28,,,1
|
|
||||||
688778.SH,20230422,20230422,20230331,1,1,1,,,4316666162.25,54863.79,,,,,,,,,,,,34693537.06,4351414563.1,3451563285.74,85248896.27,105399593.19,,,,,,32391685.58,3674603460.78,676811102.32,,450000000.0,2230059.88,,,452230059.88,134341538.79,594740000.0,,,,729081538.79,-276851478.91,402000000.0,,0.0,402000000.0,60289974.7726,222700000.0,12294856.95,,1742485.66,236737342.61,165262657.39,-1257790.87,563964489.93,1016518212.28,1580482702.21,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20230422,20230422,20230331,1,1,1,,,4316666162.25,54863.79,,,,,,,,,,,,34693537.06,4351414563.1,3451563285.74,85248896.27,105399593.19,,,,,,32391685.58,3674603460.78,676811102.32,,450000000.0,2230059.88,,,452230059.88,134341538.79,594740000.0,,,,729081538.79,-276851478.91,402000000.0,,0.0,402000000.0,681689974.7726,222700000.0,12294856.95,,1742485.66,236737342.61,165262657.39,-1257790.87,563964489.93,1016518212.28,1580482702.21,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,1129880515.59,120191224.54,15561092286.68,297597281.58,,,,,,,,,,,,171518574.44,16030208142.7,16723541559.63,336031383.04,391079031.02,,,,,,140986766.58,17591638740.27,-1561430597.57,,303251813.2,2477374.43,4535.5,,305733723.13,650661425.97,650000000.0,,,,1300661425.97,-994927702.84,2333165406.17,,,5913365300.25,-2383625052.1233,2411778233.78,186424842.53,,179740556.82,2777943633.13,3135421667.12,8938215.13,588001581.84,428516630.44,1016518212.28,3580199894.08,85000000.0,,149808467.88,296389110.13,5781446.77,,,,-4535.5,5129425.18,,-5499341.74,-17982000.92,-559273.41,-628607056.11,-3093979995.47,372065771.02,,-1561430597.57,,,,588001581.84,,,102361558.43,3594086.04,,1016518212.28,428516630.44,,,1
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,1129880515.59,120191224.54,15561092286.68,297597281.58,,,,,,,,,,,,171518574.44,16030208142.7,16723541559.63,336031383.04,391079031.02,,,,,,140986766.58,17591638740.27,-1561430597.57,,303251813.2,2477374.43,4535.5,,305733723.13,650661425.97,650000000.0,,,,1300661425.97,-994927702.84,2333165406.17,,,5913365300.25,-2383625052.1233,2411778233.78,186424842.53,,179740556.82,2777943633.13,3135421667.12,8938215.13,588001581.84,428516630.44,1016518212.28,3580199894.08,85000000.0,,149808467.88,296389110.13,5781446.77,,,,-4535.5,5129425.18,,-5499341.74,-17982000.92,-559273.41,-628607056.11,-3093979995.47,372065771.02,,-1561430597.57,,,,588001581.84,,,102361558.43,3594086.04,,1016518212.28,428516630.44,,,0
|
|
||||||
688778.SH,20221027,20221027,20220930,1,1,3,,,10685973810.23,283588668.05,,,,,,,,,,,,127040894.79,11096603373.07,11706738166.87,218908643.8,293300927.75,,,,,,158214602.87,12377162341.29,-1280558968.22,,300000000.0,5729187.63,4535.5,,305733723.13,456697841.67,100000000.0,,,,556697841.67,-250964118.54,1883165406.17,,,5463365300.25,-1478723299.4085,1837778233.78,172333018.04,,4122243.26,2014233495.08,3449131805.17,8830770.5,1926439488.91,425014387.51,2351453876.42,3580199894.08,85000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20221027,20221027,20220930,1,1,3,,,10685973810.23,283588668.05,,,,,,,,,,,,127040894.79,11096603373.07,11706738166.87,218908643.8,293300927.75,,,,,,158214602.87,12377162341.29,-1280558968.22,,300000000.0,5729187.63,4535.5,,305733723.13,456697841.67,100000000.0,,,,556697841.67,-250964118.54,1883165406.17,,,5463365300.25,-2521538945.6,1837778233.78,172333018.04,,4122243.26,2014233495.08,3449131805.17,8830770.5,1926439488.91,425014387.51,2351453876.42,3580199894.08,85000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20220728,20220728,20220630,1,1,2,537063271.42,50666027.26,6014968609.39,204187720.95,,,,,,,,,,,,109316639.16,6328472969.5,5815045585.63,142413044.39,148034350.65,,,,,,67862487.72,6173355468.39,155117501.11,,300000000.0,2477374.43,,,302477374.43,310236406.34,100000000.0,,,,410236406.34,-107759031.91,1083165406.17,,,1168165406.17,150961508.8056,777446751.43,157256578.37,,1289619.26,935992949.06,232172457.11,7682794.79,287213721.1,425014387.51,712228108.61,85000000.0,85000000.0,,164846458.89,138252530.69,2749706.31,0.0,,,0.0,1840747.52,0.0,-1935152.21,-13248352.53,-279636.7,-847483996.57,-2009254800.15,2130716877.5,,155117501.11,,,,287213721.1,,,0.0,1183819.68,,712228108.61,425014387.51,0.0,0.0,1
|
|
||||||
688778.SH,20220427,20220427,20220331,1,1,1,,,2526112830.15,12334377.98,,,,,,,,,,,,74977487.83,2613424695.96,2362586038.05,71144779.33,66045554.23,,,,,,44172677.62,2543949049.23,69475646.73,,200000000.0,1580152.21,,,201580152.21,153549983.27,100000000.0,,,,253549983.27,-51969831.06,832103201.18,,,882103201.18,136999478.7791,207379400.0,15221237.31,,644809.63,223245446.94,658857754.24,-308203.03,676055366.88,425014387.51,1101069754.39,50000000.0,50000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20220331,20220331,20211231,1,1,4,568137491.16,123429328.39,4990224293.12,58318651.83,,,,,,,,,,,,82535568.49,5131078513.44,4154030691.03,265620315.47,186894602.84,,,,,,92521864.72,4699067474.06,432011039.38,,114293314.34,484075.51,,,114777389.85,556253874.65,300000000.0,,,,856253874.65,-741476484.8,1770381988.6,,,3238718123.02,-12568210.3197,2526278487.66,81523635.77,4500000.0,173696024.37,2781498147.8,457219975.22,-655705.71,147098824.09,277915563.42,425014387.51,1468336134.42,4500000.0,,74960397.3,232895000.28,5477288.76,,,,,6060690.52,,-11210471.23,-26094072.3,-559273.41,-1656214011.47,-2168669804.86,3190858693.08,,432011039.38,,,,147098824.09,,,90514386.09,2425397.07,,425014387.51,277915563.42,,,1
|
|
||||||
688778.SH,20220331,20220331,20211231,1,1,4,568137491.16,123429328.39,4990224293.12,58318651.83,,,,,,,,,,,,82535568.49,5131078513.44,4154030691.03,265620315.47,186894602.84,,,,,,92521864.72,4699067474.06,432011039.38,,114293314.34,484075.51,,,114777389.85,556253874.65,300000000.0,,,,856253874.65,-741476484.8,1770381988.6,,,3238718123.02,-12568210.3197,2526278487.66,81523635.77,4500000.0,173696024.37,2781498147.8,457219975.22,-655705.71,147098824.09,277915563.42,425014387.51,1468336134.42,4500000.0,,74960397.3,232895000.28,5477288.76,,,,,6060690.52,,-11210471.23,-26094072.3,-559273.41,-1656214011.47,-2168669804.86,3190858693.08,,432011039.38,,,,147098824.09,,,90514386.09,2425397.07,,425014387.51,277915563.42,,,0
|
|
||||||
688778.SH,20211029,20211029,20210930,1,1,3,,,3485925713.29,46088941.13,,,,,,,,,,,,52526389.22,3584541043.64,2463491571.8,178562716.59,154345697.74,,,,,,52165506.79,2848565492.92,735975550.72,,,,0.0,,0.0,296383245.54,,,,,296383245.54,-296383245.54,873962788.6,,,2337798923.02,513272096.4696,1401813487.66,62051728.14,,156135500.0,1620000715.8,717798207.22,-292626.72,1157097885.68,277915563.42,1435013449.1,1463836134.42,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20210804,20210804,20210630,1,1,2,,,2123656374.88,35011133.26,,,,,,,,,,,,32170614.77,2190838122.91,1598717700.87,118443305.23,99475539.8,,,,,,38413871.05,1855050416.95,335787705.96,,,,,,,160115703.19,,,,,160115703.19,-160115703.19,563962788.6,,,563962788.6,452466903.8866,660015559.1,41221370.52,,150135500.0,851372429.62,-287409641.02,-286166.19,-112023804.44,277915563.42,165891758.98,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20210719,20210719,20210331,1,1,1,114411526.09,37952651.07,912941976.75,9453556.72,,,,,,,,,,,,39296907.67,961692441.14,779121093.92,46553352.95,42989223.94,,,,,,30931549.92,899595220.73,62097220.41,,,,,,,68944229.06,,,,,68944229.06,-68944229.06,253962788.6,,,253962788.6,21817605.1208,140857142.86,21266861.3,,60000000.0,222124004.16,31838784.44,-209305.88,24782469.91,277915563.42,302698033.33,,,,3500772.42,56466196.47,1369322.19,,,,,1769384.24,,,-5825558.32,-139818.35,-737188375.76,-845164802.15,1427913593.38,,62097220.41,,,,24782469.91,,,7032329.13,,,302698033.33,277915563.42,,,1
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,251637337.2,114394645.43,3038419568.9,57939847.61,,,,,,,,,,,,69782314.55,3166141731.06,2346503512.56,176565500.35,107473340.8,,,,,,138719470.32,2769261824.03,396879907.03,,,,506780.29,,506780.29,333176928.52,,,,,333176928.52,-332670148.23,2922289400.0,,,3089919297.16,45978881.3941,2487571428.58,286552967.0,3000000.0,155000000.0,2929124395.58,160794901.58,1469786.76,226474447.14,51441116.28,277915563.42,167629897.16,3000000.0,,47360230.97,191083013.24,5477288.76,,,,477694.2,9514381.22,,-1103388.89,-3176601.56,-559273.41,-401512093.02,-269338780.61,422354744.44,,396879907.03,,,,226474447.14,,,30270709.06,,,277915563.42,51441116.28,,,1
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,251637337.2,114394645.43,3038419568.9,57939847.61,,,,,,,,,,,,69782314.55,3166141731.06,2346503512.56,176565500.35,107473340.8,,,,,,138719470.32,2769261824.03,396879907.03,,,,506780.29,,506780.29,333176928.52,,,,,333176928.52,-332670148.23,2922289400.0,,,3089919297.16,45978881.3941,2487571428.58,286552967.0,3000000.0,155000000.0,2929124395.58,160794901.58,1469786.76,226474447.14,51441116.28,277915563.42,167629897.16,3000000.0,,47360230.97,191083013.24,5477288.76,,,,477694.2,9514381.22,,-1103388.89,-3176601.56,-559273.41,-401512093.02,-269338780.61,422354744.44,,396879907.03,,,,226474447.14,,,30270709.06,,,277915563.42,51441116.28,,,0
|
|
||||||
688778.SH,20211029,20211029,20200930,1,1,3,,,2092787793.24,56325556.01,,,,,,,,,,,,61906193.62,2211019542.87,1518364943.91,120416567.02,77113641.48,,,,,,104595931.92,1820491084.33,390528458.54,,,,1500.0,,1500.0,267834691.2,,,,,267834691.2,-267833191.2,1525000000.0,,,1692629897.16,,1272571428.58,252644432.53,3000000.0,95000000.0,1620215861.11,72414036.05,2196295.44,197305598.83,51441116.28,248746715.11,167629897.16,3000000.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,92250423.63,46343627.2,1240123774.8,22113477.75,,,,,,,,,,,,30577349.93,1292814602.48,800205390.85,82642425.85,53133931.01,,,,,,42953916.56,978935664.27,313878938.21,,,,1500.0,,1500.0,155690946.19,,,,,155690946.19,-155689446.19,1185000000.0,,,1352629897.16,412884613.4532,960000000.0,232929121.33,3000000.0,35000000.0,1227929121.33,124700775.83,1365419.5,284255687.35,51441116.28,335696803.63,167629897.16,3000000.0,,27930393.28,89000046.67,2738644.38,,,,11525.44,4284214.24,,-1103388.89,-717590.87,-279636.7,105282953.95,305378440.03,-351213371.88,,313878938.21,,,,284255687.35,,,-6027342.27,,,335696803.63,51441116.28,,,1
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,92250423.63,46343627.2,1240123774.8,22113477.75,,,,,,,,,,,,30577349.93,1292814602.48,800205390.85,82642425.85,53133931.01,,,,,,42953916.56,978935664.27,313878938.21,,,,1500.0,,1500.0,155690946.19,,,,,155690946.19,-155689446.19,1185000000.0,,,1352629897.16,412884613.4532,960000000.0,232929121.33,3000000.0,35000000.0,1227929121.33,124700775.83,1365419.5,284255687.35,51441116.28,335696803.63,167629897.16,3000000.0,,27930393.28,89000046.67,2738644.38,,,,11525.44,4284214.24,,-1103388.89,-717590.87,-279636.7,105282953.95,305378440.03,-351213371.88,,313878938.21,,,,284255687.35,,,-6027342.27,,,335696803.63,51441116.28,,,0
|
|
||||||
688778.SH,20210719,20210719,20200331,1,1,1,34582066.81,24675367.33,590326266.21,13019601.56,,,,,,,,,,,,5106664.61,608452532.38,397023743.91,29569511.1,9725913.07,,,,,,22610137.63,458929305.71,149523226.67,,,,,,,118036407.05,,,,,118036407.05,-118036407.05,585000000.0,,,749629897.16,,200000000.0,196463918.38,,12500000.0,408963918.38,340665978.78,1246993.32,373399791.72,51441116.28,424840908.0,164629897.16,,,14706127.52,44037417.54,1369322.19,,,,,60277.71,,105152.64,-2936036.31,-139818.35,54449902.77,45811914.81,-73924634.01,,149523226.67,,,,373399791.72,,,6726166.02,,,424840908.0,51441116.28,,,1
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,142730777.95,109701423.08,3040791932.81,47894804.22,,,,,,,,,,,,146816874.74,3235503611.77,2695959985.17,159385513.12,114526261.24,,,,,,93794652.22,3063666411.75,171837200.02,,,,700100.0,,700100.0,585823275.12,3351250.0,,,,589174525.12,-588474425.12,2010000000.0,,,2629020646.88,-898419626.99,1410000000.0,98377100.83,1500000.0,817490966.8,2325868067.63,303152579.25,414486.41,-113070159.44,164511275.72,51441116.28,619020646.88,1500000.0,,56817227.81,115728870.72,5468793.63,,,,947653.98,277706.17,,328364.56,-13660703.3,26175.5,673471548.37,168818580.04,-1077151762.53,,171837200.02,,,,-113070159.44,,,-11667455.96,,,51441116.28,164511275.72,,,1
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,142730777.95,109701423.08,3040791932.81,47894804.22,,,,,,,,,,,,146816874.74,3235503611.77,2695959985.17,159385513.12,114526261.24,,,,,,93794652.22,3063666411.75,171837200.02,,,,700100.0,,700100.0,585823275.12,3351250.0,,,,589174525.12,-588474425.12,2010000000.0,,,2629020646.88,-898419626.99,1410000000.0,98377100.83,1500000.0,817490966.8,2325868067.63,303152579.25,414486.41,-113070159.44,164511275.72,51441116.28,619020646.88,1500000.0,,56817227.81,115728870.72,5468793.63,,,,947653.98,277706.17,,328364.56,-13660703.3,26175.5,673471548.37,168818580.04,-1077151762.53,,171837200.02,,,,-113070159.44,,,-11667455.96,,,51441116.28,164511275.72,,,0
|
|
||||||
688778.SH,20210719,20210719,20181231,1,1,4,81739174.49,107387619.4,3939876897.35,77722200.03,,,,,,,,,,,,71244859.79,4088843957.17,3579388258.84,126126437.64,116039626.06,,,,,,155793840.51,3977348163.05,111495794.12,,,,,,,612866302.48,,,,,612866302.48,-612866302.48,1360000000.0,,25000000.0,1385000000.0,-612499543.8517,390000000.0,90487021.18,,349213930.05,829700951.23,555299048.77,1066799.85,54995340.26,109515935.46,164511275.72,,,,86581336.59,59692527.17,3072435.6,,,,179084.16,2673930.2,,,-27153629.11,5161758.34,-423476503.79,-566777902.54,784798463.15,,111495794.12,,,,54995340.26,,,,,,164511275.72,109515935.46,,,1
|
|
||||||
688778.SH,20200804,20200804,20171231,1,1,4,173472703.48,43195626.13,696989047.96,39881179.35,,,,,,,,,,,,75229883.77,812100111.08,1182879736.74,84937048.79,44988451.94,,,,,,93161590.8,1405966828.27,-593866717.19,,,,1000.0,,1000.0,379211287.96,,,,,379211287.96,-379210287.96,394000000.0,,692679496.4,1118400267.81,,,34723437.49,,,34723437.49,1083676830.32,-3487725.97,107112099.2,2403836.26,109515935.46,31720771.41,,,15532866.58,45939419.29,1527445.75,,,,3665.64,12844474.24,,,-8147227.81,,-914766546.86,-1174467142.59,1210058639.19,,-593866717.19,,,,107112099.2,,,,,,109515935.46,2403836.26,,,1
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
end_date,ex_date,div_proc,cash_div
|
|
||||||
20250630,,预案,0.0
|
|
||||||
20250630,,股东大会通过,0.0
|
|
||||||
20250630,20250910,实施,0.2
|
|
||||||
20241231,,预案,0.0
|
|
||||||
20241231,,股东大会通过,0.0
|
|
||||||
20241231,20250703,实施,0.4
|
|
||||||
20240630,,预案,0.0
|
|
||||||
20231231,,预案,0.0
|
|
||||||
20231231,,股东大会通过,0.0
|
|
||||||
20231231,20240614,实施,0.7
|
|
||||||
20230630,,预案,0.0
|
|
||||||
20221231,,预案,0.0
|
|
||||||
20221231,,股东大会通过,0.0
|
|
||||||
20221231,20230606,实施,0.5
|
|
||||||
20220630,,预案,0.0
|
|
||||||
20211231,,预案,0.0
|
|
||||||
20211231,,股东大会通过,0.0
|
|
||||||
20211231,20220523,实施,0.5
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
688778.SH,20250821,20250630,14720
|
|
||||||
688778.SH,20250426,20250331,14235
|
|
||||||
688778.SH,20250426,20241231,14740
|
|
||||||
688778.SH,20241026,20240930,13770
|
|
||||||
688778.SH,20240803,20240630,14169
|
|
||||||
688778.SH,20240418,20240331,13613
|
|
||||||
688778.SH,20240418,20231231,13732
|
|
||||||
688778.SH,20231025,20230930,13957
|
|
||||||
688778.SH,20230825,20230630,15024
|
|
||||||
688778.SH,20230422,20230331,16033
|
|
||||||
688778.SH,20230422,20221231,14462
|
|
||||||
688778.SH,20221027,20220930,11115
|
|
||||||
688778.SH,20220728,20220630,12073
|
|
||||||
688778.SH,20220427,20220331,14159
|
|
||||||
688778.SH,20220331,20220228,15105
|
|
||||||
688778.SH,20220331,20211231,15688
|
|
||||||
688778.SH,20211029,20210930,15837
|
|
||||||
688778.SH,20210804,20210805,51601
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
ts_code,ann_date,f_ann_date,end_date,report_type,comp_type,end_type,basic_eps,diluted_eps,total_revenue,revenue,int_income,prem_earned,comm_income,n_commis_income,n_oth_income,n_oth_b_income,prem_income,out_prem,une_prem_reser,reins_income,n_sec_tb_income,n_sec_uw_income,n_asset_mg_income,oth_b_income,fv_value_chg_gain,invest_income,ass_invest_income,forex_gain,total_cogs,oper_cost,int_exp,comm_exp,biz_tax_surchg,sell_exp,admin_exp,fin_exp,assets_impair_loss,prem_refund,compens_payout,reser_insur_liab,div_payt,reins_exp,oper_exp,compens_payout_refu,insur_reser_refu,reins_cost_refund,other_bus_cost,operate_profit,non_oper_income,non_oper_exp,nca_disploss,total_profit,income_tax,n_income,n_income_attr_p,minority_gain,oth_compr_income,t_compr_income,compr_inc_attr_p,compr_inc_attr_m_s,ebit,ebitda,insurance_exp,undist_profit,distable_profit,rd_exp,fin_exp_int_exp,fin_exp_int_inc,transfer_surplus_rese,transfer_housing_imprest,transfer_oth,adj_lossgain,withdra_legal_surplus,withdra_legal_pubfund,withdra_biz_devfund,withdra_rese_fund,withdra_oth_ersu,workers_welfare,distr_profit_shrhder,prfshare_payable_dvd,comshare_payable_dvd,capit_comstock_div,continued_net_profit,update_flag
|
|
||||||
688778.SH,20251025,20251025,20250930,1,1,3,1.1,1.1,13059219222.37,13059219222.37,,,,,,,,,,,,,,,4521696.64,-29919515.1,-3140850.45,,12443937874.6,11753569900.62,,,59882045.95,32215296.78,154605972.9,5831187.58,1215491.3,,,,,,,,,,,616846615.68,985356.14,5519043.5,,612312928.32,56903666.57,555409261.75,552209641.93,3199619.82,43864537.17,599273798.92,586653445.71,12620353.21,646846254.43,,,,,390248834.07,12494954.91,14377717.66,,,,,,,,,,,,,,,555409261.75,1
|
|
||||||
688778.SH,20250821,20250821,20250630,1,1,2,0.61,0.61,7533703523.34,7533703523.34,,,,,,,,,,,,,,,4053631.27,-17917613.43,-3346171.4,,7196593679.48,6780836288.83,,,29651297.4,19200405.52,97500118.71,847932.23,-8969614.42,,,,,,,,,,,340857178.66,431249.75,2227565.36,,339060863.05,33176242.96,305884620.09,306894646.16,-1010026.07,45049252.67,350933872.76,341921267.25,9012605.51,355569093.05,570509120.81,,,,243443638.33,9421000.05,9130042.27,,,,,,,,,,,,,,,305884620.09,1
|
|
||||||
688778.SH,20250426,20250426,20250331,1,1,1,0.28,0.28,2976556152.31,2976556152.31,,,,,,,,,,,,,,,1837712.01,-10525414.68,-1349679.39,,2852536451.49,2691238415.53,,,8196032.92,8128842.91,41470295.68,1788914.6,-31441154.52,,,,,,,,,,,125191607.56,241280.02,1718058.13,,123714829.45,9120051.36,114594778.09,116678997.2,-2084219.11,15052857.49,129647635.58,128432300.7,1215334.88,167109379.35,,,,,98564879.76,5818391.23,4505644.53,,,,,,,,,,,,,,,114594778.09,1
|
|
||||||
688778.SH,20250426,20250426,20250331,1,1,1,0.28,0.28,2976556152.31,2976556152.31,,,,,,,,,,,,,,,1837712.01,-10525414.68,-1349679.39,,2852536451.49,2691238415.53,,,8196032.92,8128842.91,41470295.68,1788914.6,-31441154.52,,,,,,,,,,,125191607.56,241280.02,1718058.13,,123714829.45,9120051.36,114594778.09,116678997.2,-2084219.11,15052857.49,129647635.58,128432300.7,1215334.88,,,,,,98564879.76,5818391.23,4505644.53,,,,,,,,,,,,,,,114594778.09,0
|
|
||||||
688778.SH,20250426,20250426,20241231,1,1,4,1.18,1.18,13296790264.71,13296790264.71,,,,,,,,,,,,,,,7518003.31,-18178379.54,957802.35,,12840071241.11,11999431892.69,,,31179013.8,41624947.13,188447421.39,26835407.2,-194158465.59,,,,,,,,,,,513233262.76,749203.69,6115103.56,,507867362.89,19546244.75,488321118.14,494073837.67,-5752719.53,-16050545.32,472270572.82,479537522.33,-7266949.51,550729046.19,944038145.5,,,,418721301.81,45037590.5,24588099.68,,,,,,,,,,,,,,,488321118.14,0
|
|
||||||
688778.SH,20241026,20241026,20240930,1,1,3,0.87,0.87,9882356287.35,9882356287.35,,,,,,,,,,,,,,,5402083.34,-13599406.03,2811195.6,,9509943428.77,8927906003.07,,,22284593.05,28786387.86,139425671.46,24918733.87,-88239523.75,,,,,,,,,,,387322057.35,462932.58,1694976.48,,386090013.45,21857960.71,364232052.74,367491385.43,-3259332.69,1177973.22,365410025.96,369147757.84,-3737731.88,508677637.66,,,,,312017035.2,37060275.25,19159713.82,,,,,,,,,,,,,,,364232052.74,1
|
|
||||||
688778.SH,20240803,20240803,20240630,1,1,2,0.57,0.57,6300137327.3,6300137327.3,,,,,,,,,,,,,,,3540044.35,-4413115.89,3426233.74,,6069644151.03,5700840306.84,,,15512878.49,17632543.37,88227435.27,20252240.0,-60538331.13,,,,,,,,,,,246442124.91,361657.32,417235.01,,246386547.22,7950519.64,238436027.58,239090203.7,-654176.12,-2234271.12,236201756.46,236875242.73,-673486.27,267567436.45,463585717.3,,,,207480857.71,30871874.19,12819576.84,,,,,,,,,,,,,,,238436027.58,1
|
|
||||||
688778.SH,20240418,20240418,20240331,1,1,1,0.26,0.26,3298786656.17,3298786656.17,,,,,,,,,,,,,,,1709974.24,4870126.19,3544562.46,,3198041938.57,3048187873.72,,,7782995.02,7550555.76,39681438.87,17761661.05,-21314991.97,,,,,,,,,,,114167501.78,137207.99,301370.45,,114003339.32,3419047.02,110584292.3,111288715.41,-704423.11,-4257903.91,106326388.39,107060843.86,-734455.47,146664054.37,,,,,87222232.61,23028065.1,5634227.66,,,,,,,,,,,,,,,110584292.3,1
|
|
||||||
688778.SH,20240418,20240418,20231231,1,1,4,1.25,1.25,17310873278.22,17310873278.22,,,,,,,,,,,,,,,4163210.94,7107457.5,2206828.55,,16845200569.28,15927192080.98,,,38942909.63,32893039.02,192374622.46,87143460.63,-178565661.45,,,,,,,,,,,560381772.08,4476840.99,6275201.24,,558583411.83,29091634.68,529491777.15,527454540.65,2037236.5,3933852.36,533425629.51,531253975.01,2171654.5,636254564.27,1004822510.41,,,,464606608.1,124085924.0,22036950.98,,,,,,,,,,,,,,,529491777.15,1
|
|
||||||
688778.SH,20231025,20231025,20230930,1,1,3,0.98,0.98,13122438075.54,13122438075.54,,,,,,,,,,,,,,,,10648968.74,4733402.69,,12731085161.03,12076406317.17,,,31272142.15,23316503.46,147379271.87,69749655.81,-133917162.14,,,,,,,,,,,450715332.87,766569.98,3194955.02,,448286947.83,35041452.11,413245495.72,412394970.29,850525.43,-59933.3,413185562.42,412370442.34,815120.08,643733182.08,,,,,323985176.47,102585163.92,17120687.96,,,,,,,,,,,,,,,413245495.72,1
|
|
||||||
688778.SH,20230825,20230825,20230630,1,1,2,0.61,0.61,8121442070.41,8121442070.41,,,,,,,,,,,,,,,,9631902.28,5531379.34,,7885658838.0,7500105744.27,,,14938864.83,13714727.11,95553232.09,47458583.57,-95487727.3,,,,,,,,,,,275689224.48,428519.76,2179719.63,,273938024.61,18671952.99,255266071.62,254665548.07,600523.55,368473.14,255634544.76,255111995.11,522549.65,313515905.77,496001034.51,,,,221948507.06,74105037.35,10993321.04,,,,,,,,,,,,,,,255266071.62,1
|
|
||||||
688778.SH,20230422,20230422,20230331,1,1,1,0.38,0.38,3586248672.17,3586248672.17,,,,,,,,,,,,,,,,7871431.72,5905351.65,,3492423800.01,3322413069.52,,,6138355.21,5773097.82,44537519.0,48161420.23,-54803245.67,,,,,,,,,,,120903547.35,209354.24,715224.35,,120397677.24,4577567.7,115820109.54,115573100.93,247008.61,-3689888.22,112130221.32,112530409.0,-400187.68,215996781.53,,,,,111418932.76,44600635.11,4520314.34,,,,,,,,,,,,,,,115820109.54,1
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,4.18,4.18,28751311102.65,28751311102.65,,,,,,,,,,,,,,,,5499341.74,264507.77,,27637697815.06,26277854884.2,,,37137235.62,26323805.64,154979228.63,131922386.44,-149808467.88,,,,,,,,,,,1239753004.76,6242750.3,5281526.07,,1240714228.99,110833713.4,1129880515.59,1120551568.79,9328946.8,-4772037.56,1125108478.03,1115817324.0,9291154.03,1366171513.96,1671936156.9,,,,757310248.22,141835209.11,15185289.59,,,,,,,,,,,,,,,1129880515.59,1
|
|
||||||
688778.SH,20230422,20230422,20221231,1,1,4,4.18,4.18,28751311102.65,28751311102.65,,,,,,,,,,,,,,,,5499341.74,264507.77,,27637697815.06,26277854884.2,,,37137235.62,26323805.64,154979228.63,131922386.44,-149808467.88,,,,,,,,,,,1239753004.76,6242750.3,5281526.07,,1240714228.99,110833713.4,1129880515.59,1120551568.79,9328946.8,-4772037.56,1125108478.03,1115817324.0,9291154.03,1366171513.96,1671936156.9,,,,757310248.22,141835209.11,15185289.59,,,,,,,,,,,,,,,1129880515.59,0
|
|
||||||
688778.SH,20221027,20221027,20220930,1,1,3,3.34,3.34,22029709889.61,22029709889.61,,,,,,,,,,,,,,,,5186965.41,3251813.2,,21173438909.88,20107565483.27,,,28740529.62,18044139.6,131223782.74,101694254.07,-103309693.13,,,,,,,,,,,956477630.69,5936254.04,2288435.68,,960125449.05,94226888.45,865898560.6,858959975.06,6938585.54,-5572391.73,860326168.87,853406786.53,6919382.34,1156294612.48,,,,,571350640.05,101661763.76,8890796.42,,,,,,,,,,,,,,,865898560.6,1
|
|
||||||
688778.SH,20220728,20220728,20220630,1,1,2,2.12,2.12,14302469281.01,14302469281.01,,,,,,,,,,,,,,,,1935152.21,,,13802190481.97,13050176610.4,,,18578960.7,12425928.08,84378213.8,64429670.32,-81999385.13,,,,,,,,,,,587374771.8,5226089.77,1846187.33,,590754674.24,53691402.82,537063271.42,532408438.56,4654832.86,-3756561.75,533306709.67,528536736.19,4769973.48,649869289.91,792055346.59,,,,407354639.78,62117252.75,3857630.11,,,,,,,,,,,,,,,537063271.42,1
|
|
||||||
688778.SH,20220427,20220427,20220331,1,1,1,0.82,0.82,5909071678.49,5909071678.49,,,,,,,,,,,,,,,,1580152.21,,,5750859436.15,5403156385.18,,,10051753.73,6571456.67,37247717.2,41511683.14,-36048489.89,,,,,,,,,,,229558174.47,239630.61,310405.18,,229487399.9,20773664.33,208713735.57,206898625.84,1815109.73,-3587549.04,205126186.53,203195936.18,1930250.35,,,,,,190926100.49,33868695.73,1460870.05,,,,,,,,,,,,,,,208713735.57,0
|
|
||||||
688778.SH,20220427,20220427,20220331,1,1,1,0.82,0.82,5909071678.49,5909071678.49,,,,,,,,,,,,,,,,1580152.21,,,5750859436.15,5403156385.18,,,10051753.73,6571456.67,37247717.2,41511683.14,-36048489.89,,,,,,,,,,,229558174.47,239630.61,310405.18,,229487399.9,20773664.33,208713735.57,206898625.84,1815109.73,-3587549.04,205126186.53,203195936.18,1930250.35,305538195.29,,,,,190926100.49,33868695.73,1460870.05,,,,,,,,,,,,,,,208713735.57,1
|
|
||||||
688778.SH,20220331,20220331,20211231,1,1,4,2.65,2.65,15565760243.3,15565760243.3,,,,,,,,,,,,,,,,11210471.23,,,15006701336.84,14079277712.97,,,22554439.1,29086596.76,130506869.16,127942914.23,-74960397.3,,,,,,,,,,,617522672.64,1514878.73,6139580.26,,612897971.11,44760479.95,568137491.16,555349247.43,12788243.73,1523027.64,569660518.8,556849390.21,12811128.59,734255115.64,975052801.75,,,,451858021.23,118562305.87,4276772.64,,,,,,,,,,,,,,,568137491.16,1
|
|
||||||
688778.SH,20220331,20220331,20211231,1,1,4,2.65,2.65,15565760243.3,15565760243.3,,,,,,,,,,,,,,,,11210471.23,,,15006701336.84,14079277712.97,,,22554439.1,29086596.76,130506869.16,127942914.23,-74960397.3,,,,,,,,,,,617522672.64,1514878.73,6139580.26,,612897971.11,44760479.95,568137491.16,555349247.43,12788243.73,1523027.64,569660518.8,556849390.21,12811128.59,734255115.64,975052801.75,,,,451858021.23,118562305.87,4276772.64,,,,,,,,,,,,,,,568137491.16,0
|
|
||||||
688778.SH,20211029,20211029,20210930,1,1,3,2.04,2.04,10312502889.64,10312502889.64,,,,,,,,,,,,,,,,10184173.5,,,9896621546.25,9327357015.05,,,15143706.3,20985936.4,81410662.51,104734314.87,-31167876.97,,,,,,,,,,,448080105.54,1231277.72,4389750.7,,444921632.56,35239869.2,409681763.36,398994123.22,10687640.14,-1488618.53,408193144.83,397544323.97,10648820.86,573798123.88,,,,,282032486.4,93624540.21,1623216.97,,,,,,,,,,,,,,,409681763.36,1
|
|
||||||
688778.SH,20211029,20211029,20210930,1,1,3,2.04,2.04,10312502889.64,10312502889.64,,,,,,,,,,,,,,,,10184173.5,,,9896621546.25,9327357015.05,,,15143706.3,20985936.4,81410662.51,104734314.87,-31167876.97,,,,,,,,,,,448080105.54,1231277.72,4389750.7,,444921632.56,35239869.2,409681763.36,398994123.22,10687640.14,-1488618.53,408193144.83,397544323.97,10648820.86,,,,,,282032486.4,93624540.21,1623216.97,,,,,,,,,,,,,,,409681763.36,0
|
|
||||||
688778.SH,20210804,20210804,20210630,1,1,2,1.33,,6568279577.46,6568279577.46,,,,,,,,,,,,,,,,10184173.5,,,6312127107.7,5962589610.23,,,9072241.32,12350347.06,48610080.12,73383429.82,-12524122.4,,,,,,,,,,,281848483.28,397976.25,1905037.56,,280341421.97,22309576.77,258031845.2,250910527.11,7121318.09,474515.75,258506360.95,251481601.22,7024759.73,357571862.0,357571862.0,,,,163670425.6,64247116.51,300749.07,,,,,,,,,,,,,,,258031845.2,1
|
|
||||||
688778.SH,20210719,20210719,20210331,1,1,1,0.59,,2906106622.87,2906106622.87,,,,,,,,,,,,,,,,,,,2783258567.59,2625484047.75,,,4371880.3,4945109.56,21706766.76,39286923.12,-3500772.42,,,,,,,,,,,130514297.2,234244.86,1769384.24,,128979157.82,14567631.73,114411526.09,111794785.01,2616741.08,-3822200.06,110589326.03,108332655.78,2256670.25,173301992.74,,,,,76930738.55,33365086.87,156655.54,,,,,,,,,,,,,,,114411526.09,1
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,1.36,1.36,7989637657.15,7989637657.15,,,,,,,,,,,,,,,,1103388.89,1103388.89,,7739340040.17,7152011262.31,,,13642510.77,26681430.66,89978009.11,118211933.36,-47360230.97,,,,,,,,,,,277838341.51,2787877.09,17935821.34,,262690397.26,11053060.06,251637337.2,250546071.8,1091265.4,1015119.22,252652456.42,251322956.32,1329500.1,395424580.18,591984882.18,,,,261183953.93,105930283.21,877589.17,,,,,,,,,,,,,,,251637337.2,0
|
|
||||||
688778.SH,20210719,20210719,20201231,1,1,4,1.36,1.36,7989637657.15,7989637657.15,,,,,,,,,,,,,,,,1103388.89,1103388.89,,7739340040.17,7152011262.31,,,13642510.77,26681430.66,89978009.11,118211933.36,-47360230.97,,,,,,,,,,,277838341.51,2787877.09,17935821.34,,262690397.26,11053060.06,251637337.2,250546071.8,1091265.4,1015119.22,252652456.42,251322956.32,1329500.1,395424580.18,591984882.18,,,,261183953.93,105930283.21,877589.17,,,,,,,,,,,,,,,251637337.2,1
|
|
||||||
688778.SH,20211029,20211029,20200930,1,1,3,0.86,0.86,5192989697.18,5192989697.18,,,,,,,,,,,,,,,,1103388.89,1103388.89,,5039601306.43,4635943996.2,,,7868277.54,33134028.93,60291289.56,78396945.07,-37794325.61,,,,,,,,,,,174898379.91,2534951.91,12748527.53,,164684804.29,11222977.6,153461826.69,156081587.4,-2619760.71,2386333.6,155848160.29,158179649.95,-2331489.66,214221439.2,,,,,161593490.02,76355258.83,578910.89,,,,,,,,,,,,,,,153461826.69,1
|
|
||||||
688778.SH,20211029,20211029,20200930,1,1,3,0.86,0.86,5192989697.18,5192989697.18,,,,,,,,,,,,,,,,1103388.89,1103388.89,,5039601306.43,4635943996.2,,,7868277.54,33134028.93,60291289.56,78396945.07,-37794325.61,,,,,,,,,,,174898379.91,2534951.91,12748527.53,,164684804.29,11222977.6,153461826.69,156081587.4,-2619760.71,2386333.6,155848160.29,158179649.95,-2331489.66,214221439.2,,,,,161593490.02,76355258.83,578910.89,,,,,,,,,,,,,,,153461826.69,0
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,0.53,0.53,3072183824.06,3072183824.06,,,,,,,,,,,,,,,,1103388.89,1103388.89,,2980363045.66,2745827826.3,,,4887532.2,19453973.96,39900660.81,47993542.89,-27930393.28,,,,,,,,,,,103990246.84,2178279.91,12665587.48,,93502939.27,1252515.64,92250423.63,95347209.52,-3096785.89,1289740.97,93540164.6,96313429.53,-2773264.93,178822319.56,270561010.61,,,,100396458.49,49247139.31,473870.81,,,,,,,,,,,,,,,92250423.63,0
|
|
||||||
688778.SH,20200804,20200804,20200630,1,1,2,0.53,0.53,3072183824.06,3072183824.06,,,,,,,,,,,,,,,,1103388.89,1103388.89,,2980363045.66,2745827826.3,,,4887532.2,19453973.96,39900660.81,47993542.89,-27930393.28,,,,,,,,,,,103990246.84,2178279.91,12665587.48,,93502939.27,1252515.64,92250423.63,95347209.52,-3096785.89,1289740.97,93540164.6,96313429.53,-2773264.93,178822319.56,270561010.61,,,,100396458.49,49247139.31,473870.81,,,,,,,,,,,,,,,92250423.63,1
|
|
||||||
688778.SH,20210719,20210719,20200331,1,1,1,0.22,,1449523648.26,1449523648.26,,,,,,,,,,,,,,,,-105152.64,-105152.64,,1412815859.58,1304497378.77,,,2226295.88,5324302.0,17619252.13,25699975.15,-14706127.52,,,,,,,,,,,41519783.29,255090.0,8057289.24,,33717584.05,-864482.76,34582066.81,36891273.24,-2309206.43,1824526.41,36406593.22,38339539.48,-1932946.26,,,,,,36016362.11,25589544.75,361239.87,,,,,,,,,,,,,,,34582066.81,1
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,1.07,1.07,6977723911.27,6977723911.27,,,,,,,,,,,,,,,,-328364.56,-328364.56,,6949478021.0,6415517218.05,,,11278121.99,40139061.23,78228468.49,113738891.83,-56817227.81,,,,,,,,,,,109347502.44,3897973.11,311291.34,,112934184.21,-29796593.74,142730777.95,150080974.56,-7350196.61,-3080485.67,139650292.28,147376749.06,-7726456.78,224362412.81,345560077.16,,,,245426487.56,111688425.83,209613.46,,,,,,,,,,,,,,,142730777.95,1
|
|
||||||
688778.SH,20210719,20210719,20191231,1,1,4,1.07,1.07,6977723911.27,6977723911.27,,,,,,,,,,,,,,,,-328364.56,-328364.56,,6949478021.0,6415517218.05,,,11278121.99,40139061.23,78228468.49,113738891.83,-56817227.81,,,,,,,,,,,109347502.44,3897973.11,311291.34,,112934184.21,-29796593.74,142730777.95,150080974.56,-7350196.61,-3080485.67,139650292.28,147376749.06,-7726456.78,224362412.81,345560077.16,,,,245426487.56,111688425.83,209613.46,,,,,,,,,,,,,,,142730777.95,0
|
|
||||||
688778.SH,20190823,20190823,20190630,1,1,2,,,3295176800.0,3295176800.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3295176800.0,3295176800.0,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20190823,20190823,20190630,1,1,2,,,3295176800.0,3295176800.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3295176800.0,3295176800.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20210719,20210719,20181231,1,1,4,0.8,0.8,7026350478.8,7026350478.8,,,,,,,,,,,,,,,,,,,6949299320.52,6317152631.06,,,9637821.28,25969674.13,64515505.18,113097542.1,86581336.59,,,,,,,,,,,84593052.85,2345948.29,2881102.44,,84057898.7,2318724.21,81739174.49,80106100.11,1633074.38,,81739174.49,80106100.11,1633074.38,197869679.11,260634641.88,,,,332344810.18,118242552.26,295348.44,,,,,,,,,,,,,,,81739174.49,1
|
|
||||||
688778.SH,20190312,20190312,20180630,1,1,2,,,3267087500.0,3267087500.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67280800.0,,,,,,3267087500.0,3267087500.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20190312,20190312,20180630,1,1,2,,,3267087500.0,3267087500.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67280800.0,,,,,,3267087500.0,3267087500.0,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20200804,20200804,20171231,1,1,4,1.66,1.66,4211441780.41,4211441780.41,,,,,,,,,,,,,,,,,,,3980692154.25,3676771458.96,,,5701299.91,21269980.48,46501604.8,42322531.89,15532866.58,,,,,,,,,,,250579370.75,630155.16,12861664.98,,238347860.93,64875157.45,173472703.48,166057247.41,7415456.07,,173472703.48,166057247.41,7415456.07,308438434.86,355905299.9,,,,172592411.63,36818044.49,1595553.95,,,,,,,,,,,,,,,173472703.48,1
|
|
||||||
688778.SH,20170810,20170810,20170630,1,1,2,,,1676006100.0,1676006100.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,115435300.0,,,,,,1676006100.0,1676006100.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
688778.SH,20170810,20170810,20170630,1,1,2,,,1676006100.0,1676006100.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,115435300.0,,,,,,1676006100.0,1676006100.0,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20170427,20170427,20161231,1,1,4,,,0.0,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0.0,,,,,,0.0,0.0,,,,,,,,,,,,,,,,,,,,,,1
|
|
||||||
688778.SH,20170427,20170427,20161231,1,1,4,,,0.0,0.0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0.0,,,,,,0.0,0.0,,,,,,,,,,,,,,,,,,,,,,0
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,trade_date,close,turnover_rate,turnover_rate_f,volume_ratio,pe,pe_ttm,pb,ps,ps_ttm,dv_ratio,dv_ttm,total_share,float_share,free_share,total_mv,circ_mv
|
|
||||||
688778.SH,20251231,77.37,1.3395,3.8637,1.24,79.0326,57.5256,4.3344,2.9366,2.3703,,,50469.1083,50469.1083,17496.7565,3904794.9092,3904794.9092
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,holder_num
|
|
||||||
688778.SH,20251025,20250930,24627
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
name,list_date
|
|
||||||
厦钨新能,20210805
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
ts_code,ann_date,end_date,proc,exp_date,vol,amount,high_limit,low_limit
|
|
||||||
688778.SH,20250227,20250227,完成,,1170589.0,40678183.98,42.46,31.26
|
|
||||||
688778.SH,20250206,20250131,实施,,1170589.0,40678183.98,42.46,31.26
|
|
||||||
688778.SH,20240801,20240731,实施,,1049834.0,35683821.52,35.81,31.26
|
|
||||||
688778.SH,20240615,,预案,,,50000000.0,50.3,
|
|
||||||
688778.SH,20240402,20240331,实施,,890978.0,30684586.97,35.81,33.22
|
|
||||||
688778.SH,20240302,20240301,实施,,129640.0,4585614.53,35.81,35.01
|
|
||||||
688778.SH,20240228,,预案,,,50000000.0,51.0,
|
|
||||||
688778.SH,20231221,,提议,,,50000000.0,,
|
|
||||||
|
@ -1,445 +0,0 @@
|
|||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>688778.SH Financial Report</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f6fa;
|
|
||||||
--card-bg: #ffffff;
|
|
||||||
--header-bg: #f7f8fb;
|
|
||||||
--section-bg: #f0f2f5;
|
|
||||||
--border: #e5e7eb;
|
|
||||||
--text-primary: #111827;
|
|
||||||
--text-secondary: #6b7280;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 32px;
|
|
||||||
background: var(--bg);
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
color: var(--text-primary);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-container {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 32px 40px;
|
|
||||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 24px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: var(--card-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-align: right;
|
|
||||||
background: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:first-child,
|
|
||||||
td:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.company-table th,
|
|
||||||
.company-table td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
background: var(--card-bg);
|
|
||||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th:first-child {
|
|
||||||
left: 0;
|
|
||||||
z-index: 4;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table th:first-child,
|
|
||||||
.metrics-table td:first-child {
|
|
||||||
width: 180px;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
background: var(--card-bg);
|
|
||||||
font-weight: 600;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.04);
|
|
||||||
z-index: 2;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:not(:first-child) {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td:first-child {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody tr:hover td {
|
|
||||||
background: #f4efff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-row td {
|
|
||||||
background: #eef1f6;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-row td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-label {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-spacer {
|
|
||||||
background: #eef1f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-name {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container table {
|
|
||||||
margin-bottom: 0;
|
|
||||||
min-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-gap {
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data {
|
|
||||||
margin-top: 24px;
|
|
||||||
padding: 32px;
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-green { background-color: #e6f7eb !important; }
|
|
||||||
.bg-red { background-color: #ffeef0 !important; }
|
|
||||||
.font-red { color: #d32f2f !important; }
|
|
||||||
.font-green { color: #1b873f !important; }
|
|
||||||
.font-blue { color: #2563eb !important; }
|
|
||||||
.italic { font-style: italic !important; }
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body { padding: 16px; }
|
|
||||||
.report-container { padding: 24px; }
|
|
||||||
table { font-size: 0.85rem; }
|
|
||||||
th,
|
|
||||||
td { padding: 10px 12px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="report-container">
|
|
||||||
<h1>厦钨新能 (688778.SH) - Financial Report</h1>
|
|
||||||
<p><em>Report generated on: 2026-01-03</em></p>
|
|
||||||
|
|
||||||
<table class="company-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>代码</th>
|
|
||||||
<th>简称</th>
|
|
||||||
<th>上市日期</th>
|
|
||||||
<th>PE</th>
|
|
||||||
<th>PB</th>
|
|
||||||
<th>股息率(%)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>688778.SH</td>
|
|
||||||
<td>厦钨新能</td>
|
|
||||||
<td>2021-08-05</td>
|
|
||||||
<td>79.03</td>
|
|
||||||
<td>4.33</td>
|
|
||||||
<td>0.00%</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="table-gap"></div>
|
|
||||||
|
|
||||||
<table class="metrics-table" data-table="metrics" data-scrollable="true">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>指标</th>
|
|
||||||
<th>2025Q3</th><th>2024A</th><th>2023A</th><th>2022A</th><th>2021A</th><th>2020A</th><th>2019A</th><th>2018A</th><th>2017A</th><th>2016A</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="section-row"><td class="section-label">主要指标</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">ROE</td><td>6.13%</td><td>5.65%</td><td>6.15%</td><td>13.67%</td><td>14.87%</td><td>14.33%</td><td>9.93%</td><td>10.73%</td><td>24.90%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROA</td><td>3.17%</td><td>3.35%</td><td>3.91%</td><td>7.29%</td><td>5.28%</td><td>4.03%</td><td>2.81%</td><td>1.44%</td><td>4.40%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROCE/ROIC</td><td>6.71%</td><td>5.83%</td><td>6.83%</td><td>13.99%</td><td>13.65%</td><td>9.48%</td><td>6.43%</td><td>9.16%</td><td>29.07%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">毛利率</td><td>10.00%</td><td>9.76%</td><td>7.99%</td><td>8.60%</td><td>9.55%</td><td>10.48%</td><td>8.06%</td><td>10.09%</td><td>12.70%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润率</td><td>4.23%</td><td>3.72%</td><td>3.05%</td><td>3.90%</td><td>3.57%</td><td>3.14%</td><td>2.15%</td><td>1.14%</td><td>3.94%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">收入(亿)</td><td>130.59</td><td>132.97</td><td>173.11</td><td>287.51</td><td>155.66</td><td>79.90</td><td>69.78</td><td>70.26</td><td>42.11</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">收入增速</td><td>32.15%</td><td>-23.19%</td><td>-39.79%</td><td>84.71%</td><td>94.82%</td><td>14.50%</td><td>-0.69%</td><td>66.84%</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润(亿)</td><td>5.52</td><td>4.94</td><td>5.27</td><td>11.21</td><td>5.55</td><td>2.51</td><td>1.50</td><td>0.80</td><td>1.66</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润增速</td><td>50.26%</td><td>-6.33%</td><td>-52.93%</td><td>101.77%</td><td>121.66%</td><td>66.94%</td><td>87.35%</td><td>-51.76%</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">经营净现金流(亿)</td><td>8.97</td><td>17.53</td><td>25.80</td><td>-15.61</td><td>4.32</td><td>3.97</td><td>1.72</td><td>1.11</td><td>-5.94</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">资本开支(亿)</td><td>4.89</td><td>9.66</td><td>11.45</td><td>6.51</td><td>5.56</td><td>3.33</td><td>5.86</td><td>6.13</td><td>3.79</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">自由现金流(亿)</td><td>4.08</td><td>7.87</td><td>14.35</td><td>-22.12</td><td>-1.24</td><td>0.64</td><td>-4.14</td><td>-5.01</td><td>-9.73</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">分红(亿)</td><td>-</td><td>2.02</td><td>2.95</td><td>2.10</td><td>1.26</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">回购(亿)</td><td>-</td><td>1.71</td><td>0.50</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产(亿)</td><td>174.13</td><td>147.47</td><td>134.81</td><td>153.80</td><td>105.16</td><td>62.22</td><td>53.48</td><td>55.49</td><td>37.74</td><td>1.00</td></tr>
|
|
||||||
<tr><td class="metric-name">净资产(亿)</td><td>90.09</td><td>87.37</td><td>85.82</td><td>82.00</td><td>37.36</td><td>17.48</td><td>15.12</td><td>7.47</td><td>6.67</td><td>1.00</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉(亿)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">费用指标</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">销售费用率</td><td>0.25%</td><td>0.31%</td><td>0.19%</td><td>0.09%</td><td>0.19%</td><td>0.33%</td><td>0.58%</td><td>0.37%</td><td>0.51%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">管理费用率</td><td>1.18%</td><td>1.42%</td><td>1.11%</td><td>0.54%</td><td>0.84%</td><td>1.13%</td><td>1.12%</td><td>0.92%</td><td>1.10%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">SG&A比例</td><td>1.43%</td><td>1.73%</td><td>1.30%</td><td>0.63%</td><td>1.03%</td><td>1.46%</td><td>1.70%</td><td>1.29%</td><td>1.61%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">研发费用率</td><td>2.99%</td><td>3.15%</td><td>2.68%</td><td>2.63%</td><td>2.90%</td><td>3.27%</td><td>3.52%</td><td>4.73%</td><td>4.10%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">其他费用率</td><td>1.35%</td><td>1.16%</td><td>0.96%</td><td>1.44%</td><td>2.05%</td><td>2.62%</td><td>0.69%</td><td>2.94%</td><td>3.05%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">折旧费用占比</td><td>-</td><td>2.77%</td><td>2.02%</td><td>1.03%</td><td>1.50%</td><td>2.39%</td><td>1.66%</td><td>0.85%</td><td>1.09%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">所得税率</td><td>9.29%</td><td>3.85%</td><td>5.21%</td><td>8.93%</td><td>7.30%</td><td>4.21%</td><td>-26.38%</td><td>2.76%</td><td>27.22%</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">资产占比</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">现金占比</td><td>8.88%</td><td>11.09%</td><td>8.90%</td><td>6.61%</td><td>4.04%</td><td>4.47%</td><td>0.96%</td><td>2.96%</td><td>2.90%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">库存占比</td><td>26.24%</td><td>16.79%</td><td>14.57%</td><td>21.79%</td><td>26.58%</td><td>19.51%</td><td>16.08%</td><td>28.66%</td><td>32.68%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款占比</td><td>18.81%</td><td>15.92%</td><td>25.95%</td><td>32.22%</td><td>28.09%</td><td>19.84%</td><td>12.33%</td><td>15.88%</td><td>13.23%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">预付款占比</td><td>0.75%</td><td>0.08%</td><td>0.07%</td><td>0.11%</td><td>0.16%</td><td>1.25%</td><td>0.39%</td><td>6.20%</td><td>3.26%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产占比</td><td>-</td><td>23.88%</td><td>25.96%</td><td>23.65%</td><td>26.59%</td><td>38.24%</td><td>37.34%</td><td>19.47%</td><td>15.24%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">长期投资占比</td><td>2.39%</td><td>2.83%</td><td>2.95%</td><td>0.65%</td><td>-</td><td>0.07%</td><td>0.07%</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉占比</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="other-assets-row"><td class="metric-name">其他资产占比</td><td>42.94%</td><td>29.42%</td><td>21.60%</td><td>14.97%</td><td>14.54%</td><td>16.62%</td><td>32.82%</td><td>26.83%</td><td>32.70%</td><td>100.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款占比</td><td>17.61%</td><td>14.64%</td><td>16.87%</td><td>13.63%</td><td>33.13%</td><td>19.56%</td><td>16.47%</td><td>12.18%</td><td>15.49%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">预收款占比</td><td>0.88%</td><td>0.02%</td><td>0.03%</td><td>0.04%</td><td>0.10%</td><td>0.03%</td><td>0.05%</td><td>0.14%</td><td>0.36%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">短期借款占比</td><td>1.06%</td><td>1.60%</td><td>0.25%</td><td>4.53%</td><td>2.48%</td><td>20.67%</td><td>33.82%</td><td>23.62%</td><td>10.33%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期借款占比</td><td>2.57%</td><td>3.16%</td><td>5.23%</td><td>5.66%</td><td>13.15%</td><td>18.25%</td><td>3.12%</td><td>1.87%</td><td>0.11%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">运营资产占比</td><td>27.30%</td><td>18.13%</td><td>23.69%</td><td>40.46%</td><td>21.59%</td><td>21.02%</td><td>12.29%</td><td>38.41%</td><td>33.31%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">有息负债率</td><td>3.63%</td><td>4.76%</td><td>5.47%</td><td>10.19%</td><td>15.64%</td><td>38.92%</td><td>36.94%</td><td>25.49%</td><td>10.44%</td><td>0.00%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">周转能力</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">存货周转天数</td><td>141</td><td>75</td><td>45</td><td>46</td><td>72</td><td>61</td><td>48</td><td>91</td><td>122</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款周转天数</td><td>91</td><td>64</td><td>73</td><td>62</td><td>69</td><td>56</td><td>34</td><td>45</td><td>43</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款周转天数</td><td>95</td><td>65</td><td>52</td><td>29</td><td>90</td><td>62</td><td>50</td><td>39</td><td>58</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产周转率</td><td>-</td><td>3.78</td><td>4.95</td><td>7.91</td><td>5.57</td><td>3.36</td><td>3.49</td><td>6.50</td><td>7.32</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产周转率</td><td>0.75</td><td>0.90</td><td>1.28</td><td>1.87</td><td>1.48</td><td>1.28</td><td>1.30</td><td>1.27</td><td>1.12</td><td>0.00</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">人均效率</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">员工人数</td><td>-</td><td>3,344</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创收(万)</td><td>-</td><td>397.63</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创利(万)</td><td>-</td><td>14.77</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均薪酬(万)</td><td>-</td><td>15.29</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">市场表现</td><td class="section-spacer" colspan="10"></td></tr>
|
|
||||||
<tr><td class="metric-name">股价</td><td>77.37</td><td>45.64</td><td>39.64</td><td>77.68</td><td>103.35</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">市值(亿)</td><td>390.48</td><td>192.04</td><td>166.79</td><td>233.47</td><td>260.00</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PE</td><td>79.03</td><td>36.41</td><td>14.88</td><td>42.04</td><td>103.77</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">PB</td><td>4.33</td><td>2.23</td><td>1.97</td><td>2.93</td><td>7.27</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">股东户数</td><td>24,627</td><td>14,740</td><td>13,732</td><td>14,462</td><td>15,688</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const scrollableTables = document.querySelectorAll('table[data-scrollable="true"]');
|
|
||||||
scrollableTables.forEach(table => {
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'table-container';
|
|
||||||
table.parentNode.insertBefore(container, table);
|
|
||||||
container.appendChild(table);
|
|
||||||
});
|
|
||||||
|
|
||||||
const parseValue = (text) => {
|
|
||||||
if (!text || text.trim() === '-') return null;
|
|
||||||
return parseFloat(text.replace(/%|,/g, ''));
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightIfOverThirtyPercent = (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 30) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleRules = {
|
|
||||||
'ROE': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 15) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'ROA': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 10) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'毛利率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 50) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'净利润率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 20) {
|
|
||||||
cell.classList.add('bg-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'收入增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'净利润增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'经营净现金流(亿)': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value < 0) cell.classList.add('bg-red', 'font-red');
|
|
||||||
},
|
|
||||||
'应收款周转天数': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 90) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'现金占比': highlightIfOverThirtyPercent,
|
|
||||||
'库存占比': highlightIfOverThirtyPercent,
|
|
||||||
'应收款占比': highlightIfOverThirtyPercent,
|
|
||||||
'预付款占比': highlightIfOverThirtyPercent,
|
|
||||||
'固定资产占比': highlightIfOverThirtyPercent,
|
|
||||||
'长期投资占比': highlightIfOverThirtyPercent,
|
|
||||||
'商誉占比': highlightIfOverThirtyPercent,
|
|
||||||
'其他资产占比': highlightIfOverThirtyPercent
|
|
||||||
};
|
|
||||||
|
|
||||||
const metricsTables = document.querySelectorAll('table[data-table="metrics"]');
|
|
||||||
metricsTables.forEach(table => {
|
|
||||||
let netProfitValues = [];
|
|
||||||
let fcfRow = null;
|
|
||||||
const rows = table.querySelectorAll('tbody tr');
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
if (metricName === '净利润(亿)') {
|
|
||||||
row.querySelectorAll('td:not(:first-child)').forEach(cell => {
|
|
||||||
netProfitValues.push(parseValue(cell.textContent));
|
|
||||||
});
|
|
||||||
} else if (metricName === '自由现金流(亿)') {
|
|
||||||
fcfRow = row;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
const cells = row.querySelectorAll('td:not(:first-child)');
|
|
||||||
if (styleRules[metricName]) {
|
|
||||||
cells.forEach(cell => {
|
|
||||||
styleRules[metricName](cell);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (row === fcfRow && netProfitValues.length > 0) {
|
|
||||||
cells.forEach((cell, index) => {
|
|
||||||
const fcfValue = parseValue(cell.textContent);
|
|
||||||
const netProfitValue = netProfitValues[index];
|
|
||||||
if (fcfValue !== null) {
|
|
||||||
if (fcfValue < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else if (netProfitValue !== null && fcfValue > netProfitValue) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# 厦钨新能 (688778.SH) - Financial Report
|
|
||||||
*Report generated on: 2026-01-03*
|
|
||||||
|
|
||||||
| 代码 | 简称 | 上市日期 | PE | PB | 股息率(%) |
|
|
||||||
|:---|:---|:---|:---|:---|:---|
|
|
||||||
| 688778.SH | 厦钨新能 | 2021-08-05 | 79.03 | 4.33 | 0.00% |
|
|
||||||
|
|
||||||
|
|
||||||
## 主要指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| ROE | 6.13% | 5.65% | 6.15% | 13.67% | 14.87% | 14.33% | 9.93% | 10.73% | 24.90% | 0.00% |
|
|
||||||
| ROA | 3.17% | 3.35% | 3.91% | 7.29% | 5.28% | 4.03% | 2.81% | 1.44% | 4.40% | 0.00% |
|
|
||||||
| ROCE/ROIC | 6.71% | 5.83% | 6.83% | 13.99% | 13.65% | 9.48% | 6.43% | 9.16% | 29.07% | 0.00% |
|
|
||||||
| 毛利率 | 10.00% | 9.76% | 7.99% | 8.60% | 9.55% | 10.48% | 8.06% | 10.09% | 12.70% | - |
|
|
||||||
| 净利润率 | 4.23% | 3.72% | 3.05% | 3.90% | 3.57% | 3.14% | 2.15% | 1.14% | 3.94% | - |
|
|
||||||
| 收入(亿) | 130.59 | 132.97 | 173.11 | 287.51 | 155.66 | 79.90 | 69.78 | 70.26 | 42.11 | 0.00 |
|
|
||||||
| 收入增速 | 32.15% | -23.19% | -39.79% | 84.71% | 94.82% | 14.50% | -0.69% | 66.84% | - | - |
|
|
||||||
| 净利润(亿) | 5.52 | 4.94 | 5.27 | 11.21 | 5.55 | 2.51 | 1.50 | 0.80 | 1.66 | 0.00 |
|
|
||||||
| 净利润增速 | 50.26% | -6.33% | -52.93% | 101.77% | 121.66% | 66.94% | 87.35% | -51.76% | - | - |
|
|
||||||
| 经营净现金流(亿) | 8.97 | 17.53 | 25.80 | -15.61 | 4.32 | 3.97 | 1.72 | 1.11 | -5.94 | - |
|
|
||||||
| 资本开支(亿) | 4.89 | 9.66 | 11.45 | 6.51 | 5.56 | 3.33 | 5.86 | 6.13 | 3.79 | - |
|
|
||||||
| 自由现金流(亿) | 4.08 | 7.87 | 14.35 | -22.12 | -1.24 | 0.64 | -4.14 | -5.01 | -9.73 | - |
|
|
||||||
| 分红(亿) | - | 2.02 | 2.95 | 2.10 | 1.26 | - | - | - | - | - |
|
|
||||||
| 回购(亿) | - | 1.71 | 0.50 | - | - | - | - | - | - | - |
|
|
||||||
| 总资产(亿) | 174.13 | 147.47 | 134.81 | 153.80 | 105.16 | 62.22 | 53.48 | 55.49 | 37.74 | 1.00 |
|
|
||||||
| 净资产(亿) | 90.09 | 87.37 | 85.82 | 82.00 | 37.36 | 17.48 | 15.12 | 7.47 | 6.67 | 1.00 |
|
|
||||||
| 商誉(亿) | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 费用指标
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 销售费用率 | 0.25% | 0.31% | 0.19% | 0.09% | 0.19% | 0.33% | 0.58% | 0.37% | 0.51% | - |
|
|
||||||
| 管理费用率 | 1.18% | 1.42% | 1.11% | 0.54% | 0.84% | 1.13% | 1.12% | 0.92% | 1.10% | - |
|
|
||||||
| SG&A比例 | 1.43% | 1.73% | 1.30% | 0.63% | 1.03% | 1.46% | 1.70% | 1.29% | 1.61% | - |
|
|
||||||
| 研发费用率 | 2.99% | 3.15% | 2.68% | 2.63% | 2.90% | 3.27% | 3.52% | 4.73% | 4.10% | - |
|
|
||||||
| 其他费用率 | 1.35% | 1.16% | 0.96% | 1.44% | 2.05% | 2.62% | 0.69% | 2.94% | 3.05% | - |
|
|
||||||
| 折旧费用占比 | - | 2.77% | 2.02% | 1.03% | 1.50% | 2.39% | 1.66% | 0.85% | 1.09% | - |
|
|
||||||
| 所得税率 | 9.29% | 3.85% | 5.21% | 8.93% | 7.30% | 4.21% | -26.38% | 2.76% | 27.22% | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 资产占比
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 现金占比 | 8.88% | 11.09% | 8.90% | 6.61% | 4.04% | 4.47% | 0.96% | 2.96% | 2.90% | - |
|
|
||||||
| 库存占比 | 26.24% | 16.79% | 14.57% | 21.79% | 26.58% | 19.51% | 16.08% | 28.66% | 32.68% | - |
|
|
||||||
| 应收款占比 | 18.81% | 15.92% | 25.95% | 32.22% | 28.09% | 19.84% | 12.33% | 15.88% | 13.23% | - |
|
|
||||||
| 预付款占比 | 0.75% | 0.08% | 0.07% | 0.11% | 0.16% | 1.25% | 0.39% | 6.20% | 3.26% | - |
|
|
||||||
| 固定资产占比 | - | 23.88% | 25.96% | 23.65% | 26.59% | 38.24% | 37.34% | 19.47% | 15.24% | - |
|
|
||||||
| 长期投资占比 | 2.39% | 2.83% | 2.95% | 0.65% | - | 0.07% | 0.07% | - | - | - |
|
|
||||||
| 商誉占比 | - | - | - | - | - | - | - | - | - | - |
|
|
||||||
| 其他资产占比 | 42.94% | 29.42% | 21.60% | 14.97% | 14.54% | 16.62% | 32.82% | 26.83% | 32.70% | 100.00% |
|
|
||||||
| 应付款占比 | 17.61% | 14.64% | 16.87% | 13.63% | 33.13% | 19.56% | 16.47% | 12.18% | 15.49% | - |
|
|
||||||
| 预收款占比 | 0.88% | 0.02% | 0.03% | 0.04% | 0.10% | 0.03% | 0.05% | 0.14% | 0.36% | 0.00% |
|
|
||||||
| 短期借款占比 | 1.06% | 1.60% | 0.25% | 4.53% | 2.48% | 20.67% | 33.82% | 23.62% | 10.33% | 0.00% |
|
|
||||||
| 长期借款占比 | 2.57% | 3.16% | 5.23% | 5.66% | 13.15% | 18.25% | 3.12% | 1.87% | 0.11% | 0.00% |
|
|
||||||
| 运营资产占比 | 27.30% | 18.13% | 23.69% | 40.46% | 21.59% | 21.02% | 12.29% | 38.41% | 33.31% | 0.00% |
|
|
||||||
| 有息负债率 | 3.63% | 4.76% | 5.47% | 10.19% | 15.64% | 38.92% | 36.94% | 25.49% | 10.44% | 0.00% |
|
|
||||||
|
|
||||||
|
|
||||||
## 周转能力
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 存货周转天数 | 141 | 75 | 45 | 46 | 72 | 61 | 48 | 91 | 122 | - |
|
|
||||||
| 应收款周转天数 | 91 | 64 | 73 | 62 | 69 | 56 | 34 | 45 | 43 | - |
|
|
||||||
| 应付款周转天数 | 95 | 65 | 52 | 29 | 90 | 62 | 50 | 39 | 58 | - |
|
|
||||||
| 固定资产周转率 | - | 3.78 | 4.95 | 7.91 | 5.57 | 3.36 | 3.49 | 6.50 | 7.32 | - |
|
|
||||||
| 总资产周转率 | 0.75 | 0.90 | 1.28 | 1.87 | 1.48 | 1.28 | 1.30 | 1.27 | 1.12 | 0.00 |
|
|
||||||
|
|
||||||
|
|
||||||
## 人均效率
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 员工人数 | - | 3,344 | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均创收(万) | - | 397.63 | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均创利(万) | - | 14.77 | - | - | - | - | - | - | - | - |
|
|
||||||
| 人均薪酬(万) | - | 15.29 | - | - | - | - | - | - | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 市场表现
|
|
||||||
| 指标 | 2025Q3 | 2024A | 2023A | 2022A | 2021A | 2020A | 2019A | 2018A | 2017A | 2016A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|
|
||||||
| 股价 | 77.37 | 45.64 | 39.64 | 77.68 | 103.35 | - | - | - | - | - |
|
|
||||||
| 市值(亿) | 390.48 | 192.04 | 166.79 | 233.47 | 260.00 | - | - | - | - | - |
|
|
||||||
| PE | 79.03 | 36.41 | 14.88 | 42.04 | 103.77 | - | - | - | - | - |
|
|
||||||
| PB | 4.33 | 2.23 | 1.97 | 2.93 | 7.27 | - | - | - | - | - |
|
|
||||||
| 股东户数 | 24,627 | 14,740 | 13,732 | 14,462 | 15,688 | - | - | - | - | - |
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
cash_equi_short_term_inve_oas,accou_and_notes_recei_oas,inventories_oas,ppe_net_oas,long_term_inv_and_receiv_oas,goodwill_and_intasset_oas,short_term_debt_oas,short_term_borrowings_oas,account_and_note_payable_oas,contra_liabilities_current_oas,advance_from_cust_current_oas,defer_revenue_current_oas,long_term_debt_oas,long_term_borrowings_oas,total_assets_oas,equity_attri_to_companyowner_oas,prepaid_expenses_current_oas,end_date
|
|
||||||
5899320980.35,22326249202.25,16650772821.2,31263474425.4,4794152048.0,53852622755.049995,3617228537.3,3617228537.3,7518553255.849999,,,,36159437268.15,36159437268.15,155576124604.95,54802733151.25,,20241231
|
|
||||||
7070829794.070001,21350738934.77,16675747687.67,29873189030.72,5307593791.54,34970889368.92,5072156415.77,5072156415.77,6915651724.870001,,,,27998809255.25,27998809255.25,144576837566.65,57062250906.689995,,20231231
|
|
||||||
5046190177.88,20369212787.27,15183728587.93,29336618624.86,5409547685.4,25662437929.58,5989276634.969999,5989276634.969999,6303080634.48,,,,21383987001.46,21383987001.46,133028563816.29,51281444590.26,,20221231
|
|
||||||
8709165023.76,20609942061.24,13679704695.48,29539550251.08,6497706183.72,25484093179.92,5616320844.24,5616320844.24,5452427104.8,,,,24897794036.4,24897794036.4,136777293387.96,49476819729.48,,20211231
|
|
||||||
10725243245.05,22595254368.58,13732598542.25,33002436277.529995,6686243673.8,28770955850.0,15747071314.71,15747071314.71,6078069930.14,,,,24889089960.7,24889089960.7,155512580861.81,53026073056.08,,20201231
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
corp_cn_name,accounting_date,ipo_date
|
|
||||||
麒麟控股株式会社,1231,19490516
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
net_cash_flows_from_oa_oas,purchase_of_ppe_and_ia_oas,dividends_paid_oas,end_date
|
|
||||||
11263845394.2,8376036701.2,2704873943.8,20241231
|
|
||||||
10238024262.94,5734031186.9,2896993175.0,20231231
|
|
||||||
7093529728.46,5153093891.57,2814032263.74,20221231
|
|
||||||
12134499912.36,4777098580.2,2998115590.08,20211231
|
|
||||||
10423243057.93,5882300964.62,3498421765.62,20201231
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
date_str,employee_count
|
|
||||||
20261231,31934.0
|
|
||||||
20251231,31934.0
|
|
||||||
20241231,31934.0
|
|
||||||
20231231,30538.0
|
|
||||||
20221231,29515.0
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
date_str,PE,PB,MarketCap,Price
|
|
||||||
20241231,0.0,0.0,86865526677.3,95.03886945
|
|
||||||
20231231,0.0,0.0,95138465046.76,104.09022434
|
|
||||||
20221231,0.0,0.0,96179539188.82,105.22925513
|
|
||||||
20211231,0.0,0.0,93409361034.96,102.19842564
|
|
||||||
20201231,0.0,0.0,0.0,0.0
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
revenue_oas,gross_profit_oas,sga_expenses_oas,selling_marketing_expenses_oas,ga_expenses_oas,rd_expenses_oas,income_tax_expense_oas,net_income_attri_to_common_sh_oas,operating_income_oas,end_date
|
|
||||||
108461428374.25,49442244062.75,34274708414.449997,7858262714.049999,,5382196355.9,2500510225.5,2700142872.7,5813651487.0,20241231
|
|
||||||
107536033978.57,48541816110.34,34112774799.24,8351653454.849999,,4277221488.55,2348378241.39,5677955475.53,7572185952.06,20231231
|
|
||||||
104102553826.44,47393090179.79,33504032019.72,8687928238.56,,3886365990.93,2491542010.45,5808644417.809999,6070906489.7699995,20221231
|
|
||||||
100791329828.4,45529592285.04,32524275468.12,9023230136.88,,3851779537.44,1725974819.16,3308307454.8,3767232058.08,20211231
|
|
||||||
116952038544.15,50831829234.21,36502312399.16,9503078333.689999,,4078520115.0,1562420984.83,4548656503.45,6507863747.53,20201231
|
|
||||||
|
@ -1,445 +0,0 @@
|
|||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>2503.T Financial Report</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f6fa;
|
|
||||||
--card-bg: #ffffff;
|
|
||||||
--header-bg: #f7f8fb;
|
|
||||||
--section-bg: #f0f2f5;
|
|
||||||
--border: #e5e7eb;
|
|
||||||
--text-primary: #111827;
|
|
||||||
--text-secondary: #6b7280;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 32px;
|
|
||||||
background: var(--bg);
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
color: var(--text-primary);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.report-container {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: var(--card-bg);
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 32px 40px;
|
|
||||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 8px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 0 24px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: var(--card-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-align: right;
|
|
||||||
background: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:first-child,
|
|
||||||
td:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.company-table th,
|
|
||||||
.company-table td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
background: var(--card-bg);
|
|
||||||
box-shadow: 0 10px 20px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table thead th:first-child {
|
|
||||||
left: 0;
|
|
||||||
z-index: 4;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table th:first-child,
|
|
||||||
.metrics-table td:first-child {
|
|
||||||
width: 180px;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
background: var(--card-bg);
|
|
||||||
font-weight: 600;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.04);
|
|
||||||
z-index: 2;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody td:not(:first-child) {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tr.other-assets-row td:first-child {
|
|
||||||
background: #fff7e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table tbody tr:hover td {
|
|
||||||
background: #f4efff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-row td {
|
|
||||||
background: #eef1f6;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-row td:first-child {
|
|
||||||
position: sticky;
|
|
||||||
left: 0;
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: 16px 0 24px rgba(15, 23, 42, 0.08);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metrics-table .section-label {
|
|
||||||
color: var(--text-primary);
|
|
||||||
background: #eef1f6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-spacer {
|
|
||||||
background: #eef1f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-name {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container table {
|
|
||||||
margin-bottom: 0;
|
|
||||||
min-width: 960px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-gap {
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data {
|
|
||||||
margin-top: 24px;
|
|
||||||
padding: 32px;
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed var(--border);
|
|
||||||
border-radius: 16px;
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-green { background-color: #e6f7eb !important; }
|
|
||||||
.bg-red { background-color: #ffeef0 !important; }
|
|
||||||
.font-red { color: #d32f2f !important; }
|
|
||||||
.font-green { color: #1b873f !important; }
|
|
||||||
.font-blue { color: #2563eb !important; }
|
|
||||||
.italic { font-style: italic !important; }
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
body { padding: 16px; }
|
|
||||||
.report-container { padding: 24px; }
|
|
||||||
table { font-size: 0.85rem; }
|
|
||||||
th,
|
|
||||||
td { padding: 10px 12px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="report-container">
|
|
||||||
<h1>麒麟控股株式会社 (2503.T) - Financial Report</h1>
|
|
||||||
<p><em>Report generated on: 2026-01-07</em></p>
|
|
||||||
|
|
||||||
<table class="company-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>代码</th>
|
|
||||||
<th>简称</th>
|
|
||||||
<th>上市日期</th>
|
|
||||||
<th>PE</th>
|
|
||||||
<th>PB</th>
|
|
||||||
<th>股息率(%)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>2503.T</td>
|
|
||||||
<td>麒麟控股株式会社</td>
|
|
||||||
<td>1949-05-16</td>
|
|
||||||
<td>0.00</td>
|
|
||||||
<td>0.00</td>
|
|
||||||
<td>0.00%</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="table-gap"></div>
|
|
||||||
|
|
||||||
<table class="metrics-table" data-table="metrics" data-scrollable="true">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>指标</th>
|
|
||||||
<th>2024A</th><th>2023A</th><th>2022A</th><th>2021A</th><th>2020A</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="section-row"><td class="section-label">主要指标</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">ROE</td><td>4.93%</td><td>9.95%</td><td>11.33%</td><td>6.69%</td><td>8.58%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROA</td><td>1.74%</td><td>3.93%</td><td>4.37%</td><td>2.42%</td><td>2.92%</td></tr>
|
|
||||||
<tr><td class="metric-name">ROCE/ROIC</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">毛利率</td><td>45.59%</td><td>45.14%</td><td>45.53%</td><td>45.17%</td><td>43.46%</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润率</td><td>2.49%</td><td>5.28%</td><td>5.58%</td><td>3.28%</td><td>3.89%</td></tr>
|
|
||||||
<tr><td class="metric-name">收入(亿)</td><td>1,084.61</td><td>1,075.36</td><td>1,041.03</td><td>1,007.91</td><td>1,169.52</td></tr>
|
|
||||||
<tr><td class="metric-name">收入增速</td><td>0.86%</td><td>3.30%</td><td>3.29%</td><td>-13.82%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润(亿)</td><td>27.00</td><td>56.78</td><td>58.09</td><td>33.08</td><td>45.49</td></tr>
|
|
||||||
<tr><td class="metric-name">净利润增速</td><td>-52.45%</td><td>-2.25%</td><td>75.58%</td><td>-27.27%</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">经营净现金流(亿)</td><td>112.64</td><td>102.38</td><td>70.94</td><td>121.34</td><td>104.23</td></tr>
|
|
||||||
<tr><td class="metric-name">资本开支(亿)</td><td>83.76</td><td>57.34</td><td>51.53</td><td>47.77</td><td>58.82</td></tr>
|
|
||||||
<tr><td class="metric-name">自由现金流(亿)</td><td>28.88</td><td>45.04</td><td>19.40</td><td>73.57</td><td>45.41</td></tr>
|
|
||||||
<tr><td class="metric-name">分红(亿)</td><td>27.05</td><td>28.97</td><td>28.14</td><td>29.98</td><td>34.98</td></tr>
|
|
||||||
<tr><td class="metric-name">回购(亿)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产(亿)</td><td>1,555.76</td><td>1,445.77</td><td>1,330.29</td><td>1,367.77</td><td>1,555.13</td></tr>
|
|
||||||
<tr><td class="metric-name">净资产(亿)</td><td>548.03</td><td>570.62</td><td>512.81</td><td>494.77</td><td>530.26</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉(亿)</td><td>538.53</td><td>349.71</td><td>256.62</td><td>254.84</td><td>287.71</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">费用指标</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">销售费用率</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">管理费用率</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">SG&A比例</td><td>31.60%</td><td>31.72%</td><td>32.18%</td><td>32.27%</td><td>31.21%</td></tr>
|
|
||||||
<tr><td class="metric-name">研发费用率</td><td>4.96%</td><td>3.98%</td><td>3.73%</td><td>3.82%</td><td>3.49%</td></tr>
|
|
||||||
<tr><td class="metric-name">其他费用率</td><td>6.53%</td><td>4.16%</td><td>4.03%</td><td>5.80%</td><td>4.88%</td></tr>
|
|
||||||
<tr><td class="metric-name">折旧费用占比</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">所得税率</td><td>48.08%</td><td>29.26%</td><td>30.02%</td><td>34.28%</td><td>25.57%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">资产占比</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">现金占比</td><td>3.79%</td><td>4.89%</td><td>3.79%</td><td>6.37%</td><td>6.90%</td></tr>
|
|
||||||
<tr><td class="metric-name">库存占比</td><td>10.70%</td><td>11.53%</td><td>11.41%</td><td>10.00%</td><td>8.83%</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款占比</td><td>14.35%</td><td>14.77%</td><td>15.31%</td><td>15.07%</td><td>14.53%</td></tr>
|
|
||||||
<tr><td class="metric-name">预付款占比</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产占比</td><td>20.10%</td><td>20.66%</td><td>22.05%</td><td>21.60%</td><td>21.22%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期投资占比</td><td>3.08%</td><td>3.67%</td><td>4.07%</td><td>4.75%</td><td>4.30%</td></tr>
|
|
||||||
<tr><td class="metric-name">商誉占比</td><td>34.61%</td><td>24.19%</td><td>19.29%</td><td>18.63%</td><td>18.50%</td></tr>
|
|
||||||
<tr class="other-assets-row"><td class="metric-name">其他资产占比</td><td>13.36%</td><td>20.29%</td><td>24.07%</td><td>23.58%</td><td>25.72%</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款占比</td><td>4.83%</td><td>4.78%</td><td>4.74%</td><td>3.99%</td><td>3.91%</td></tr>
|
|
||||||
<tr><td class="metric-name">预收款占比</td><td>0.00%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td><td>0.00%</td></tr>
|
|
||||||
<tr><td class="metric-name">短期借款占比</td><td>2.33%</td><td>3.51%</td><td>4.50%</td><td>4.11%</td><td>10.13%</td></tr>
|
|
||||||
<tr><td class="metric-name">长期借款占比</td><td>46.48%</td><td>38.73%</td><td>32.15%</td><td>36.41%</td><td>32.01%</td></tr>
|
|
||||||
<tr><td class="metric-name">运营资产占比</td><td>20.22%</td><td>21.52%</td><td>21.99%</td><td>21.08%</td><td>19.45%</td></tr>
|
|
||||||
<tr><td class="metric-name">有息负债率</td><td>48.81%</td><td>42.24%</td><td>36.65%</td><td>40.51%</td><td>42.14%</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">周转能力</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">存货周转天数</td><td>102</td><td>103</td><td>97</td><td>90</td><td>75</td></tr>
|
|
||||||
<tr><td class="metric-name">应收款周转天数</td><td>75</td><td>72</td><td>71</td><td>74</td><td>70</td></tr>
|
|
||||||
<tr><td class="metric-name">应付款周转天数</td><td>46</td><td>42</td><td>40</td><td>36</td><td>33</td></tr>
|
|
||||||
<tr><td class="metric-name">固定资产周转率</td><td>3.47</td><td>3.60</td><td>3.55</td><td>3.41</td><td>3.54</td></tr>
|
|
||||||
<tr><td class="metric-name">总资产周转率</td><td>0.70</td><td>0.74</td><td>0.78</td><td>0.74</td><td>0.75</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">人均效率</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">员工人数</td><td>31,934</td><td>30,538</td><td>29,515</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创收(万)</td><td>339.64</td><td>352.14</td><td>352.71</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均创利(万)</td><td>8.46</td><td>18.59</td><td>19.68</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr><td class="metric-name">人均薪酬(万)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
<tr class="section-row"><td class="section-label">市场表现</td><td class="section-spacer" colspan="5"></td></tr>
|
|
||||||
<tr><td class="metric-name">股价</td><td>95.04</td><td>104.09</td><td>105.23</td><td>102.20</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">市值(亿)</td><td>868.66</td><td>951.38</td><td>961.80</td><td>934.09</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">PE</td><td>32.17</td><td>16.76</td><td>16.56</td><td>28.23</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">PB</td><td>1.59</td><td>1.67</td><td>1.88</td><td>1.89</td><td>0.00</td></tr>
|
|
||||||
<tr><td class="metric-name">股东户数</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const scrollableTables = document.querySelectorAll('table[data-scrollable="true"]');
|
|
||||||
scrollableTables.forEach(table => {
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.className = 'table-container';
|
|
||||||
table.parentNode.insertBefore(container, table);
|
|
||||||
container.appendChild(table);
|
|
||||||
});
|
|
||||||
|
|
||||||
const parseValue = (text) => {
|
|
||||||
if (!text || text.trim() === '-') return null;
|
|
||||||
return parseFloat(text.replace(/%|,/g, ''));
|
|
||||||
};
|
|
||||||
|
|
||||||
const highlightIfOverThirtyPercent = (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 30) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleRules = {
|
|
||||||
'ROE': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 15) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'ROA': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 10) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'毛利率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 50) cell.classList.add('bg-green');
|
|
||||||
},
|
|
||||||
'净利润率': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 20) {
|
|
||||||
cell.classList.add('bg-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'收入增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'净利润增速': (cell) => {
|
|
||||||
cell.classList.add('italic');
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null) {
|
|
||||||
if (value > 15) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
} else if (value < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else {
|
|
||||||
cell.classList.add('font-blue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'经营净现金流(亿)': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value < 0) cell.classList.add('bg-red', 'font-red');
|
|
||||||
},
|
|
||||||
'应收款周转天数': (cell) => {
|
|
||||||
const value = parseValue(cell.textContent);
|
|
||||||
if (value !== null && value > 90) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'现金占比': highlightIfOverThirtyPercent,
|
|
||||||
'库存占比': highlightIfOverThirtyPercent,
|
|
||||||
'应收款占比': highlightIfOverThirtyPercent,
|
|
||||||
'预付款占比': highlightIfOverThirtyPercent,
|
|
||||||
'固定资产占比': highlightIfOverThirtyPercent,
|
|
||||||
'长期投资占比': highlightIfOverThirtyPercent,
|
|
||||||
'商誉占比': highlightIfOverThirtyPercent,
|
|
||||||
'其他资产占比': highlightIfOverThirtyPercent
|
|
||||||
};
|
|
||||||
|
|
||||||
const metricsTables = document.querySelectorAll('table[data-table="metrics"]');
|
|
||||||
metricsTables.forEach(table => {
|
|
||||||
let netProfitValues = [];
|
|
||||||
let fcfRow = null;
|
|
||||||
const rows = table.querySelectorAll('tbody tr');
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
if (metricName === '净利润(亿)') {
|
|
||||||
row.querySelectorAll('td:not(:first-child)').forEach(cell => {
|
|
||||||
netProfitValues.push(parseValue(cell.textContent));
|
|
||||||
});
|
|
||||||
} else if (metricName === '自由现金流(亿)') {
|
|
||||||
fcfRow = row;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rows.forEach(row => {
|
|
||||||
if (row.classList.contains('section-row')) return;
|
|
||||||
const metricCell = row.querySelector('td:first-child');
|
|
||||||
if (!metricCell) return;
|
|
||||||
const metricName = metricCell.textContent.trim();
|
|
||||||
const cells = row.querySelectorAll('td:not(:first-child)');
|
|
||||||
if (styleRules[metricName]) {
|
|
||||||
cells.forEach(cell => {
|
|
||||||
styleRules[metricName](cell);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (row === fcfRow && netProfitValues.length > 0) {
|
|
||||||
cells.forEach((cell, index) => {
|
|
||||||
const fcfValue = parseValue(cell.textContent);
|
|
||||||
const netProfitValue = netProfitValues[index];
|
|
||||||
if (fcfValue !== null) {
|
|
||||||
if (fcfValue < 0) {
|
|
||||||
cell.classList.add('bg-red', 'font-red');
|
|
||||||
} else if (netProfitValue !== null && fcfValue > netProfitValue) {
|
|
||||||
cell.classList.add('bg-green', 'font-green');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# 麒麟控股株式会社 (2503.T) - Financial Report
|
|
||||||
*Report generated on: 2026-01-07*
|
|
||||||
|
|
||||||
| 代码 | 简称 | 上市日期 | PE | PB | 股息率(%) |
|
|
||||||
|:---|:---|:---|:---|:---|:---|
|
|
||||||
| 2503.T | 麒麟控股株式会社 | 1949-05-16 | 0.00 | 0.00 | 0.00% |
|
|
||||||
|
|
||||||
|
|
||||||
## 主要指标
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| ROE | 4.93% | 9.95% | 11.33% | 6.69% | 8.58% |
|
|
||||||
| ROA | 1.74% | 3.93% | 4.37% | 2.42% | 2.92% |
|
|
||||||
| ROCE/ROIC | - | - | - | - | - |
|
|
||||||
| 毛利率 | 45.59% | 45.14% | 45.53% | 45.17% | 43.46% |
|
|
||||||
| 净利润率 | 2.49% | 5.28% | 5.58% | 3.28% | 3.89% |
|
|
||||||
| 收入(亿) | 1,084.61 | 1,075.36 | 1,041.03 | 1,007.91 | 1,169.52 |
|
|
||||||
| 收入增速 | 0.86% | 3.30% | 3.29% | -13.82% | - |
|
|
||||||
| 净利润(亿) | 27.00 | 56.78 | 58.09 | 33.08 | 45.49 |
|
|
||||||
| 净利润增速 | -52.45% | -2.25% | 75.58% | -27.27% | - |
|
|
||||||
| 经营净现金流(亿) | 112.64 | 102.38 | 70.94 | 121.34 | 104.23 |
|
|
||||||
| 资本开支(亿) | 83.76 | 57.34 | 51.53 | 47.77 | 58.82 |
|
|
||||||
| 自由现金流(亿) | 28.88 | 45.04 | 19.40 | 73.57 | 45.41 |
|
|
||||||
| 分红(亿) | 27.05 | 28.97 | 28.14 | 29.98 | 34.98 |
|
|
||||||
| 回购(亿) | - | - | - | - | - |
|
|
||||||
| 总资产(亿) | 1,555.76 | 1,445.77 | 1,330.29 | 1,367.77 | 1,555.13 |
|
|
||||||
| 净资产(亿) | 548.03 | 570.62 | 512.81 | 494.77 | 530.26 |
|
|
||||||
| 商誉(亿) | 538.53 | 349.71 | 256.62 | 254.84 | 287.71 |
|
|
||||||
|
|
||||||
|
|
||||||
## 费用指标
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| 销售费用率 | - | - | - | - | - |
|
|
||||||
| 管理费用率 | - | - | - | - | - |
|
|
||||||
| SG&A比例 | 31.60% | 31.72% | 32.18% | 32.27% | 31.21% |
|
|
||||||
| 研发费用率 | 4.96% | 3.98% | 3.73% | 3.82% | 3.49% |
|
|
||||||
| 其他费用率 | 6.53% | 4.16% | 4.03% | 5.80% | 4.88% |
|
|
||||||
| 折旧费用占比 | - | - | - | - | - |
|
|
||||||
| 所得税率 | 48.08% | 29.26% | 30.02% | 34.28% | 25.57% |
|
|
||||||
|
|
||||||
|
|
||||||
## 资产占比
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| 现金占比 | 3.79% | 4.89% | 3.79% | 6.37% | 6.90% |
|
|
||||||
| 库存占比 | 10.70% | 11.53% | 11.41% | 10.00% | 8.83% |
|
|
||||||
| 应收款占比 | 14.35% | 14.77% | 15.31% | 15.07% | 14.53% |
|
|
||||||
| 预付款占比 | - | - | - | - | - |
|
|
||||||
| 固定资产占比 | 20.10% | 20.66% | 22.05% | 21.60% | 21.22% |
|
|
||||||
| 长期投资占比 | 3.08% | 3.67% | 4.07% | 4.75% | 4.30% |
|
|
||||||
| 商誉占比 | 34.61% | 24.19% | 19.29% | 18.63% | 18.50% |
|
|
||||||
| 其他资产占比 | 13.36% | 20.29% | 24.07% | 23.58% | 25.72% |
|
|
||||||
| 应付款占比 | 4.83% | 4.78% | 4.74% | 3.99% | 3.91% |
|
|
||||||
| 预收款占比 | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
|
|
||||||
| 短期借款占比 | 2.33% | 3.51% | 4.50% | 4.11% | 10.13% |
|
|
||||||
| 长期借款占比 | 46.48% | 38.73% | 32.15% | 36.41% | 32.01% |
|
|
||||||
| 运营资产占比 | 20.22% | 21.52% | 21.99% | 21.08% | 19.45% |
|
|
||||||
| 有息负债率 | 48.81% | 42.24% | 36.65% | 40.51% | 42.14% |
|
|
||||||
|
|
||||||
|
|
||||||
## 周转能力
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| 存货周转天数 | 102 | 103 | 97 | 90 | 75 |
|
|
||||||
| 应收款周转天数 | 75 | 72 | 71 | 74 | 70 |
|
|
||||||
| 应付款周转天数 | 46 | 42 | 40 | 36 | 33 |
|
|
||||||
| 固定资产周转率 | 3.47 | 3.60 | 3.55 | 3.41 | 3.54 |
|
|
||||||
| 总资产周转率 | 0.70 | 0.74 | 0.78 | 0.74 | 0.75 |
|
|
||||||
|
|
||||||
|
|
||||||
## 人均效率
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| 员工人数 | 31,934 | 30,538 | 29,515 | - | - |
|
|
||||||
| 人均创收(万) | 339.64 | 352.14 | 352.71 | - | - |
|
|
||||||
| 人均创利(万) | 8.46 | 18.59 | 19.68 | - | - |
|
|
||||||
| 人均薪酬(万) | - | - | - | - | - |
|
|
||||||
|
|
||||||
|
|
||||||
## 市场表现
|
|
||||||
| 指标 | 2024A | 2023A | 2022A | 2021A | 2020A |
|
|
||||||
|:---|--:|--:|--:|--:|--:|
|
|
||||||
| 股价 | 95.04 | 104.09 | 105.23 | 102.20 | 0.00 |
|
|
||||||
| 市值(亿) | 868.66 | 951.38 | 961.80 | 934.09 | 0.00 |
|
|
||||||
| PE | 32.17 | 16.76 | 16.56 | 28.23 | 0.00 |
|
|
||||||
| PB | 1.59 | 1.67 | 1.88 | 1.89 | 0.00 |
|
|
||||||
| 股东户数 | - | - | - | - | - |
|
|
||||||
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
apps: [
|
|
||||||
{
|
|
||||||
name: "datafetch-backend",
|
|
||||||
script: ".venv/bin/uvicorn",
|
|
||||||
args: "backend.app.main:app --host 0.0.0.0 --port 8000",
|
|
||||||
cwd: ".",
|
|
||||||
env: {
|
|
||||||
PYTHONPATH: "."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "datafetch-frontend",
|
|
||||||
script: "npm",
|
|
||||||
args: "run dev",
|
|
||||||
cwd: "./frontend",
|
|
||||||
env: {
|
|
||||||
NODE_ENV: "development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
80
frontend/package-lock.json
generated
80
frontend/package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
|
"@radix-ui/react-progress": "^1.1.8",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
@ -84,6 +85,7 @@
|
|||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@ -1723,6 +1725,68 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-progress": {
|
||||||
|
"version": "1.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz",
|
||||||
|
"integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-context": "1.1.3",
|
||||||
|
"@radix-ui/react-primitive": "2.1.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.2.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-roving-focus": {
|
"node_modules/@radix-ui/react-roving-focus": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
||||||
@ -2422,6 +2486,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@ -2432,6 +2497,7 @@
|
|||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@ -2487,6 +2553,7 @@
|
|||||||
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
"integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.51.0",
|
"@typescript-eslint/scope-manager": "8.51.0",
|
||||||
"@typescript-eslint/types": "8.51.0",
|
"@typescript-eslint/types": "8.51.0",
|
||||||
@ -2992,6 +3059,7 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -3354,6 +3422,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@ -4054,6 +4123,7 @@
|
|||||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@ -4239,6 +4309,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@ -7470,6 +7541,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -7479,6 +7551,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@ -7491,6 +7564,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.69.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.69.0.tgz",
|
||||||
"integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==",
|
"integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
@ -8339,7 +8413,8 @@
|
|||||||
"version": "4.1.18",
|
"version": "4.1.18",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss-animate": {
|
"node_modules/tailwindcss-animate": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
@ -8405,6 +8480,7 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@ -8597,6 +8673,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@ -9036,6 +9113,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz",
|
||||||
"integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==",
|
"integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-label": "^2.1.8",
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
|
"@radix-ui/react-progress": "^1.1.8",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { getConfig, updateConfig } from "@/lib/api"
|
import { getConfig, updateConfig } from "@/lib/api"
|
||||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card"
|
import { AI_MODELS } from "@/lib/constants"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
@ -71,10 +72,11 @@ export default function ConfigPage() {
|
|||||||
value={config["AI_MODEL"] || "gemini-2.0-flash"}
|
value={config["AI_MODEL"] || "gemini-2.0-flash"}
|
||||||
onChange={(e) => setConfig({ ...config, "AI_MODEL": e.target.value })}
|
onChange={(e) => setConfig({ ...config, "AI_MODEL": e.target.value })}
|
||||||
>
|
>
|
||||||
<option value="gemini-2.0-flash">Gemini 2.0 Flash</option>
|
{AI_MODELS.map((model) => (
|
||||||
<option value="gemini-2.5-flash">Gemini 2.5 Flash</option>
|
<option key={model.value} value={model.value}>
|
||||||
<option value="gemini-3-flash-preview">Gemini 3 Flash Preview</option>
|
{model.label}
|
||||||
<option value="gemini-3-pro-preview">Gemini 3 Pro Preview</option>
|
</option>
|
||||||
|
))}
|
||||||
<option value="custom">自定义模型...</option>
|
<option value="custom">自定义模型...</option>
|
||||||
</select>
|
</select>
|
||||||
<Button onClick={() => handleSave("AI_MODEL", config["AI_MODEL"])}>保存</Button>
|
<Button onClick={() => handleSave("AI_MODEL", config["AI_MODEL"])}>保存</Button>
|
||||||
|
|||||||
@ -1,9 +1,91 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react"
|
||||||
|
import { useSearchParams } from "next/navigation"
|
||||||
import { SearchStock } from "@/components/search-stock"
|
import { SearchStock } from "@/components/search-stock"
|
||||||
import { HistoryList } from "@/components/history-list"
|
import { HistoryList } from "@/components/history-list"
|
||||||
|
import { DataSourceSelector } from "@/components/data-source-selector"
|
||||||
|
import { DataStatusCard } from "@/components/data-status-card"
|
||||||
|
import { FinancialTables } from "@/components/financial-tables"
|
||||||
|
import { AnalysisTrigger } from "@/components/analysis-trigger"
|
||||||
|
import { AnalysisReport } from "@/components/analysis-report"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { ArrowLeft, Building2, RefreshCw, Loader2, CheckCircle2 } from "lucide-react"
|
||||||
|
import type { SearchResult } from "@/lib/types"
|
||||||
|
import { useFinancialData } from "@/hooks/use-financial-data"
|
||||||
|
import { Progress } from "@/components/ui/progress"
|
||||||
|
import { formatTimestamp } from "@/lib/formatters"
|
||||||
|
import { BloombergView } from "@/components/bloomberg-view"
|
||||||
|
import { HeaderPortal } from "@/components/header-portal"
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const searchParams = useSearchParams()
|
||||||
|
|
||||||
|
// 状态管理
|
||||||
|
const [selectedCompany, setSelectedCompany] = useState<SearchResult | null>(null)
|
||||||
|
const [selectedDataSource, setSelectedDataSource] = useState<string>("iFinD")
|
||||||
|
const [companyId, setCompanyId] = useState<number | null>(null)
|
||||||
|
const [showFinancialData, setShowFinancialData] = useState(false)
|
||||||
|
const [analysisId, setAnalysisId] = useState<number | null>(null)
|
||||||
|
const [oneTimeModel, setOneTimeModel] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
|
// 处理公司选择
|
||||||
|
const handleCompanySelect = (company: SearchResult, dataSource?: string) => {
|
||||||
|
setSelectedCompany(company)
|
||||||
|
setCompanyId(null)
|
||||||
|
setShowFinancialData(false)
|
||||||
|
setAnalysisId(null)
|
||||||
|
setOneTimeModel(undefined)
|
||||||
|
|
||||||
|
// 如果没有传入数据源,则根据市场设置默认值
|
||||||
|
const targetDataSource = dataSource || (company.market === 'CN' ? 'Tushare' : 'iFinD')
|
||||||
|
setSelectedDataSource(targetDataSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听 URL 参数变化实现快速导航
|
||||||
|
useEffect(() => {
|
||||||
|
const symbol = searchParams.get('symbol')
|
||||||
|
const market = searchParams.get('market')
|
||||||
|
const source = searchParams.get('source')
|
||||||
|
const name = searchParams.get('name')
|
||||||
|
|
||||||
|
if (symbol && market && source) {
|
||||||
|
const company: SearchResult = {
|
||||||
|
symbol,
|
||||||
|
market,
|
||||||
|
company_name: name || symbol
|
||||||
|
}
|
||||||
|
handleCompanySelect(company, source)
|
||||||
|
}
|
||||||
|
}, [searchParams])
|
||||||
|
|
||||||
|
// 数据准备就绪
|
||||||
|
const handleDataReady = (id: number) => {
|
||||||
|
setCompanyId(id)
|
||||||
|
setShowFinancialData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI分析完成
|
||||||
|
const handleAnalysisComplete = (id: number) => {
|
||||||
|
setAnalysisId(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回搜索
|
||||||
|
const handleBackToSearch = () => {
|
||||||
|
setSelectedCompany(null)
|
||||||
|
setCompanyId(null)
|
||||||
|
setShowFinancialData(false)
|
||||||
|
setAnalysisId(null)
|
||||||
|
setOneTimeModel(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-8 p-8 max-w-7xl mx-auto">
|
<div className="min-h-screen w-full p-8">
|
||||||
|
{/* 标题和描述 */}
|
||||||
|
{!selectedCompany && (
|
||||||
|
<div className="max-w-7xl mx-auto flex flex-col gap-8">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h1 className="text-3xl font-bold tracking-tight">股票分析</h1>
|
<h1 className="text-3xl font-bold tracking-tight">股票分析</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
@ -11,12 +93,169 @@ export default function Home() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SearchStock />
|
{/* 搜索组件 */}
|
||||||
|
<div className="grid grid-cols-1 gap-6">
|
||||||
|
<SearchStockWithSelection onSelect={handleCompanySelect} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 最近的报告 */}
|
||||||
<div className="flex flex-col gap-4 mt-8">
|
<div className="flex flex-col gap-4 mt-8">
|
||||||
<h2 className="text-2xl font-bold tracking-tight">最近的报告</h2>
|
<h2 className="text-2xl font-bold tracking-tight">最近的报告</h2>
|
||||||
<HistoryList />
|
<HistoryList />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedCompany && (
|
||||||
|
<div className="w-full">
|
||||||
|
<CompanyAnalysisView
|
||||||
|
company={selectedCompany}
|
||||||
|
dataSource={selectedDataSource}
|
||||||
|
onBack={handleBackToSearch}
|
||||||
|
onDataSourceChange={setSelectedDataSource}
|
||||||
|
oneTimeModel={oneTimeModel}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拆分出单独的组件以使用Hooks
|
||||||
|
function CompanyAnalysisView({
|
||||||
|
company,
|
||||||
|
dataSource,
|
||||||
|
onBack,
|
||||||
|
onDataSourceChange,
|
||||||
|
oneTimeModel
|
||||||
|
}: {
|
||||||
|
company: SearchResult,
|
||||||
|
dataSource: string,
|
||||||
|
onBack: () => void,
|
||||||
|
onDataSourceChange: (ds: string) => void,
|
||||||
|
oneTimeModel?: string
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
status,
|
||||||
|
loading,
|
||||||
|
fetching,
|
||||||
|
updateStatus,
|
||||||
|
error,
|
||||||
|
fetchData,
|
||||||
|
checkStatus
|
||||||
|
} = useFinancialData(company, dataSource)
|
||||||
|
|
||||||
|
const [companyId, setCompanyId] = useState<number | null>(null)
|
||||||
|
const [analysisId, setAnalysisId] = useState<number | null>(null)
|
||||||
|
|
||||||
|
// 当数据就绪时设置companyId
|
||||||
|
useEffect(() => {
|
||||||
|
if (status?.has_data && status.company_id) {
|
||||||
|
setCompanyId(status.company_id)
|
||||||
|
} else {
|
||||||
|
setCompanyId(null)
|
||||||
|
}
|
||||||
|
}, [status])
|
||||||
|
|
||||||
|
const handleAnalysisComplete = (id: number) => {
|
||||||
|
setAnalysisId(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isUpdating = fetching && updateStatus
|
||||||
|
const progress = updateStatus?.progress_percentage || 0
|
||||||
|
const progressStatus = updateStatus?.progress_message || ""
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<HeaderPortal>
|
||||||
|
<div className="flex items-center justify-end w-full gap-4 text-sm h-full">
|
||||||
|
{/* 1. 状态显示 (进度或最后更新) */}
|
||||||
|
<div className="flex items-center text-muted-foreground mr-auto">
|
||||||
|
{isUpdating ? (
|
||||||
|
<div className="flex items-center gap-2 text-xs font-mono bg-muted/50 rounded-full px-3 py-1 animate-pulse">
|
||||||
|
<span className="font-bold text-primary">{Math.round(progress)}%</span>
|
||||||
|
<span className="truncate max-w-[200px]">{progressStatus || "Processing..."}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
status?.has_data && status.last_update && (
|
||||||
|
<div className="flex items-center gap-1.5 text-xs opacity-80">
|
||||||
|
<CheckCircle2 className="h-3.5 w-3.5 text-green-500" />
|
||||||
|
<span>已更新: {formatTimestamp(status.last_update.date)}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 2. 公司基础信息 */}
|
||||||
|
<div className="flex items-center gap-3 border-l pl-4 border-r pr-4 h-8">
|
||||||
|
<span className="font-bold truncate max-w-[200px]">{company.company_name}</span>
|
||||||
|
<Badge variant="secondary" className="font-mono h-6">{company.market} {company.symbol}</Badge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 3. 操作按钮 (刷新) */}
|
||||||
|
<Button
|
||||||
|
onClick={() => fetchData(true)}
|
||||||
|
disabled={fetching}
|
||||||
|
variant={!status?.has_data ? "default" : "outline"}
|
||||||
|
size="sm"
|
||||||
|
className="h-8"
|
||||||
|
>
|
||||||
|
{fetching ? (
|
||||||
|
<Loader2 className="h-3.5 w-3.5 animate-spin mr-2" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="h-3.5 w-3.5 mr-2" />
|
||||||
|
)}
|
||||||
|
{status?.has_data ? "更新数据" : "获取数据"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</HeaderPortal>
|
||||||
|
|
||||||
|
{/* 数据状态详情 (Card) */}
|
||||||
|
|
||||||
|
|
||||||
|
{/* 财务数据表格 */}
|
||||||
|
{status?.has_data && companyId && (
|
||||||
|
dataSource === 'Bloomberg' ? (
|
||||||
|
<BloombergView
|
||||||
|
companyId={companyId}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FinancialTables
|
||||||
|
companyId={companyId}
|
||||||
|
dataSource={dataSource}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* AI 分析触发器 */}
|
||||||
|
{status?.has_data && companyId && !analysisId && (
|
||||||
|
<AnalysisTrigger
|
||||||
|
companyId={companyId}
|
||||||
|
dataSource={dataSource}
|
||||||
|
model={oneTimeModel}
|
||||||
|
onAnalysisComplete={handleAnalysisComplete}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* AI 分析报告 */}
|
||||||
|
{analysisId && (
|
||||||
|
<AnalysisReport analysisId={analysisId} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 搜索组件的包装器,添加选择功能
|
||||||
|
function SearchStockWithSelection({ onSelect }: { onSelect: (company: SearchResult) => void }) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>开始新的分析</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<SearchStock onCompanySelect={onSelect} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
176
frontend/src/components/analysis-report.tsx
Normal file
176
frontend/src/components/analysis-report.tsx
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Loader2, FileText, TrendingUp, Users, ThumbsUp, ThumbsDown } from "lucide-react"
|
||||||
|
import { getAnalysisResult } from "@/lib/api"
|
||||||
|
import { MarkdownRenderer } from "@/components/markdown-renderer"
|
||||||
|
import type { AnalysisResultResponse } from "@/lib/types"
|
||||||
|
|
||||||
|
interface AnalysisReportProps {
|
||||||
|
analysisId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AnalysisReport({ analysisId }: AnalysisReportProps) {
|
||||||
|
const [data, setData] = useState<AnalysisResultResponse | null>(null)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [error, setError] = useState("")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function loadReport() {
|
||||||
|
setLoading(true)
|
||||||
|
setError("")
|
||||||
|
try {
|
||||||
|
const result = await getAnalysisResult(analysisId)
|
||||||
|
setData(result)
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.message || "加载分析报告失败")
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadReport()
|
||||||
|
}, [analysisId])
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6 flex items-center justify-center min-h-[400px]">
|
||||||
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="text-center text-destructive">{error}</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<FileText className="h-5 w-5" />
|
||||||
|
<CardTitle>AI 分析报告</CardTitle>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Badge variant="outline">{data.ai_model}</Badge>
|
||||||
|
<Badge variant="secondary">{data.total_tokens} tokens</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
使用 {data.data_source} 数据源
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Tabs defaultValue="profile" className="w-full">
|
||||||
|
<TabsList className="grid w-full grid-cols-5">
|
||||||
|
<TabsTrigger value="profile">
|
||||||
|
<FileText className="h-4 w-4 mr-1" />
|
||||||
|
公司简介
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="fundamental">
|
||||||
|
<TrendingUp className="h-4 w-4 mr-1" />
|
||||||
|
基本面
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="insider">
|
||||||
|
<Users className="h-4 w-4 mr-1" />
|
||||||
|
内部人士
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="bullish">
|
||||||
|
<ThumbsUp className="h-4 w-4 mr-1" />
|
||||||
|
看涨分析
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="bearish">
|
||||||
|
<ThumbsDown className="h-4 w-4 mr-1" />
|
||||||
|
看跌分析
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="profile" className="mt-4">
|
||||||
|
<ReportSection
|
||||||
|
content={data.company_profile}
|
||||||
|
title="公司简介"
|
||||||
|
tokens={data.tokens_by_section?.company_profile}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="fundamental" className="mt-4">
|
||||||
|
<ReportSection
|
||||||
|
content={data.fundamental_analysis}
|
||||||
|
title="基本面分析"
|
||||||
|
tokens={data.tokens_by_section?.fundamental_analysis}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="insider" className="mt-4">
|
||||||
|
<ReportSection
|
||||||
|
content={data.insider_analysis}
|
||||||
|
title="内部人士分析"
|
||||||
|
tokens={data.tokens_by_section?.insider_analysis}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="bullish" className="mt-4">
|
||||||
|
<ReportSection
|
||||||
|
content={data.bullish_analysis}
|
||||||
|
title="看涨分析"
|
||||||
|
tokens={data.tokens_by_section?.bullish_analysis}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="bearish" className="mt-4">
|
||||||
|
<ReportSection
|
||||||
|
content={data.bearish_analysis}
|
||||||
|
title="看跌分析"
|
||||||
|
tokens={data.tokens_by_section?.bearish_analysis}
|
||||||
|
/>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReportSectionProps {
|
||||||
|
content?: string | null
|
||||||
|
title: string
|
||||||
|
tokens?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReportSection({ content, title, tokens }: ReportSectionProps) {
|
||||||
|
if (!content) {
|
||||||
|
return (
|
||||||
|
<div className="text-center text-muted-foreground py-8">
|
||||||
|
{title}内容暂未生成
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="prose prose-sm max-w-none dark:prose-invert">
|
||||||
|
<MarkdownRenderer content={content} />
|
||||||
|
</div>
|
||||||
|
{tokens && (
|
||||||
|
<div className="text-xs text-muted-foreground text-right">
|
||||||
|
本节使用 {tokens} tokens
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
141
frontend/src/components/analysis-trigger.tsx
Normal file
141
frontend/src/components/analysis-trigger.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Loader2, Bot, CheckCircle2, AlertCircle } from "lucide-react"
|
||||||
|
import { startAIAnalysis, getAnalysisStatus } from "@/lib/api"
|
||||||
|
import type { AnalysisStatusResponse } from "@/lib/types"
|
||||||
|
|
||||||
|
interface AnalysisTriggerProps {
|
||||||
|
companyId: number
|
||||||
|
dataSource: string
|
||||||
|
model?: string
|
||||||
|
onAnalysisComplete: (analysisId: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AnalysisTrigger({
|
||||||
|
companyId,
|
||||||
|
dataSource,
|
||||||
|
model = "gemini-2.0-flash",
|
||||||
|
onAnalysisComplete
|
||||||
|
}: AnalysisTriggerProps) {
|
||||||
|
const [analysisId, setAnalysisId] = useState<number | null>(null)
|
||||||
|
const [status, setStatus] = useState<AnalysisStatusResponse | null>(null)
|
||||||
|
const [error, setError] = useState("")
|
||||||
|
const [polling, setPolling] = useState(false)
|
||||||
|
|
||||||
|
// 轮询分析状态
|
||||||
|
useEffect(() => {
|
||||||
|
if (!analysisId || !polling) return
|
||||||
|
|
||||||
|
const interval = setInterval(async () => {
|
||||||
|
try {
|
||||||
|
const data = await getAnalysisStatus(analysisId)
|
||||||
|
setStatus(data)
|
||||||
|
|
||||||
|
if (data.status === "completed") {
|
||||||
|
setPolling(false)
|
||||||
|
onAnalysisComplete(analysisId)
|
||||||
|
} else if (data.status === "failed") {
|
||||||
|
setPolling(false)
|
||||||
|
setError(data.error_message || "分析失败")
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Failed to get analysis status:", err)
|
||||||
|
}
|
||||||
|
}, 3000)
|
||||||
|
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [analysisId, polling])
|
||||||
|
|
||||||
|
const handleStartAnalysis = async () => {
|
||||||
|
setError("")
|
||||||
|
setPolling(true)
|
||||||
|
try {
|
||||||
|
const response = await startAIAnalysis({
|
||||||
|
company_id: companyId,
|
||||||
|
data_source: dataSource,
|
||||||
|
model
|
||||||
|
})
|
||||||
|
setAnalysisId(response.analysis_id)
|
||||||
|
} catch (err: any) {
|
||||||
|
setPolling(false)
|
||||||
|
setError(err.message || "启动AI分析失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusBadge = () => {
|
||||||
|
if (!status) return null
|
||||||
|
|
||||||
|
const statusMap: Record<string, { variant: any; label: string }> = {
|
||||||
|
'pending': { variant: 'secondary', label: '等待中' },
|
||||||
|
'in_progress': { variant: 'default', label: '分析中' },
|
||||||
|
'completed': { variant: 'default', label: '已完成' },
|
||||||
|
'failed': { variant: 'destructive', label: '失败' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = statusMap[status.status] || statusMap['pending']
|
||||||
|
return <Badge variant={config.variant}>{config.label}</Badge>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Bot className="h-5 w-5" />
|
||||||
|
<CardTitle>AI 分析</CardTitle>
|
||||||
|
</div>
|
||||||
|
{status && getStatusBadge()}
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
使用 {model} 进行深度分析
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
{error && (
|
||||||
|
<div className="flex items-center gap-2 text-sm text-destructive">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<span>{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{polling && status && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{status.status === "in_progress" ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
||||||
|
)}
|
||||||
|
<span className="text-sm font-medium">
|
||||||
|
{status.status === "pending" && "等待分析开始..."}
|
||||||
|
{status.status === "in_progress" && "AI正在分析财务数据..."}
|
||||||
|
{status.status === "completed" && "分析已完成"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
这可能需要1-2分钟,请耐心等待
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!polling && !status && (
|
||||||
|
<Button onClick={handleStartAnalysis} className="w-full">
|
||||||
|
<Bot className="mr-2 h-4 w-4" />
|
||||||
|
开始 AI 分析
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{status && status.status === "completed" && !polling && (
|
||||||
|
<div className="flex items-center gap-2 text-sm text-green-600">
|
||||||
|
<CheckCircle2 className="h-4 w-4" />
|
||||||
|
<span>分析报告已生成</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
530
frontend/src/components/bloomberg-view.tsx
Normal file
530
frontend/src/components/bloomberg-view.tsx
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { Loader2, DollarSign, RefreshCw } from "lucide-react"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { getFinancialData } from "@/lib/api"
|
||||||
|
import { formatNumber, formatLargeNumber, formatDate } from "@/lib/formatters"
|
||||||
|
import type { FinancialDataResponse } from "@/lib/types"
|
||||||
|
|
||||||
|
interface BloombergViewProps {
|
||||||
|
companyId: number
|
||||||
|
onBack?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BloombergView({ companyId, onBack }: BloombergViewProps) {
|
||||||
|
const [data, setData] = useState<FinancialDataResponse | null>(null)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [error, setError] = useState("")
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
setError("")
|
||||||
|
try {
|
||||||
|
console.log("Fetching Bloomberg data for company:", companyId)
|
||||||
|
const result = await getFinancialData(companyId, "Bloomberg")
|
||||||
|
console.log("Bloomberg data result:", result)
|
||||||
|
setData(result)
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Bloomberg fetch error:", err)
|
||||||
|
setError(err.message || "加载 Bloomberg 数据失败")
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadData()
|
||||||
|
}, [companyId])
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-[400px] space-y-4">
|
||||||
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||||
|
<p className="text-muted-foreground">正在加载 Bloomberg 原始数据...</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Card className="border-destructive">
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="text-center text-destructive space-y-4">
|
||||||
|
<p>{error}</p>
|
||||||
|
<Button variant="outline" onClick={loadData}>重试</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) return null
|
||||||
|
|
||||||
|
// 如果后端提供了统一数据字段,直接使用
|
||||||
|
const mergedData = data.unified_data || []
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-8">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h2 className="text-2xl font-bold flex items-center gap-2">
|
||||||
|
<DollarSign className="w-6 h-6" />
|
||||||
|
Bloomberg 财务数据总览
|
||||||
|
</h2>
|
||||||
|
<Button variant="outline" size="sm" onClick={loadData}>
|
||||||
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
|
刷新数据
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<RawDataTable title="财务数据总表" data={mergedData} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function RawDataTable({ data, title }: { data: any[], title: string }) {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-base">{title}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-center text-muted-foreground py-8">暂无数据</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取所有指标键值 (排除元数据)
|
||||||
|
const excludeKeys = ['id', 'company_code', 'code', 'symbol', 'market', 'update_date', 'create_time', 'end_date', 'ts_code']
|
||||||
|
|
||||||
|
// 从合并后的数据中收集所有可能的指标
|
||||||
|
const allIndicators = new Set<string>()
|
||||||
|
data.forEach(row => {
|
||||||
|
Object.keys(row).forEach(k => {
|
||||||
|
if (!excludeKeys.includes(k)) {
|
||||||
|
allIndicators.add(k)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 对指标进行逻辑排序/分组
|
||||||
|
const priorityOrder = [
|
||||||
|
'currency',
|
||||||
|
'__SECTION_MAIN__',
|
||||||
|
'roe', 'roce', 'roa',
|
||||||
|
'gross_margin', 'net_profit_margin', 'ebitda_margin',
|
||||||
|
'revenue', 'revenue_growth',
|
||||||
|
'net_income', 'netincome_growth',
|
||||||
|
'cash_from_operating', 'capital_expenditure', 'free_cash_flow',
|
||||||
|
'dividends_paid', 'dividend_payout_ratio', 'repurchase',
|
||||||
|
'total_assets', 'equity', 'goodwill',
|
||||||
|
'__SECTION_EXPENSE__',
|
||||||
|
'selling&marketing', 'general&admin', 'sg&a', 'r&d',
|
||||||
|
'depreciation', 'tax_rate',
|
||||||
|
'__SECTION_ASSET__',
|
||||||
|
'cash', 'inventory', 'accounts¬es_receivable', 'prepaid',
|
||||||
|
'property_plant&equipment', 'lt_investment',
|
||||||
|
'accounts_payable', 'st_defer_rev',
|
||||||
|
'st_debt', 'lt_debt', 'total_debt_ratio',
|
||||||
|
'__SECTION_TURNOVER__',
|
||||||
|
'inventory_days', 'days_sales_outstanding', 'payables_days',
|
||||||
|
'net_fixed_asset_turnover', 'asset_turnover',
|
||||||
|
'__SECTION_EFFICIENCY__',
|
||||||
|
'employee', 'num_of_employees',
|
||||||
|
'__SECTION_MARKET__',
|
||||||
|
'last_price', 'market_cap', 'pe', 'pb',
|
||||||
|
'dividend_yield', 'shareholders'
|
||||||
|
]
|
||||||
|
|
||||||
|
// Ensure section header is in the list to be sorted
|
||||||
|
const sectionKeys = [
|
||||||
|
'__SECTION_MAIN__', '__SECTION_EXPENSE__', '__SECTION_ASSET__',
|
||||||
|
'__SECTION_TURNOVER__', '__SECTION_EFFICIENCY__', '__SECTION_MARKET__'
|
||||||
|
]
|
||||||
|
sectionKeys.forEach(key => {
|
||||||
|
if (!allIndicators.has(key)) {
|
||||||
|
allIndicators.add(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const sortedIndicators = Array.from(allIndicators).sort((a, b) => {
|
||||||
|
const idxA = priorityOrder.indexOf(a)
|
||||||
|
const idxB = priorityOrder.indexOf(b)
|
||||||
|
|
||||||
|
// Items in priority list come first, sorted by their order in the list
|
||||||
|
if (idxA !== -1 && idxB !== -1) return idxA - idxB
|
||||||
|
|
||||||
|
// Items in priority list come before items not in list
|
||||||
|
if (idxA !== -1) return -1
|
||||||
|
if (idxB !== -1) return 1
|
||||||
|
|
||||||
|
// Remaining items sorted alphabetically
|
||||||
|
return a.localeCompare(b)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构建查找表: Map<DateString, RowData>
|
||||||
|
const dataMap = new Map()
|
||||||
|
data.forEach(row => {
|
||||||
|
dataMap.set(row.end_date, row)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 过滤日期: 只保留有营业收入 (revenue) 的列
|
||||||
|
const dates = Array.from(new Set(data.map(row => row.end_date)))
|
||||||
|
.filter(date => {
|
||||||
|
const row = dataMap.get(date)
|
||||||
|
// Check if revenue exists and is not null/undefined
|
||||||
|
return row && row.revenue !== null && row.revenue !== undefined
|
||||||
|
})
|
||||||
|
.sort((a, b) => new Date(b).getTime() - new Date(a).getTime())
|
||||||
|
|
||||||
|
|
||||||
|
// Tooltip State
|
||||||
|
const [tooltip, setTooltip] = useState<{ show: boolean, x: number, y: number, text: string }>({
|
||||||
|
show: false, x: 0, y: 0, text: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleMouseMove = (e: React.MouseEvent, text: string) => {
|
||||||
|
setTooltip({
|
||||||
|
show: true,
|
||||||
|
x: e.clientX,
|
||||||
|
y: e.clientY,
|
||||||
|
text
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseLeave = () => {
|
||||||
|
setTooltip(prev => ({ ...prev, show: false }))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取第一行数据的货币单位 (假设一致)
|
||||||
|
const currency = data[0]?.currency || 'CNY'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
{tooltip.show && (
|
||||||
|
<div
|
||||||
|
className="fixed z-50 px-2 py-1 text-xs text-white bg-black/90 rounded pointer-events-none whitespace-nowrap"
|
||||||
|
style={{
|
||||||
|
left: tooltip.x + 10,
|
||||||
|
top: tooltip.y + 10
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tooltip.text}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<table className="w-full caption-bottom text-sm">
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[200px] sticky left-0 top-0 bg-background z-50 border-r border-b shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]">
|
||||||
|
<div className="flex flex-col gap-1 py-1">
|
||||||
|
<span className="font-bold text-foreground">指标 / 报告期</span>
|
||||||
|
<span className="text-xs font-normal text-muted-foreground">(单位: 亿)</span>
|
||||||
|
</div>
|
||||||
|
</TableHead>
|
||||||
|
{dates.map(date => (
|
||||||
|
<TableHead key={date} className="text-right min-w-[120px] px-4 font-mono sticky top-0 bg-background z-40 border-b">
|
||||||
|
{formatDate(date)}
|
||||||
|
</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{sortedIndicators.map(indicator => {
|
||||||
|
if (indicator === '__SECTION_MAIN__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
主要指标
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (indicator === '__SECTION_EXPENSE__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
费用指标
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (indicator === '__SECTION_ASSET__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
资产结构
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (indicator === '__SECTION_TURNOVER__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
周转能力
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (indicator === '__SECTION_EFFICIENCY__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
人均效率
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (indicator === '__SECTION_MARKET__') {
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="bg-muted">
|
||||||
|
<TableCell
|
||||||
|
className="font-bold sticky left-0 bg-muted z-10 border-r py-1"
|
||||||
|
colSpan={1}
|
||||||
|
>
|
||||||
|
市场表现
|
||||||
|
</TableCell>
|
||||||
|
<TableCell colSpan={dates.length} className="bg-muted p-0" />
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableRow key={indicator} className="hover:bg-purple-100 dark:hover:bg-purple-900/40">
|
||||||
|
<TableCell
|
||||||
|
className={`font-medium sticky left-0 bg-background z-10 border-r shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)] cursor-help transition-colors hover:bg-muted ${['revenue_growth', 'netincome_growth'].includes(indicator) ? 'text-blue-600 italic dark:text-blue-400' : ''
|
||||||
|
}`}
|
||||||
|
onMouseMove={(e) => handleMouseMove(e, indicator)}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
>
|
||||||
|
<span>{formatColumnName(indicator)}</span>
|
||||||
|
</TableCell>
|
||||||
|
{dates.map(date => {
|
||||||
|
const row = dataMap.get(date)
|
||||||
|
const value = row ? row[indicator] : null
|
||||||
|
|
||||||
|
let highlightClass = ''
|
||||||
|
let textStyle = ''
|
||||||
|
|
||||||
|
if (value !== null && value !== undefined) {
|
||||||
|
const numVal = typeof value === 'string' ? parseFloat(value) : value
|
||||||
|
if (typeof numVal === 'number' && !isNaN(numVal)) {
|
||||||
|
if (indicator === 'roe' && numVal > 15) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (indicator === 'gross_margin' && numVal > 40) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (indicator === 'net_profit_margin' && numVal > 15) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (indicator === 'roce' && numVal > 15) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (indicator === 'roa' && numVal > 10) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (indicator === 'revenue_growth') {
|
||||||
|
if (numVal > 15) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (numVal < 0) highlightClass = 'bg-red-100 dark:bg-red-900/40'
|
||||||
|
}
|
||||||
|
else if (indicator === 'netincome_growth') {
|
||||||
|
if (numVal > 20) highlightClass = 'bg-green-100 dark:bg-green-900/40'
|
||||||
|
else if (numVal < 0) highlightClass = 'bg-red-100 dark:bg-red-900/40'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic text style based on value for growth rates
|
||||||
|
if (['revenue_growth', 'netincome_growth'].includes(indicator)) {
|
||||||
|
if (numVal < 0) {
|
||||||
|
textStyle = 'text-red-600 italic font-bold dark:text-red-400'
|
||||||
|
} else {
|
||||||
|
textStyle = 'text-blue-600 italic dark:text-blue-400'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for text style if value is missing/invalid but indicator is growth rate
|
||||||
|
if (textStyle === '' && ['revenue_growth', 'netincome_growth'].includes(indicator)) {
|
||||||
|
textStyle = 'text-blue-600 italic dark:text-blue-400'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableCell key={date} className={`text-right px-4 font-mono ${highlightClass} ${textStyle}`}>
|
||||||
|
{formatCellValue(indicator, value)}
|
||||||
|
</TableCell>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复用之前的 formatting 逻辑
|
||||||
|
function formatColumnName(column: string): string {
|
||||||
|
const nameMap: Record<string, string> = {
|
||||||
|
// --- 核心利润表 ---
|
||||||
|
'revenue': '营业收入',
|
||||||
|
'net_income': '净利润',
|
||||||
|
'operating_profit': '营业利润',
|
||||||
|
'gross_margin': '毛利率',
|
||||||
|
'net_profit_margin': '净利率',
|
||||||
|
'ebitda_margin': 'EBITDA利润率',
|
||||||
|
'sg&a': '销售管理费用(SG&A)',
|
||||||
|
'selling&marketing': '销售费用',
|
||||||
|
'general&admin': '管理费用',
|
||||||
|
'ga_exp': '管理费用', // Alias
|
||||||
|
'rd_exp': '研发费用',
|
||||||
|
'r&d': '研发费用',
|
||||||
|
'depreciation': '折旧',
|
||||||
|
'tax_rate': '有效税率',
|
||||||
|
'dividends': '分红',
|
||||||
|
'dividend_payout_ratio': '分红支付率',
|
||||||
|
'netincome_growth': '净利润增长率',
|
||||||
|
'revenue_growth': '营收增长率',
|
||||||
|
|
||||||
|
// --- 资产负债表 ---
|
||||||
|
'total_assets': '总资产',
|
||||||
|
'total_liabilities': '总负债',
|
||||||
|
'shareholders_equity': '净资产', // Alias
|
||||||
|
'total_equity': '净资产', // Alias
|
||||||
|
'equity': '净资产', // Real Bloomberg Key
|
||||||
|
'cash': '现金',
|
||||||
|
'inventory': '存货',
|
||||||
|
'accounts¬es_receivable': '应收账款及票据',
|
||||||
|
'receivables': '应收账款',
|
||||||
|
'accounts_payable': '应付账款',
|
||||||
|
'prepayment': '预付款项',
|
||||||
|
'prepaid': '预付款项',
|
||||||
|
'fixed_assets': '固定资产',
|
||||||
|
'property_plant&equipment': '固定资产(PP&E)',
|
||||||
|
'long_term_investments': '长期投资',
|
||||||
|
'lt_investment': '长期投资',
|
||||||
|
'short_term_debt': '短期借款',
|
||||||
|
'st_debt': '短期借款',
|
||||||
|
'long_term_debt': '长期借款',
|
||||||
|
'lt_debt': '长期借款',
|
||||||
|
'deferred_revenue': '递延收入',
|
||||||
|
'st_defer_rev': '短期递延收入',
|
||||||
|
'goodwill': '商誉',
|
||||||
|
'total_debt_ratio': '总债务比率',
|
||||||
|
|
||||||
|
// --- 现金流量表 ---
|
||||||
|
'cash_from_operating': '经营现金流',
|
||||||
|
'ocf': '经营现金流', // Alias
|
||||||
|
'capital_expenditure': '资本支出',
|
||||||
|
'capex': '资本支出', // Alias
|
||||||
|
'free_cash_flow': '自由现金流',
|
||||||
|
'fcf': '自由现金流', // Alias
|
||||||
|
'dividends_paid': '支付股息',
|
||||||
|
'repurchase': '股份回购',
|
||||||
|
|
||||||
|
// --- 运营效率/周转 ---
|
||||||
|
'asset_turnover': '总资产周转率',
|
||||||
|
'net_fixed_asset_turnover': '固定资产周转率', // Correct Bloomberg Key
|
||||||
|
'net_fixed_asset_turn': '固定资产周转率', // Alias just in case
|
||||||
|
'inventory_days': '存货周转天数',
|
||||||
|
'invent_days': '存货周转天数',
|
||||||
|
'days_sales_outstanding': '应收账款周转天数',
|
||||||
|
'payables_days': '应付账款周转天数',
|
||||||
|
'employee': '员工人数',
|
||||||
|
'num_of_employees': '员工人数',
|
||||||
|
|
||||||
|
// --- 估值与市场 ---
|
||||||
|
'pe': '市盈率(PE)',
|
||||||
|
'pe_ratio': '市盈率(PE)',
|
||||||
|
'pb': '市净率(PB)',
|
||||||
|
'pb_ratio': '市净率(PB)',
|
||||||
|
'market_cap': '市值',
|
||||||
|
'price': '最新股价',
|
||||||
|
'last_price': '最新股价',
|
||||||
|
'roe': 'ROE',
|
||||||
|
'roa': 'ROA',
|
||||||
|
'roce': 'ROCE',
|
||||||
|
'dividend_yield': '股息率',
|
||||||
|
'shareholders': '股东人数',
|
||||||
|
'company_name': '公司名称',
|
||||||
|
'ipo_date': '上市日期',
|
||||||
|
'rev_abroad': '海外收入占比',
|
||||||
|
'currency': '货币',
|
||||||
|
}
|
||||||
|
return nameMap[column.toLowerCase()] || column
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCellValue(column: string, value: any): string {
|
||||||
|
if (value === null || value === undefined) return '-'
|
||||||
|
|
||||||
|
// 尝试解析文本数字
|
||||||
|
let numVal = value
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
const parsed = parseFloat(value)
|
||||||
|
if (!isNaN(parsed)) {
|
||||||
|
numVal = parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof numVal === 'number') {
|
||||||
|
const lowerCol = column.toLowerCase()
|
||||||
|
|
||||||
|
// Special scaling for tax_rate
|
||||||
|
if (lowerCol === 'tax_rate') {
|
||||||
|
numVal = numVal * 100
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRatio = ['roe', 'roce', 'roa', 'gross_margin', 'net_profit_margin', 'ebitda_margin', 'dividend_yield', 'rev_abroad', 'tax_rate', 'revenue_growth', 'netincome_growth'].includes(lowerCol)
|
||||||
|
|
||||||
|
// Scale huge monetary values to "Yi" (100 Million)
|
||||||
|
// Bloomberg raw data is in Millions.
|
||||||
|
// Millions -> Yi (100 Millions) = divide by 100.
|
||||||
|
const isMoney = [
|
||||||
|
'revenue', 'net_income', 'operating_profit',
|
||||||
|
'total_assets', 'total_liabilities', 'equity', 'shareholders_equity', 'total_equity',
|
||||||
|
'cash', 'inventory', 'accounts¬es_receivable', 'receivables', 'accounts_payable', 'prepaid', 'prepayment',
|
||||||
|
'property_plant&equipment', 'fixed_assets', 'lt_investment', 'long_term_investments',
|
||||||
|
'st_debt', 'short_term_debt', 'lt_debt', 'long_term_debt', 'st_defer_rev', 'deferred_revenue', 'goodwill',
|
||||||
|
'cash_from_operating', 'capital_expenditure', 'capex', 'free_cash_flow', 'fcf',
|
||||||
|
'dividends_paid', 'repurchase',
|
||||||
|
'sg&a', 'selling&marketing', 'general&admin', 'r&d', 'depreciation',
|
||||||
|
'market_cap'
|
||||||
|
].includes(lowerCol)
|
||||||
|
|
||||||
|
if (isMoney) {
|
||||||
|
numVal = numVal / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRatio) {
|
||||||
|
return numVal.toLocaleString('en-US', {
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
}) + '%'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果大于 1000,不保留小数;否则保留两位小数
|
||||||
|
const isLarge = Math.abs(numVal) > 1000
|
||||||
|
return numVal.toLocaleString('en-US', {
|
||||||
|
minimumFractionDigits: isLarge ? 0 : 2,
|
||||||
|
maximumFractionDigits: isLarge ? 0 : 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
95
frontend/src/components/data-source-selector.tsx
Normal file
95
frontend/src/components/data-source-selector.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { Database } from "lucide-react"
|
||||||
|
import { getAvailableSources } from "@/lib/api"
|
||||||
|
import type { DataSourceInfo } from "@/lib/types"
|
||||||
|
|
||||||
|
interface DataSourceSelectorProps {
|
||||||
|
market: string
|
||||||
|
selectedSource: string
|
||||||
|
onSourceChange: (source: string) => void
|
||||||
|
disabled?: boolean
|
||||||
|
showLabel?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataSourceSelector({
|
||||||
|
market,
|
||||||
|
selectedSource,
|
||||||
|
onSourceChange,
|
||||||
|
disabled = false,
|
||||||
|
showLabel = true
|
||||||
|
}: DataSourceSelectorProps) {
|
||||||
|
const [sources, setSources] = useState<DataSourceInfo[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function loadSources() {
|
||||||
|
if (!market) return
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
const data = await getAvailableSources(market)
|
||||||
|
setSources(data.sources.filter(s => s.available))
|
||||||
|
|
||||||
|
// 如果当前选中的源不可用,自动选择第一个可用的
|
||||||
|
const availableSources = data.sources.filter(s => s.available)
|
||||||
|
if (availableSources.length > 0 && !availableSources.find(s => s.source === selectedSource)) {
|
||||||
|
onSourceChange(availableSources[0].source)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to load data sources:", error)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSources()
|
||||||
|
}, [market])
|
||||||
|
|
||||||
|
if (sources.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{showLabel && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Database className="h-4 w-4 text-muted-foreground" />
|
||||||
|
<Label>数据源</Label>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Select
|
||||||
|
value={selectedSource}
|
||||||
|
onValueChange={onSourceChange}
|
||||||
|
disabled={disabled || loading}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="选择数据源" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent portal={false}>
|
||||||
|
{sources.map((source) => (
|
||||||
|
<SelectItem key={source.source} value={source.source}>
|
||||||
|
{source.source}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
{
|
||||||
|
sources.length === 1 && (
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
该市场仅支持 {sources[0].source} 数据源
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div >
|
||||||
|
)
|
||||||
|
}
|
||||||
215
frontend/src/components/data-status-card.tsx
Normal file
215
frontend/src/components/data-status-card.tsx
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Loader2, Database, CheckCircle2, AlertCircle, RefreshCw } from "lucide-react"
|
||||||
|
import { checkDataStatus, fetchFinancialData, getFetchStatus } from "@/lib/api"
|
||||||
|
import { formatTimestamp } from "@/lib/formatters"
|
||||||
|
import type { DataCheckResponse, DataUpdateResponse, SearchResult } from "@/lib/types"
|
||||||
|
|
||||||
|
interface DataStatusCardProps {
|
||||||
|
company: SearchResult
|
||||||
|
dataSource: string
|
||||||
|
onDataReady: (companyId: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataStatusCard({ company, dataSource, onDataReady }: DataStatusCardProps) {
|
||||||
|
const [status, setStatus] = useState<DataCheckResponse | null>(null)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [fetching, setFetching] = useState(false)
|
||||||
|
const [updateId, setUpdateId] = useState<number | null>(null)
|
||||||
|
const [updateStatus, setUpdateStatus] = useState<DataUpdateResponse | null>(null)
|
||||||
|
const [error, setError] = useState<string>("")
|
||||||
|
|
||||||
|
// 检查数据状态
|
||||||
|
const checkStatus = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
setError("")
|
||||||
|
try {
|
||||||
|
const data = await checkDataStatus(company.market, company.symbol, dataSource)
|
||||||
|
setStatus(data)
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.message || "检查数据状态失败")
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkStatus()
|
||||||
|
}, [company, dataSource])
|
||||||
|
|
||||||
|
// 轮询获取状态
|
||||||
|
useEffect(() => {
|
||||||
|
if (!updateId || !fetching) return
|
||||||
|
|
||||||
|
const interval = setInterval(async () => {
|
||||||
|
try {
|
||||||
|
const data = await getFetchStatus(updateId)
|
||||||
|
setUpdateStatus(data)
|
||||||
|
|
||||||
|
if (data.status === "completed") {
|
||||||
|
setFetching(false)
|
||||||
|
setUpdateId(null)
|
||||||
|
// 刷新数据状态
|
||||||
|
await checkStatus()
|
||||||
|
// 通知父组件数据已就绪
|
||||||
|
if (data.company_id) {
|
||||||
|
onDataReady(data.company_id)
|
||||||
|
}
|
||||||
|
} else if (data.status === "failed") {
|
||||||
|
setFetching(false)
|
||||||
|
setUpdateId(null)
|
||||||
|
setError(data.error_message || "数据获取失败")
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Failed to get fetch status:", err)
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
|
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [updateId, fetching])
|
||||||
|
|
||||||
|
// 触发数据获取
|
||||||
|
const handleFetchData = async (forceRefresh = false) => {
|
||||||
|
setFetching(true)
|
||||||
|
setError("")
|
||||||
|
try {
|
||||||
|
const response = await fetchFinancialData({
|
||||||
|
market: company.market,
|
||||||
|
symbol: company.symbol,
|
||||||
|
company_name: company.company_name,
|
||||||
|
data_source: dataSource,
|
||||||
|
force_refresh: forceRefresh
|
||||||
|
})
|
||||||
|
setUpdateId(response.update_id)
|
||||||
|
} catch (err: any) {
|
||||||
|
setFetching(false)
|
||||||
|
setError(err.message || "启动数据获取失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6 flex items-center justify-center">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Database className="h-5 w-5" />
|
||||||
|
<CardTitle>数据状态</CardTitle>
|
||||||
|
</div>
|
||||||
|
<Badge variant={status?.has_data ? "default" : "secondary"}>
|
||||||
|
{dataSource}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
{company.company_name} ({company.symbol})
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
{error && (
|
||||||
|
<div className="flex items-center gap-2 text-sm text-destructive">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<span>{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{fetching && updateStatus && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
<span className="text-sm font-medium">
|
||||||
|
{updateStatus.status === "in_progress" ? "正在获取数据..." : "等待中..."}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{updateStatus.fetched_tables && updateStatus.fetched_tables.length > 0 && (
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
已获取: {updateStatus.fetched_tables.join(", ")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!fetching && status?.has_data && status.last_update && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-green-600">
|
||||||
|
<CheckCircle2 className="h-4 w-4" />
|
||||||
|
<span>数据已就绪</span>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||||
|
<div>
|
||||||
|
<span className="text-muted-foreground">最后更新:</span>
|
||||||
|
<br />
|
||||||
|
<span className="font-mono text-xs">
|
||||||
|
{formatTimestamp(status.last_update.date)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{status.last_update.data_start_date && status.last_update.data_end_date && (
|
||||||
|
<div>
|
||||||
|
<span className="text-muted-foreground">数据范围:</span>
|
||||||
|
<br />
|
||||||
|
<span className="font-mono text-xs">
|
||||||
|
{status.last_update.data_start_date} ~ {status.last_update.data_end_date}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{status.last_update.table_counts && (
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
表格数据: {Object.entries(status.last_update.table_counts).map(
|
||||||
|
([table, count]) => `${table}(${count}行)`
|
||||||
|
).join(", ")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!fetching && !status?.has_data && (
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
暂无该数据源的数据
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{!status?.has_data && (
|
||||||
|
<Button
|
||||||
|
onClick={() => handleFetchData(false)}
|
||||||
|
disabled={fetching}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{fetching ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
获取中...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"获取数据"
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{status?.has_data && !fetching && (
|
||||||
|
<Button
|
||||||
|
onClick={() => handleFetchData(true)}
|
||||||
|
variant="outline"
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<RefreshCw className="mr-2 h-4 w-4" />
|
||||||
|
更新数据
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
135
frontend/src/components/data-status-display.tsx
Normal file
135
frontend/src/components/data-status-display.tsx
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Loader2, Database, CheckCircle2, AlertCircle } from "lucide-react"
|
||||||
|
import { Progress } from "@/components/ui/progress"
|
||||||
|
import type { DataCheckResponse, DataUpdateResponse, SearchResult } from "@/lib/types"
|
||||||
|
import { formatTimestamp } from "@/lib/formatters"
|
||||||
|
|
||||||
|
interface DataStatusDisplayProps {
|
||||||
|
company: SearchResult
|
||||||
|
dataSource: string
|
||||||
|
status: DataCheckResponse | null
|
||||||
|
updateStatus: DataUpdateResponse | null
|
||||||
|
loading: boolean
|
||||||
|
fetching: boolean
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataStatusDisplay({
|
||||||
|
company,
|
||||||
|
dataSource,
|
||||||
|
status,
|
||||||
|
updateStatus,
|
||||||
|
loading,
|
||||||
|
fetching,
|
||||||
|
error
|
||||||
|
}: DataStatusDisplayProps) {
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6 flex items-center justify-center">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we should show fetching state
|
||||||
|
const isUpdating = fetching && updateStatus;
|
||||||
|
const progress = updateStatus?.progress_percentage || 0;
|
||||||
|
const message = updateStatus?.progress_message || (updateStatus?.status === "in_progress" ? "正在获取数据..." : "准备中...");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="pb-3">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Database className="h-5 w-5" />
|
||||||
|
<CardTitle>数据状态</CardTitle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
{error && (
|
||||||
|
<div className="flex items-center gap-2 text-sm text-destructive bg-destructive/10 p-3 rounded-md">
|
||||||
|
<AlertCircle className="h-4 w-4" />
|
||||||
|
<span>{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 正在更新状态 */}
|
||||||
|
{isUpdating && (
|
||||||
|
<div className="space-y-4 p-4 bg-muted/50 rounded-lg border">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin text-primary" />
|
||||||
|
<span className="font-medium">
|
||||||
|
{message}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-muted-foreground font-mono">{Math.round(progress)}%</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Progress value={progress} className="h-2" />
|
||||||
|
|
||||||
|
{updateStatus?.fetched_tables && updateStatus.fetched_tables.length > 0 && (
|
||||||
|
<div className="text-xs text-muted-foreground mt-2">
|
||||||
|
已完成: {updateStatus.fetched_tables.map(t => t.replace('tushare_', '').replace('cn_', '')).join(", ")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 静态数据状态 (非更新时显示) */}
|
||||||
|
{!isUpdating && status?.has_data && status.last_update && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 text-sm text-green-600 font-medium">
|
||||||
|
<CheckCircle2 className="h-4 w-4" />
|
||||||
|
<span>数据已就绪</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-2 p-3 bg-muted/30 rounded-md">
|
||||||
|
<div>
|
||||||
|
<span className="text-muted-foreground text-xs uppercase tracking-wider">最后更新</span>
|
||||||
|
<div className="font-mono text-sm mt-0.5">
|
||||||
|
{formatTimestamp(status.last_update.date)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{status.last_update.data_start_date && status.last_update.data_end_date && (
|
||||||
|
<div>
|
||||||
|
<span className="text-muted-foreground text-xs uppercase tracking-wider">数据范围</span>
|
||||||
|
<div className="font-mono text-sm mt-0.5">
|
||||||
|
{status.last_update.data_start_date} <span className="text-muted-foreground">至</span> {status.last_update.data_end_date}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{status.last_update.table_counts && (
|
||||||
|
<div className="text-xs text-muted-foreground pt-2 flex flex-wrap gap-2">
|
||||||
|
{Object.entries(status.last_update.table_counts).map(([table, count]) => (
|
||||||
|
<Badge key={table} variant="secondary" className="font-normal">
|
||||||
|
{table.replace('tushare_', '').replace('cn_', '')}: {count}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 无数据状态 */}
|
||||||
|
{!isUpdating && !status?.has_data && !error && (
|
||||||
|
<div className="flex flex-col items-center justify-center py-8 text-center text-muted-foreground space-y-2">
|
||||||
|
<Database className="h-8 w-8 opacity-20" />
|
||||||
|
<p>暂无该数据源的数据</p>
|
||||||
|
<p className="text-xs">请点击右上角的"获取数据"按钮开始同步</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
306
frontend/src/components/financial-tables.tsx
Normal file
306
frontend/src/components/financial-tables.tsx
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { Loader2, TrendingUp, TrendingDown, DollarSign } from "lucide-react"
|
||||||
|
import { getFinancialData } from "@/lib/api"
|
||||||
|
import { formatNumber, formatLargeNumber, formatDate } from "@/lib/formatters"
|
||||||
|
import type { FinancialDataResponse } from "@/lib/types"
|
||||||
|
|
||||||
|
interface FinancialTablesProps {
|
||||||
|
companyId: number
|
||||||
|
dataSource: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FinancialTables({ companyId, dataSource }: FinancialTablesProps) {
|
||||||
|
const [data, setData] = useState<FinancialDataResponse | null>(null)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [error, setError] = useState("")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function loadData() {
|
||||||
|
setLoading(true)
|
||||||
|
setError("")
|
||||||
|
try {
|
||||||
|
const result = await getFinancialData(companyId, dataSource)
|
||||||
|
setData(result)
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.message || "加载财务数据失败")
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData()
|
||||||
|
}, [companyId, dataSource])
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6 flex items-center justify-center min-h-[300px]">
|
||||||
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="text-center text-destructive">{error}</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBloomberg = dataSource === 'Bloomberg'
|
||||||
|
const TableComponent = isBloomberg ? TransposedFinancialTable : FinancialTable
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<DollarSign className="h-5 w-5" />
|
||||||
|
财务数据
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold flex items-center gap-2">
|
||||||
|
<TrendingUp className="h-4 w-4" />
|
||||||
|
利润表
|
||||||
|
</h3>
|
||||||
|
<TableComponent
|
||||||
|
data={data.income_statement}
|
||||||
|
title="利润表"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold flex items-center gap-2">
|
||||||
|
<TrendingDown className="h-4 w-4" />
|
||||||
|
资产负债表
|
||||||
|
</h3>
|
||||||
|
<TableComponent
|
||||||
|
data={data.balance_sheet}
|
||||||
|
title="资产负债表"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold flex items-center gap-2">
|
||||||
|
<DollarSign className="h-4 w-4" />
|
||||||
|
现金流量表
|
||||||
|
</h3>
|
||||||
|
<TableComponent
|
||||||
|
data={data.cash_flow}
|
||||||
|
title="现金流量表"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold flex items-center gap-2">
|
||||||
|
<TrendingUp className="h-4 w-4" />
|
||||||
|
估值数据
|
||||||
|
</h3>
|
||||||
|
<TableComponent
|
||||||
|
data={data.daily_basic}
|
||||||
|
title="估值数据"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FinancialTableProps {
|
||||||
|
data: Record<string, any>[]
|
||||||
|
title: string
|
||||||
|
icon?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
function FinancialTable({ data, title }: FinancialTableProps) {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="text-center text-muted-foreground py-8">
|
||||||
|
暂无{title}数据
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有列名(排除 id, code, ticker, market, update_date 等元数据列)
|
||||||
|
const excludeColumns = ['id', 'code', 'ticker', 'market', 'update_date', 'ts_code']
|
||||||
|
const columns = Object.keys(data[0]).filter(key => !excludeColumns.includes(key))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableHead key={column} className="whitespace-nowrap">
|
||||||
|
{formatColumnName(column)}
|
||||||
|
</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{data.map((row, idx) => (
|
||||||
|
<TableRow key={idx}>
|
||||||
|
{columns.map((column) => (
|
||||||
|
<TableCell key={column} className="font-mono text-right">
|
||||||
|
{formatCellValue(column, row[column])}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
<div className="px-4 py-2 text-xs text-muted-foreground border-t">
|
||||||
|
共 {data.length} 条记录
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TransposedFinancialTable({ data, title }: FinancialTableProps) {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="text-center text-muted-foreground py-8">
|
||||||
|
暂无{title}数据
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 提取所有日期 (Headers)
|
||||||
|
// 假设 data 是按时间倒序排列的 (API通常如此)
|
||||||
|
// 如果不是,建议在这里做个sort
|
||||||
|
const sortedData = [...data].sort((a, b) =>
|
||||||
|
new Date(b.end_date).getTime() - new Date(a.end_date).getTime()
|
||||||
|
)
|
||||||
|
const dates = sortedData.map(row => row['end_date']).filter(Boolean)
|
||||||
|
|
||||||
|
// 2. 提取所有指标 (Rows)
|
||||||
|
const excludeColumns = ['id', 'code', 'ticker', 'market', 'update_date', 'ts_code', 'end_date']
|
||||||
|
// 从第一行获取所有指标key
|
||||||
|
const indicators = Object.keys(sortedData[0]).filter(key => !excludeColumns.includes(key))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{/* 第一列:指标名称 */}
|
||||||
|
<TableHead className="whitespace-nowrap w-[200px] min-w-[150px] sticky left-0 bg-background z-10 border-r shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]">
|
||||||
|
指标 / 报告期
|
||||||
|
</TableHead>
|
||||||
|
{/* 其他列:日期 */}
|
||||||
|
{dates.map((date, idx) => (
|
||||||
|
<TableHead key={idx} className="whitespace-nowrap text-right px-4 min-w-[120px]">
|
||||||
|
{formatDate(date)}
|
||||||
|
</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{indicators.map((indicator) => (
|
||||||
|
<TableRow key={indicator}>
|
||||||
|
{/* 指标名 */}
|
||||||
|
<TableCell className="font-medium sticky left-0 bg-background z-10 border-r shadow-[2px_0_5px_-2px_rgba(0,0,0,0.1)]">
|
||||||
|
{formatColumnName(indicator)}
|
||||||
|
</TableCell>
|
||||||
|
{/* 值 */}
|
||||||
|
{sortedData.map((row, rowIdx) => (
|
||||||
|
<TableCell key={rowIdx} className="font-mono text-right px-4">
|
||||||
|
{formatCellValue(indicator, row[indicator])}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
<div className="px-4 py-2 text-xs text-muted-foreground border-t">
|
||||||
|
共 {indicators.length} 个指标
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化列名
|
||||||
|
function formatColumnName(column: string): string {
|
||||||
|
const nameMap: Record<string, string> = {
|
||||||
|
'end_date': '报告期',
|
||||||
|
// Common
|
||||||
|
'revenue': '营业收入',
|
||||||
|
'net_income': '净利润',
|
||||||
|
// Balance Sheet
|
||||||
|
'total_assets': '总资产',
|
||||||
|
'total_liabilities': '总负债',
|
||||||
|
'total_equity': '股东权益',
|
||||||
|
'cash': '货币资金',
|
||||||
|
'inventory': '存货',
|
||||||
|
'receivables': '应收账款',
|
||||||
|
'prepayment': '预付款项',
|
||||||
|
'fixed_assets': '固定资产',
|
||||||
|
'long_term_investments': '长期投资',
|
||||||
|
'accounts_payable': '应付账款',
|
||||||
|
'short_term_debt': '短期借款',
|
||||||
|
'long_term_debt': '长期借款',
|
||||||
|
'deferred_revenue': '递延收入',
|
||||||
|
'goodwill': '商誉',
|
||||||
|
// Income
|
||||||
|
'sga_exp': '销售管理费用',
|
||||||
|
'selling_marketing_exp': '销售费用',
|
||||||
|
'ga_exp': '管理费用',
|
||||||
|
'rd_exp': '研发费用',
|
||||||
|
'depreciation': '折旧',
|
||||||
|
'operating_profit': '营业利润',
|
||||||
|
// Cash Flow
|
||||||
|
'ocf': '经营现金流',
|
||||||
|
'capex': '资本支出',
|
||||||
|
'dividends': '分红支付',
|
||||||
|
'fcf': '自由现金流',
|
||||||
|
// Metrics
|
||||||
|
'pe': '市盈率(PE)',
|
||||||
|
'pb': '市净率(PB)',
|
||||||
|
'market_cap': '市值',
|
||||||
|
'price': '最新股价',
|
||||||
|
'roe': 'ROE',
|
||||||
|
'roa': 'ROA',
|
||||||
|
}
|
||||||
|
return nameMap[column] || column
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化单元格值
|
||||||
|
function formatCellValue(column: string, value: any): string {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日期列
|
||||||
|
if (column.includes('date')) {
|
||||||
|
return formatDate(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数值列
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
// 比率和百分比(PE、PB等)
|
||||||
|
if (column.includes('ratio') || column.includes('pe') || column.includes('pb') || column.includes('margin') || column.includes('roe') || column.includes('roa') || column.includes('rate')) {
|
||||||
|
return formatNumber(value)
|
||||||
|
}
|
||||||
|
// 大数字(金额、市值等)
|
||||||
|
return formatLargeNumber(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
20
frontend/src/components/header-portal.tsx
Normal file
20
frontend/src/components/header-portal.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { createPortal } from "react-dom"
|
||||||
|
|
||||||
|
export const HeaderPortal = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
return () => setMounted(false)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!mounted) return null
|
||||||
|
|
||||||
|
const target = document.getElementById("header-portal-target")
|
||||||
|
if (!target) return null
|
||||||
|
|
||||||
|
return createPortal(children, target)
|
||||||
|
}
|
||||||
121
frontend/src/components/header-search.tsx
Normal file
121
frontend/src/components/header-search.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useState, useRef, useEffect } from "react"
|
||||||
|
import { searchStock } from "@/lib/api"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Search, Loader2 } from "lucide-react"
|
||||||
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import type { SearchResult } from "@/lib/types"
|
||||||
|
import { useRouter } from "next/navigation"
|
||||||
|
|
||||||
|
export function HeaderSearch({ defaultDataSource }: { defaultDataSource?: string }) {
|
||||||
|
const router = useRouter()
|
||||||
|
const [query, setQuery] = useState("")
|
||||||
|
const [results, setResults] = useState<SearchResult[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
// Handle clicks outside to close dropdown
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener("mousedown", handleClickOutside)
|
||||||
|
return () => document.removeEventListener("mousedown", handleClickOutside)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSearch = async () => {
|
||||||
|
if (!query.trim()) return
|
||||||
|
setLoading(true)
|
||||||
|
setOpen(true)
|
||||||
|
try {
|
||||||
|
// Using default model for light search
|
||||||
|
const data = await searchStock(query, "gemini-2.5-flash")
|
||||||
|
setResults(Array.isArray(data) ? data : [])
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Search failed", err)
|
||||||
|
setResults([])
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = (company: SearchResult) => {
|
||||||
|
// Use default data source from props if available
|
||||||
|
let source = defaultDataSource || "Bloomberg"
|
||||||
|
|
||||||
|
// If no default provided, keep original fallback logic (though mostly covered by default)
|
||||||
|
if (!defaultDataSource) {
|
||||||
|
if (company.market === 'CN') source = "Tushare"
|
||||||
|
else if (company.market === 'HK') source = "iFinD"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push to URL
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
params.set('symbol', company.symbol)
|
||||||
|
params.set('market', company.market)
|
||||||
|
params.set('source', source)
|
||||||
|
params.set('name', company.company_name)
|
||||||
|
params.set('t', Date.now().toString())
|
||||||
|
|
||||||
|
router.push(`/?${params.toString()}`)
|
||||||
|
|
||||||
|
// Close and clear
|
||||||
|
setOpen(false)
|
||||||
|
setQuery("")
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-full max-w-md" ref={containerRef}>
|
||||||
|
<div className="relative flex items-center">
|
||||||
|
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||||
|
<Input
|
||||||
|
className="pl-9 h-9 w-full bg-background/50 border-input/60 focus:bg-background transition-colors"
|
||||||
|
placeholder="搜索代码或名称..."
|
||||||
|
value={query}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onFocus={() => { if (results.length > 0) setOpen(true) }}
|
||||||
|
/>
|
||||||
|
{loading && (
|
||||||
|
<Loader2 className="absolute right-2.5 top-1/2 -translate-y-1/2 h-4 w-4 animate-spin text-muted-foreground" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{open && results.length > 0 && (
|
||||||
|
<div className="absolute top-full mt-2 left-0 w-full bg-popover text-popover-foreground rounded-md border shadow-md z-[80] overflow-hidden max-h-[400px] overflow-y-auto">
|
||||||
|
<div className="p-1">
|
||||||
|
{results.map((result) => (
|
||||||
|
<button
|
||||||
|
key={`${result.market}-${result.symbol}`}
|
||||||
|
className="w-full flex items-center justify-between p-2 hover:bg-accent hover:text-accent-foreground rounded-sm text-sm text-left transition-colors"
|
||||||
|
onClick={() => handleSelect(result)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col overflow-hidden">
|
||||||
|
<span className="font-medium truncate">{result.company_name}</span>
|
||||||
|
<span className="text-xs text-muted-foreground font-mono">{result.symbol}</span>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="shrink-0 ml-2 text-[10px] h-5">{result.market}</Badge>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{open && !loading && results.length === 0 && query && (
|
||||||
|
<div className="absolute top-full mt-2 left-0 w-full bg-popover text-popover-foreground rounded-md border shadow-md z-[80] p-4 text-sm text-center text-muted-foreground">
|
||||||
|
未找到结果,请检查输入或丰富内容
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -2,16 +2,137 @@
|
|||||||
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { MonitorPlay } from "lucide-react"
|
import { MonitorPlay } from "lucide-react"
|
||||||
|
import { useRouter, useSearchParams } from "next/navigation"
|
||||||
|
import { HeaderSearch } from "@/components/header-search"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select"
|
||||||
|
|
||||||
|
type RecentCompany = {
|
||||||
|
market: string
|
||||||
|
symbol: string
|
||||||
|
company_name: string
|
||||||
|
last_update: string
|
||||||
|
}
|
||||||
|
|
||||||
export function NavHeader() {
|
export function NavHeader() {
|
||||||
|
const router = useRouter()
|
||||||
|
const searchParams = useSearchParams()
|
||||||
|
|
||||||
|
const [dataSource, setDataSource] = useState("Bloomberg")
|
||||||
|
const [companies, setCompanies] = useState<RecentCompany[]>([])
|
||||||
|
|
||||||
|
// Sync state with URL params
|
||||||
|
useEffect(() => {
|
||||||
|
const sourceParam = searchParams.get('source')
|
||||||
|
if (sourceParam && sourceParam !== dataSource) {
|
||||||
|
setDataSource(sourceParam)
|
||||||
|
}
|
||||||
|
}, [searchParams])
|
||||||
|
|
||||||
|
const handleDataSourceChange = (newSource: string) => {
|
||||||
|
setDataSource(newSource)
|
||||||
|
|
||||||
|
// If viewing a company, update URL to trigger reload with new source
|
||||||
|
const currentSymbol = searchParams.get('symbol')
|
||||||
|
if (currentSymbol) {
|
||||||
|
const params = new URLSearchParams(searchParams.toString())
|
||||||
|
params.set('source', newSource)
|
||||||
|
router.push(`/?${params.toString()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch recent companies
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchRecent = async () => {
|
||||||
|
try {
|
||||||
|
// Use relative path since we are in same domain mainly
|
||||||
|
const res = await fetch(`/api/data/recent?data_source=${dataSource}`)
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
setCompanies(Array.isArray(data) ? data : [])
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to fetch recent companies:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchRecent()
|
||||||
|
}, [dataSource])
|
||||||
|
|
||||||
|
const handleCompanyChange = (value: string) => {
|
||||||
|
if (!value) return
|
||||||
|
const [symbol, market] = value.split(':')
|
||||||
|
const company = companies.find(c => c.symbol === symbol && c.market === market)
|
||||||
|
|
||||||
|
// Push URL params to trigger page state update
|
||||||
|
// We encode company name as well to display it nicely before full details load
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
params.set('symbol', symbol)
|
||||||
|
params.set('market', market)
|
||||||
|
params.set('source', dataSource)
|
||||||
|
if (company) params.set('name', company.company_name)
|
||||||
|
params.set('t', Date.now().toString()) // Force update
|
||||||
|
|
||||||
|
router.push(`/?${params.toString()}`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="border-b bg-muted/40">
|
<header className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 sticky top-0 z-[60]">
|
||||||
<div className="flex h-14 items-center gap-4 px-6 lg:h-[60px] max-w-7xl mx-auto">
|
<div className="flex h-14 items-center gap-4 px-6 lg:h-[60px] w-full px-8"> {/* Adjusted constraint */}
|
||||||
<Link className="flex items-center gap-2 font-semibold" href="/">
|
<Link className="flex items-center gap-2 font-semibold min-w-[140px]" href="/">
|
||||||
<MonitorPlay className="h-6 w-6" />
|
<MonitorPlay className="h-6 w-6" />
|
||||||
<span className="">股票分析 AI</span>
|
<span className="">股票分析 AI</span>
|
||||||
</Link>
|
</Link>
|
||||||
<nav className="ml-auto flex items-center gap-4 sm:gap-6">
|
|
||||||
|
{/* 快速选择栏 */}
|
||||||
|
<div className="hidden md:flex items-center gap-3 ml-6 px-4 border-l h-8">
|
||||||
|
<span className="text-sm text-muted-foreground whitespace-nowrap font-medium">快速访问:</span>
|
||||||
|
|
||||||
|
<Select value={dataSource} onValueChange={handleDataSourceChange}>
|
||||||
|
<SelectTrigger className="w-[120px] h-8 text-xs font-medium">
|
||||||
|
<SelectValue placeholder="数据源" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="z-[70]">
|
||||||
|
<SelectItem value="Bloomberg">Bloomberg</SelectItem>
|
||||||
|
<SelectItem value="iFinD">iFinD</SelectItem>
|
||||||
|
<SelectItem value="Tushare">Tushare</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Select onValueChange={handleCompanyChange}>
|
||||||
|
<SelectTrigger className="w-[240px] h-8 text-xs font-mono">
|
||||||
|
<SelectValue placeholder="选择最近浏览的代码..." />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="z-[70]">
|
||||||
|
{companies.map((c) => (
|
||||||
|
<SelectItem key={`${c.symbol}:${c.market}`} value={`${c.symbol}:${c.market}`}>
|
||||||
|
<span className="flex items-center gap-2 w-full">
|
||||||
|
<span className="font-bold w-[60px] text-left">{c.symbol}</span>
|
||||||
|
<span className="truncate flex-1 text-left">{c.company_name}</span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
{companies.length === 0 && (
|
||||||
|
<div className="p-2 text-xs text-muted-foreground text-center">该数据源暂无历史记录</div>
|
||||||
|
)}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-[300px] ml-6">
|
||||||
|
<HeaderSearch defaultDataSource={dataSource} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Portal Target for Dynamic Content */}
|
||||||
|
<div id="header-portal-target" className="flex-1 flex items-center justify-end px-4 gap-4 min-w-0" />
|
||||||
|
|
||||||
|
<nav className="flex items-center gap-4 sm:gap-6 border-l pl-6">
|
||||||
<Link className="text-sm font-medium hover:underline underline-offset-4" href="/">
|
<Link className="text-sm font-medium hover:underline underline-offset-4" href="/">
|
||||||
主页
|
主页
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -1,67 +1,130 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { searchStock, startAnalysis, getConfig } from "@/lib/api"
|
import { searchStock, getConfig } from "@/lib/api"
|
||||||
|
import { AI_MODELS } from "@/lib/constants"
|
||||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Search, Loader2, Database, Bot } from "lucide-react"
|
import { Search, Loader2, Settings2, Database } from "lucide-react"
|
||||||
import { useRouter } from "next/navigation"
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select"
|
|
||||||
import { Label } from "@/components/ui/label"
|
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
|
import type { SearchResult } from "@/lib/types"
|
||||||
|
|
||||||
export function SearchStock() {
|
interface SearchStockProps {
|
||||||
|
onCompanySelect?: (company: SearchResult, dataSource: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const DATA_SOURCES = {
|
||||||
|
CN: [
|
||||||
|
{ value: "Tushare", label: "Tushare (CN)" },
|
||||||
|
{ value: "iFinD", label: "iFinD" },
|
||||||
|
{ value: "Bloomberg", label: "Bloomberg" }
|
||||||
|
],
|
||||||
|
GLOBAL: [
|
||||||
|
{ value: "iFinD", label: "iFinD" },
|
||||||
|
{ value: "Bloomberg", label: "Bloomberg" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function SearchResultItem({ result, onSelect }: { result: SearchResult, onSelect: (r: SearchResult, ds: string) => void }) {
|
||||||
|
// 默认数据源逻辑:CN -> Tushare, 其他 -> iFinD
|
||||||
|
const defaultSource = result.market === "CN" ? "Tushare" : "iFinD"
|
||||||
|
const [source, setSource] = useState(defaultSource)
|
||||||
|
|
||||||
|
// 根据市场获取可用数据源列表
|
||||||
|
const availableSources = result.market === "CN" ? DATA_SOURCES.CN : DATA_SOURCES.GLOBAL
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="hover:bg-accent/50 transition-colors h-full flex flex-col">
|
||||||
|
<CardContent className="p-4 flex flex-col gap-3 h-full">
|
||||||
|
{/* 顶部:公司信息 */}
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-start justify-between gap-2">
|
||||||
|
<div className="min-w-0">
|
||||||
|
<h3 className="font-bold text-base truncate" title={result.company_name}>
|
||||||
|
{result.company_name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-muted-foreground font-mono mt-0.5">
|
||||||
|
{result.symbol}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Badge variant="secondary" className="shrink-0 text-xs font-mono">
|
||||||
|
{result.market}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部:操作区 */}
|
||||||
|
<div className="flex items-center gap-2 pt-2 border-t mt-auto">
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<Select value={source} onValueChange={setSource}>
|
||||||
|
<SelectTrigger className="h-8 text-xs w-full">
|
||||||
|
<Database className="w-3 h-3 mr-2 shrink-0" />
|
||||||
|
<span className="truncate">{availableSources.find(s => s.value === source)?.label}</span>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent portal={false}>
|
||||||
|
{availableSources.map(ds => (
|
||||||
|
<SelectItem key={ds.value} value={ds.value} className="text-xs">
|
||||||
|
{ds.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={() => onSelect(result, source)}
|
||||||
|
size="sm"
|
||||||
|
className="h-8 px-3 shrink-0"
|
||||||
|
>
|
||||||
|
选择
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SearchStock({ onCompanySelect }: SearchStockProps = {}) {
|
||||||
const [query, setQuery] = useState("")
|
const [query, setQuery] = useState("")
|
||||||
const [results, setResults] = useState<{ market: string; symbol: string; company_name: string }[]>([])
|
const [results, setResults] = useState<SearchResult[]>([])
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [error, setError] = useState("")
|
const [error, setError] = useState("")
|
||||||
const [activeIndex, setActiveIndex] = useState<number | null>(null)
|
const [selectedModel, setSelectedModel] = useState<string>("")
|
||||||
|
|
||||||
// Global Configuration State
|
// 加载默认模型配置
|
||||||
const [selectedModel, setSelectedModel] = useState("gemini-2.0-flash")
|
|
||||||
const [dataSourcePrefs, setDataSourcePrefs] = useState<Record<string, string>>({
|
|
||||||
'CN': 'Tushare',
|
|
||||||
'HK': 'iFinD',
|
|
||||||
'US': 'Alpha Vantage',
|
|
||||||
'JP': 'iFinD',
|
|
||||||
'VN': 'iFinD'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Fetch initial config
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchConfig = async () => {
|
const loadConfig = async () => {
|
||||||
try {
|
try {
|
||||||
const config = await getConfig()
|
const config = await getConfig()
|
||||||
if (config.AI_MODEL) {
|
const modelConfig = Array.isArray(config)
|
||||||
setSelectedModel(config.AI_MODEL)
|
? config.find((c: any) => c.key === 'AI_MODEL')
|
||||||
}
|
: null
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to load config:", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchConfig()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const router = useRouter()
|
if (modelConfig && modelConfig.value) {
|
||||||
|
setSelectedModel(modelConfig.value)
|
||||||
|
} else {
|
||||||
|
// 如果后端没有配置,使用 fallback
|
||||||
|
setSelectedModel("gemini-2.5-flash")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to load default model config:", error)
|
||||||
|
// 加载失败时使用 fallback
|
||||||
|
setSelectedModel("gemini-2.5-flash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadConfig()
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleSearch = async () => {
|
const handleSearch = async () => {
|
||||||
if (!query.trim()) return
|
if (!query.trim()) return
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setError("")
|
setError("")
|
||||||
setResults([])
|
setResults([])
|
||||||
setActiveIndex(null)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await searchStock(query)
|
const data = await searchStock(query, selectedModel)
|
||||||
setResults(data)
|
setResults(data)
|
||||||
// Auto-select the first result if exists? Or keep null? User asked for "click to select". Keeping null is safer.
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(err.message || "搜索失败")
|
setError(err.message || "搜索失败")
|
||||||
} finally {
|
} finally {
|
||||||
@ -69,185 +132,100 @@ export function SearchStock() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAnalyze = async (result: { market: string; symbol: string; company_name: string }) => {
|
const handleSelectCompany = (result: SearchResult, dataSource: string) => {
|
||||||
setLoading(true)
|
if (onCompanySelect) {
|
||||||
try {
|
// 这里传递数据源,而不是模型
|
||||||
// Use global model selection
|
onCompanySelect(result, dataSource)
|
||||||
const dataSource = dataSourcePrefs[result.market]
|
|
||||||
const report = await startAnalysis(result.market, result.symbol, result.company_name, selectedModel, dataSource)
|
|
||||||
router.push(`/analysis/${report.id}`)
|
|
||||||
} catch (err: any) {
|
|
||||||
setError(err.message || "启动分析失败")
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic Data Source Options (Mocking availability)
|
// 使用共享常量
|
||||||
const dataSourceOptions: Record<string, string[]> = {
|
const availableModels = AI_MODELS
|
||||||
'CN': ['Tushare'],
|
|
||||||
'HK': ['iFinD'],
|
|
||||||
'US': ['Alpha Vantage', 'iFinD'],
|
|
||||||
'JP': ['iFinD'],
|
|
||||||
'VN': ['iFinD']
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 w-full max-w-6xl">
|
<Card className="w-full border-none shadow-none">
|
||||||
{/* Left Column: Search & Results */}
|
<CardHeader className="px-0 pt-0">
|
||||||
<div className="lg:col-span-2 space-y-6">
|
<CardTitle className="flex items-center gap-2">
|
||||||
<Card className="h-full flex flex-col">
|
<Search className="h-5 w-5" />
|
||||||
<CardHeader>
|
股票搜索
|
||||||
<CardTitle>开始新的分析</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>输入公司名称或股票代码开始搜索</CardDescription>
|
<CardDescription>
|
||||||
|
输入公司名称、股票代码或关键词进行搜索
|
||||||
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4 flex-grow">
|
<CardContent className="space-y-6 px-0">
|
||||||
<div className="flex gap-2">
|
{/* 搜索框和模型选择 */}
|
||||||
|
<div className="flex gap-4 items-start">
|
||||||
|
<div className="flex-1 flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="输入公司名称(例如:腾讯)或代码(例如:700)"
|
placeholder="例如: 腾讯, AAPL, 00700.HK"
|
||||||
value={query}
|
value={query}
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
|
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
|
||||||
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
<Button onClick={handleSearch} disabled={loading} size="default" className="px-4">
|
|
||||||
{loading ? <Loader2 className="animate-spin" /> : <Search className="h-4 w-4" />}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && <div className="text-red-500 text-sm">{error}</div>}
|
|
||||||
|
|
||||||
{results.length > 0 && (
|
|
||||||
<div className="mt-6 space-y-3">
|
|
||||||
<div className="text-sm font-medium text-muted-foreground flex items-center justify-between">
|
|
||||||
<span>找到 {results.length} 个结果</span>
|
|
||||||
<span className="text-xs">点击下方卡片运行分析</span>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
||||||
{results.map((result, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className={`group relative flex flex-col justify-between p-4 rounded-lg border transition-all cursor-pointer shadow-sm hover:shadow active:scale-95 duration-200 ${activeIndex === index ? 'border-primary bg-primary/5 ring-1 ring-primary' : 'bg-card hover:bg-accent hover:border-primary/50'}`}
|
|
||||||
onClick={() => setActiveIndex(index)}
|
|
||||||
>
|
|
||||||
<div className="space-y-2 mb-4">
|
|
||||||
<div className="font-semibold text-base line-clamp-2 leading-tight" title={result.company_name}>
|
|
||||||
{result.company_name}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
||||||
<Badge variant="secondary" className="px-1.5 py-0 text-[10px] h-5">{result.market}</Badge>
|
|
||||||
<span className="font-mono">{result.symbol}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={(e) => {
|
onClick={handleSearch}
|
||||||
e.stopPropagation();
|
disabled={loading || !query.trim()}
|
||||||
handleAnalyze(result);
|
className="min-w-[100px]">
|
||||||
}}
|
{loading ? (
|
||||||
disabled={loading}
|
|
||||||
size="sm"
|
|
||||||
variant={activeIndex === index ? "default" : "secondary"}
|
|
||||||
className="w-full mt-auto"
|
|
||||||
>
|
|
||||||
{loading ? <Loader2 className="animate-spin h-3 w-3 mr-2" /> : null}
|
|
||||||
运行分析
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Right Column: Configuration */}
|
|
||||||
<div className="lg:col-span-1 space-y-6">
|
|
||||||
<Card className="h-full border-dashed shadow-sm bg-muted/30 flex flex-col">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="flex items-center gap-2 text-base">
|
|
||||||
<Bot className="h-5 w-5 text-primary" />
|
|
||||||
分析配置
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-6">
|
|
||||||
{/* Section 1: AI Model */}
|
|
||||||
<div className="space-y-3">
|
|
||||||
<Label className="text-sm font-medium">选择 AI 模型</Label>
|
|
||||||
<Select
|
|
||||||
value={selectedModel}
|
|
||||||
onValueChange={setSelectedModel}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-full bg-background">
|
|
||||||
<SelectValue placeholder="Select model" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="gemini-2.0-flash">Gemini 2.0 Flash</SelectItem>
|
|
||||||
<SelectItem value="gemini-2.5-flash">Gemini 2.5 Flash</SelectItem>
|
|
||||||
<SelectItem value="gemini-3-flash-preview">Gemini 3 Flash Preview</SelectItem>
|
|
||||||
<SelectItem value="gemini-3-pro-preview">Gemini 3 Pro Preview</SelectItem>
|
|
||||||
|
|
||||||
{/* If the current selected model is custom and not in the list above, show it */}
|
|
||||||
{selectedModel &&
|
|
||||||
!["gemini-2.0-flash", "gemini-2.5-flash", "gemini-3-flash-preview", "gemini-3-pro-preview"].includes(selectedModel) && (
|
|
||||||
<SelectItem value={selectedModel}>{selectedModel} (Custom)</SelectItem>
|
|
||||||
)}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
选择用于分析财报和生成报告的大语言模型。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Section 2: Data Sources - Only show when results are available and for relevant markets */}
|
|
||||||
{results.length > 0 && (
|
|
||||||
<>
|
<>
|
||||||
<div className="h-[1px] bg-border w-full my-4" />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
<div className="space-y-3">
|
搜索中
|
||||||
<div className="flex items-center gap-2">
|
</>
|
||||||
<Database className="h-4 w-4 text-primary" />
|
) : (
|
||||||
<Label className="text-sm font-medium">数据源偏好</Label>
|
<>
|
||||||
</div>
|
<Search className="mr-2 h-4 w-4" />
|
||||||
|
搜索
|
||||||
<div className="space-y-4">
|
|
||||||
{(activeIndex !== null && results[activeIndex] ? [results[activeIndex].market] : Array.from(new Set(results.map(r => r.market)))).map((market) => (
|
|
||||||
<div key={market} className="space-y-2 animate-in fade-in slide-in-from-right-4 duration-300">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Badge variant="outline" className="h-5 px-1.5 text-[10px] uppercase">{market}</Badge>
|
|
||||||
<span className="text-xs text-muted-foreground">选择数据源:</span>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
{(dataSourceOptions[market] || ['Default']).map((opt) => {
|
|
||||||
const isSelected = dataSourcePrefs[market] === opt;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={opt}
|
|
||||||
onClick={() => setDataSourcePrefs(prev => ({ ...prev, [market]: opt }))}
|
|
||||||
className={`
|
|
||||||
cursor-pointer relative flex flex-col items-center justify-center p-2 rounded-md border text-xs font-medium transition-all
|
|
||||||
${isSelected
|
|
||||||
? 'border-primary bg-primary/10 text-primary ring-1 ring-primary/20'
|
|
||||||
: 'bg-background hover:bg-accent hover:border-primary/30 text-muted-foreground'}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{opt}
|
|
||||||
{isSelected && <div className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-primary" />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground mt-2">
|
|
||||||
根据当前搜索结果的市场,选择首选的数据提供商。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 模型选择 - 仍然保留在搜索栏旁边,如果用户确实想在这里覆盖全局设置 */}
|
||||||
|
<div className="w-[200px]">
|
||||||
|
<Select value={selectedModel} onValueChange={setSelectedModel}>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<Settings2 className="w-4 h-4 mr-2 text-muted-foreground" />
|
||||||
|
<SelectValue placeholder="选择AI模型" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent portal={false}>
|
||||||
|
{availableModels.map((model) => (
|
||||||
|
<SelectItem key={model.value} value={model.value}>
|
||||||
|
{model.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-xs text-muted-foreground mt-1 ml-1">
|
||||||
|
本次分析使用的模型
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="p-3 text-sm text-red-600 bg-red-50 rounded-md">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{results.length > 0 && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
找到 {results.length} 个结果:
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||||
|
{results.map((result) => (
|
||||||
|
<SearchResultItem
|
||||||
|
key={`${result.market}-${result.symbol}`}
|
||||||
|
result={result}
|
||||||
|
onSelect={handleSelectCompany}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
28
frontend/src/components/ui/progress.tsx
Normal file
28
frontend/src/components/ui/progress.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Progress = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||||
|
>(({ className, value, ...props }, ref) => (
|
||||||
|
<ProgressPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ProgressPrimitive.Indicator
|
||||||
|
className="h-full w-full flex-1 bg-primary transition-all"
|
||||||
|
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||||
|
/>
|
||||||
|
</ProgressPrimitive.Root>
|
||||||
|
))
|
||||||
|
Progress.displayName = ProgressPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Progress }
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user