modify scripts
This commit is contained in:
@ -8,6 +8,9 @@ db_config = {
|
|||||||
'password': 'mysqlpw',
|
'password': 'mysqlpw',
|
||||||
'database': 'stockdb'
|
'database': 'stockdb'
|
||||||
}
|
}
|
||||||
|
# 读取环境变量,来修改 db_config 中host的值
|
||||||
|
if 'DB_HOST' in os.environ:
|
||||||
|
db_config['host'] = os.environ['DB_HOST']
|
||||||
|
|
||||||
home_dir = os.path.expanduser("~")
|
home_dir = os.path.expanduser("~")
|
||||||
global_host_data_dir = f'{home_dir}/hostdir/stock_data'
|
global_host_data_dir = f'{home_dir}/hostdir/stock_data'
|
||||||
|
|||||||
195
src/db_utils/reports_mysql.py
Normal file
195
src/db_utils/reports_mysql.py
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
import pymysql
|
||||||
|
from pymysql.cursors import DictCursor
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class DatabaseConnectionError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class StockReportMysql:
|
||||||
|
# 定义类属性(静态变量)
|
||||||
|
TBL_STOCK = 'reports_stock'
|
||||||
|
TBL_NEW_STOCK = 'reports_newstrock' # 注意原拼写可能存在笔误(strock应为stock)
|
||||||
|
TBL_STRATEGY = 'reports_strategy'
|
||||||
|
TBL_MACRESEARCH = 'reports_macresearch'
|
||||||
|
TBL_INDUSTRY = 'reports_industry'
|
||||||
|
|
||||||
|
def __init__(self, db_host, db_user, db_password, db_name, port=3306):
|
||||||
|
"""
|
||||||
|
初始化MySQL连接
|
||||||
|
:param db_host: 数据库主机地址
|
||||||
|
:param db_user: 数据库用户名
|
||||||
|
:param db_password: 数据库密码
|
||||||
|
:param db_name: 数据库名称
|
||||||
|
:param port: 数据库端口,默认3306
|
||||||
|
"""
|
||||||
|
self.db_host = db_host
|
||||||
|
self.db_user = db_user
|
||||||
|
self.db_password = db_password
|
||||||
|
self.db_name = db_name
|
||||||
|
self.port = port
|
||||||
|
self.conn = None
|
||||||
|
self.cursor = None
|
||||||
|
try:
|
||||||
|
self.conn = pymysql.connect(
|
||||||
|
host=self.db_host,
|
||||||
|
user=self.db_user,
|
||||||
|
password=self.db_password,
|
||||||
|
database=self.db_name,
|
||||||
|
port=self.port,
|
||||||
|
charset='utf8mb4' # 支持中文
|
||||||
|
)
|
||||||
|
#self.cursor = self.conn.cursor(dictionary=False) # 使用非字典游标,保持与原代码兼容
|
||||||
|
self.cursor = self.conn.cursor() # 使用默认游标
|
||||||
|
except pymysql.MySQLError as e:
|
||||||
|
logging.error(f"数据库连接失败: {e}")
|
||||||
|
raise DatabaseConnectionError("数据库连接失败")
|
||||||
|
|
||||||
|
def __get_table_columns_and_defaults(self, tbl_name):
|
||||||
|
"""获取表的列信息及默认值(适配MySQL)"""
|
||||||
|
try:
|
||||||
|
# 查询information_schema获取列信息
|
||||||
|
self.cursor.execute("""
|
||||||
|
SELECT COLUMN_NAME, COLUMN_DEFAULT
|
||||||
|
FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_NAME = %s AND TABLE_SCHEMA = %s
|
||||||
|
""", (tbl_name, self.db_name))
|
||||||
|
columns = self.cursor.fetchall()
|
||||||
|
column_info = {}
|
||||||
|
for col in columns:
|
||||||
|
col_name = col[0]
|
||||||
|
default_value = col[1]
|
||||||
|
# MySQL默认值可能包含函数(如CURRENT_TIMESTAMP),需要特殊处理
|
||||||
|
column_info[col_name] = default_value
|
||||||
|
return column_info
|
||||||
|
except pymysql.MySQLError as e:
|
||||||
|
logging.error(f"获取表结构失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __check_and_process_data(self, data, tbl_name):
|
||||||
|
"""数据校验和处理(逻辑与原代码保持一致)"""
|
||||||
|
column_info = self.__get_table_columns_and_defaults(tbl_name=tbl_name)
|
||||||
|
if column_info is None:
|
||||||
|
return None
|
||||||
|
processed_data = {}
|
||||||
|
for col, default in column_info.items():
|
||||||
|
if col == 'id': # 自增主键,不需要用户提供
|
||||||
|
continue
|
||||||
|
if col == 'created_at' or col == 'updated_at': # 日期字段由数据库或代码控制
|
||||||
|
continue
|
||||||
|
if col in ['author', 'authorID']:
|
||||||
|
# 将列表转换为逗号分隔字符串
|
||||||
|
values = data.get(col, [])
|
||||||
|
processed_data[col] = ','.join(values) if values else None
|
||||||
|
# 确保不超过255字符
|
||||||
|
if processed_data[col] and len(processed_data[col]) > 250:
|
||||||
|
processed_data[col] = processed_data[col][:250]
|
||||||
|
elif col in data:
|
||||||
|
processed_data[col] = data[col]
|
||||||
|
else:
|
||||||
|
# 使用默认值
|
||||||
|
pass
|
||||||
|
return processed_data
|
||||||
|
|
||||||
|
def insert_or_update_common(self, data, tbl_name, uniq_key='infoCode'):
|
||||||
|
"""插入或更新数据(适配MySQL的ON DUPLICATE KEY UPDATE)"""
|
||||||
|
try:
|
||||||
|
processed_data = self.__check_and_process_data(data, tbl_name)
|
||||||
|
if processed_data is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
columns = ', '.join(processed_data.keys())
|
||||||
|
values = list(processed_data.values())
|
||||||
|
placeholders = ', '.join(['%s' for _ in values]) # MySQL使用%s作为占位符
|
||||||
|
|
||||||
|
# 构造更新子句(排除唯一键字段)
|
||||||
|
update_clause = ', '.join(
|
||||||
|
[f"{col}=VALUES({col})" for col in processed_data.keys() if col != uniq_key]
|
||||||
|
) + ', updated_at=NOW()' # MySQL使用NOW()获取当前时间
|
||||||
|
|
||||||
|
sql = f'''
|
||||||
|
INSERT INTO {tbl_name} ({columns}, created_at, updated_at)
|
||||||
|
VALUES ({placeholders}, NOW(), NOW())
|
||||||
|
ON DUPLICATE KEY UPDATE {update_clause}
|
||||||
|
'''
|
||||||
|
self.cursor.execute(sql, values)
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
# 获取插入或更新后的记录ID
|
||||||
|
self.cursor.execute(f"SELECT id FROM {tbl_name} WHERE {uniq_key} = %s", (data[uniq_key],))
|
||||||
|
result = self.cursor.fetchone()
|
||||||
|
return result[0] if result else None
|
||||||
|
except pymysql.MySQLError as e:
|
||||||
|
logging.error(f"插入或更新数据失败: {e}")
|
||||||
|
self.conn.rollback() # 出错时回滚
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_pages(self, data, tbl_name, uniq_key='infoCode'):
|
||||||
|
"""更新附件页数(使用参数化查询防止SQL注入)"""
|
||||||
|
try:
|
||||||
|
# 注意:原代码直接拼接SQL有注入风险,此处改为参数化查询
|
||||||
|
sql = f'''
|
||||||
|
UPDATE {tbl_name}
|
||||||
|
SET attachPages = %s
|
||||||
|
WHERE id = %s
|
||||||
|
'''
|
||||||
|
self.cursor.execute(sql, (data['attachPages'], data['id']))
|
||||||
|
self.conn.commit()
|
||||||
|
return data['id']
|
||||||
|
except pymysql.MySQLError as e:
|
||||||
|
logging.error(f"更新页数失败: {e}")
|
||||||
|
self.conn.rollback()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def query_reports_comm(self, tbl_name, querystr='', limit=None):
|
||||||
|
"""查询报告列表(适配MySQL语法)"""
|
||||||
|
try:
|
||||||
|
# 验证表名合法性
|
||||||
|
valid_tables = [
|
||||||
|
self.TBL_STOCK, self.TBL_NEW_STOCK,
|
||||||
|
self.TBL_INDUSTRY, self.TBL_MACRESEARCH,
|
||||||
|
self.TBL_STRATEGY
|
||||||
|
]
|
||||||
|
if tbl_name not in valid_tables:
|
||||||
|
logging.warning(f'无效的表名: {tbl_name}')
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 构造查询SQL
|
||||||
|
sql = f"""
|
||||||
|
SELECT id, infoCode, title, orgSName, industryName, stockName, publishDate
|
||||||
|
FROM {tbl_name}
|
||||||
|
WHERE 1=1 {querystr}
|
||||||
|
"""
|
||||||
|
# 添加限制条件
|
||||||
|
if limit:
|
||||||
|
sql += f' LIMIT {limit}'
|
||||||
|
|
||||||
|
self.cursor.execute(sql)
|
||||||
|
results = self.cursor.fetchall()
|
||||||
|
|
||||||
|
# 获取列名
|
||||||
|
column_names = [description[0] for description in self.cursor.description]
|
||||||
|
|
||||||
|
# 转换为字典列表
|
||||||
|
result_dict_list = []
|
||||||
|
for row in results:
|
||||||
|
row_dict = {column_names[i]: value for i, value in enumerate(row)}
|
||||||
|
result_dict_list.append(row_dict)
|
||||||
|
|
||||||
|
return result_dict_list
|
||||||
|
except pymysql.MySQLError as e:
|
||||||
|
logging.error(f"查询失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""析构函数,关闭数据库连接(适配pymysql)"""
|
||||||
|
try:
|
||||||
|
# pymysql中通过ping()判断连接是否有效,若连接已关闭会抛出异常
|
||||||
|
if self.conn:
|
||||||
|
self.conn.ping() # 尝试检测连接是否存活
|
||||||
|
self.cursor.close()
|
||||||
|
self.conn.close()
|
||||||
|
except (pymysql.MySQLError, AttributeError):
|
||||||
|
# 捕获连接已关闭、游标不存在等异常,避免析构时报错
|
||||||
|
pass
|
||||||
@ -11,8 +11,9 @@ from datetime import datetime, timedelta
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
import src.crawler.em.reports as em
|
import src.crawler.em.reports as em
|
||||||
import src.utils.utils as utils
|
import src.utils.utils as utils
|
||||||
from src.config.config import global_host_data_dir, global_share_db_dir
|
from src.config.config import global_host_data_dir, global_share_db_dir, db_config
|
||||||
from src.db_utils.reports import StockReportDB, DatabaseConnectionError
|
from src.db_utils.reports import StockReportDB, DatabaseConnectionError
|
||||||
|
from src.db_utils.reports_mysql import StockReportMysql
|
||||||
from src.logger.logger import setup_logging
|
from src.logger.logger import setup_logging
|
||||||
import PyPDF2
|
import PyPDF2
|
||||||
|
|
||||||
@ -83,6 +84,17 @@ def fetch_reports_list_general(fetch_func, table_name, s_date, e_date, data_dir_
|
|||||||
# 统一以 infoCode 为 UNIQE 键,所以这里对它进行赋值
|
# 统一以 infoCode 为 UNIQE 键,所以这里对它进行赋值
|
||||||
if row.get('infoCode') is None and row.get('encodeUrl'):
|
if row.get('infoCode') is None and row.get('encodeUrl'):
|
||||||
row['infoCode'] = row['encodeUrl']
|
row['infoCode'] = row['encodeUrl']
|
||||||
|
row['count_all'] = row.get('count', 0) # 兼容旧数据
|
||||||
|
row['curr_column'] = row.get('column', 'None') # 兼容旧数据
|
||||||
|
if 'stockName' not in row or row['stockName'] is None or row['stockName']=='':
|
||||||
|
row['stockName'] = ''
|
||||||
|
if 'stockCode' not in row or row['stockCode'] is None or row['stockCode']=='':
|
||||||
|
row['stockCode'] = ''
|
||||||
|
if 'newPeIssueA' in row and row['newPeIssueA'] is None:
|
||||||
|
try:
|
||||||
|
row['newPeIssueA'] = float(row.get('newPeIssueA', 0))
|
||||||
|
except ValueError:
|
||||||
|
row['newPeIssueA'] = 0.0
|
||||||
row_id = db_tools.insert_or_update_common(row, table_name)
|
row_id = db_tools.insert_or_update_common(row, table_name)
|
||||||
if row_id:
|
if row_id:
|
||||||
logging.debug(f'insert one row. rowid:{row_id}, ')
|
logging.debug(f'insert one row. rowid:{row_id}, ')
|
||||||
@ -325,7 +337,9 @@ def main(cmd, mode, args_debug, args_force, begin, end):
|
|||||||
# 初始化DB
|
# 初始化DB
|
||||||
global db_tools
|
global db_tools
|
||||||
try:
|
try:
|
||||||
db_tools = StockReportDB(db_path)
|
#db_tools = StockReportDB(db_path)
|
||||||
|
db_tools = StockReportMysql(db_host=db_config['host'], db_user=db_config['user'], db_password=db_config['password'], db_name = db_config['database'], port=3306) # 使用配置文件中的数据库配置
|
||||||
|
|
||||||
# 进行数据库操作
|
# 进行数据库操作
|
||||||
except DatabaseConnectionError as e:
|
except DatabaseConnectionError as e:
|
||||||
logging.error(f"数据库连接失败: {e}")
|
logging.error(f"数据库连接失败: {e}")
|
||||||
|
|||||||
@ -0,0 +1,253 @@
|
|||||||
|
"""Auto update from stockdb
|
||||||
|
|
||||||
|
Revision ID: 33c9c4443fa8
|
||||||
|
Revises: 9680e7b8e29b
|
||||||
|
Create Date: 2025-08-10 18:03:56.817265
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '33c9c4443fa8'
|
||||||
|
down_revision: Union[str, Sequence[str], None] = '9680e7b8e29b'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('reports_industry',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='自增主键'),
|
||||||
|
sa.Column('infoCode', sa.String(length=255), nullable=False, comment='报告唯一标识'),
|
||||||
|
sa.Column('title', sa.String(length=512), nullable=True, comment='报告标题'),
|
||||||
|
sa.Column('stockName', sa.String(length=100), nullable=True, comment='股票名称'),
|
||||||
|
sa.Column('stockCode', sa.String(length=50), nullable=True, comment='股票代码'),
|
||||||
|
sa.Column('orgCode', sa.String(length=50), nullable=True, comment='机构代码'),
|
||||||
|
sa.Column('orgName', sa.String(length=255), nullable=True, comment='机构全称'),
|
||||||
|
sa.Column('orgSName', sa.String(length=100), nullable=True, comment='机构简称'),
|
||||||
|
sa.Column('publishDate', sa.String(length=50), nullable=True, comment='发布日期'),
|
||||||
|
sa.Column('column', sa.String(length=255), nullable=True, comment='栏目'),
|
||||||
|
sa.Column('predictNextTwoYearEps', sa.String(length=50), nullable=True, comment='未来两年EPS预测'),
|
||||||
|
sa.Column('predictNextTwoYearPe', sa.String(length=50), nullable=True, comment='未来两年PE预测'),
|
||||||
|
sa.Column('predictNextYearEps', sa.String(length=50), nullable=True, comment='明年EPS预测'),
|
||||||
|
sa.Column('predictNextYearPe', sa.String(length=50), nullable=True, comment='明年PE预测'),
|
||||||
|
sa.Column('predictThisYearEps', sa.String(length=50), nullable=True, comment='今年EPS预测'),
|
||||||
|
sa.Column('predictThisYearPe', sa.String(length=50), nullable=True, comment='今年PE预测'),
|
||||||
|
sa.Column('predictLastYearEps', sa.String(length=50), nullable=True, comment='去年EPS预测'),
|
||||||
|
sa.Column('predictLastYearPe', sa.String(length=50), nullable=True, comment='去年PE预测'),
|
||||||
|
sa.Column('actualLastTwoYearEps', sa.String(length=50), nullable=True, comment='前两年实际EPS'),
|
||||||
|
sa.Column('actualLastYearEps', sa.String(length=50), nullable=True, comment='去年实际EPS'),
|
||||||
|
sa.Column('industryCode', sa.String(length=50), nullable=True, comment='行业代码'),
|
||||||
|
sa.Column('industryName', sa.String(length=100), nullable=True, comment='行业名称'),
|
||||||
|
sa.Column('emIndustryCode', sa.String(length=50), nullable=True, comment='东方财富行业代码'),
|
||||||
|
sa.Column('indvInduCode', sa.String(length=50), nullable=True, comment='个性化行业代码'),
|
||||||
|
sa.Column('indvInduName', sa.String(length=100), nullable=True, comment='个性化行业名称'),
|
||||||
|
sa.Column('emRatingCode', sa.String(length=50), nullable=True, comment='东方财富评级代码'),
|
||||||
|
sa.Column('emRatingValue', sa.String(length=50), nullable=True, comment='东方财富评级值'),
|
||||||
|
sa.Column('emRatingName', sa.String(length=100), nullable=True, comment='东方财富评级名称'),
|
||||||
|
sa.Column('lastEmRatingCode', sa.String(length=50), nullable=True, comment='上次东方财富评级代码'),
|
||||||
|
sa.Column('lastEmRatingValue', sa.String(length=50), nullable=True, comment='上次东方财富评级值'),
|
||||||
|
sa.Column('lastEmRatingName', sa.String(length=100), nullable=True, comment='上次东方财富评级名称'),
|
||||||
|
sa.Column('ratingChange', sa.String(length=50), nullable=True, comment='评级变动'),
|
||||||
|
sa.Column('reportType', sa.Integer(), nullable=True, comment='报告类型'),
|
||||||
|
sa.Column('author', sa.String(length=255), nullable=True, comment='作者(逗号分隔)'),
|
||||||
|
sa.Column('indvIsNew', sa.String(length=20), nullable=True, comment='是否为新研报'),
|
||||||
|
sa.Column('researcher', sa.String(length=255), nullable=True, comment='研究员'),
|
||||||
|
sa.Column('newListingDate', sa.String(length=50), nullable=True, comment='新上市日期'),
|
||||||
|
sa.Column('newPurchaseDate', sa.String(length=50), nullable=True, comment='新买入日期'),
|
||||||
|
sa.Column('newIssuePrice', sa.String(length=50), nullable=True, comment='新发行价格'),
|
||||||
|
sa.Column('newPeIssueA', sa.String(length=50), nullable=True, comment='新发行市盈率A'),
|
||||||
|
sa.Column('indvAimPriceT', sa.String(length=50), nullable=True, comment='目标价上限'),
|
||||||
|
sa.Column('indvAimPriceL', sa.String(length=50), nullable=True, comment='目标价下限'),
|
||||||
|
sa.Column('attachType', sa.String(length=50), nullable=True, comment='附件类型'),
|
||||||
|
sa.Column('attachSize', sa.Integer(), nullable=True, comment='附件大小'),
|
||||||
|
sa.Column('attachPages', sa.Integer(), nullable=True, comment='附件页数'),
|
||||||
|
sa.Column('encodeUrl', sa.String(length=512), nullable=True, comment='加密URL'),
|
||||||
|
sa.Column('sRatingName', sa.String(length=100), nullable=True, comment='评级名称'),
|
||||||
|
sa.Column('sRatingCode', sa.String(length=50), nullable=True, comment='评级代码'),
|
||||||
|
sa.Column('market', sa.String(length=50), nullable=True, comment='市场'),
|
||||||
|
sa.Column('authorID', sa.String(length=255), nullable=True, comment='作者ID(逗号分隔)'),
|
||||||
|
sa.Column('count', sa.Integer(), nullable=True, comment='计数'),
|
||||||
|
sa.Column('orgType', sa.String(length=50), nullable=True, comment='机构类型'),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=False, comment='创建时间'),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=False, comment='更新时间'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('infoCode')
|
||||||
|
)
|
||||||
|
op.create_table('reports_macresearch',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='自增主键'),
|
||||||
|
sa.Column('infoCode', sa.String(length=255), nullable=False, comment='报告唯一标识'),
|
||||||
|
sa.Column('json_id', sa.String(length=50), nullable=True, comment='JSON ID'),
|
||||||
|
sa.Column('title', sa.String(length=512), nullable=True, comment='报告标题'),
|
||||||
|
sa.Column('author', sa.String(length=255), nullable=True, comment='作者(逗号分隔)'),
|
||||||
|
sa.Column('orgName', sa.String(length=255), nullable=True, comment='机构全称'),
|
||||||
|
sa.Column('orgCode', sa.String(length=50), nullable=True, comment='机构代码'),
|
||||||
|
sa.Column('orgSName', sa.String(length=100), nullable=True, comment='机构简称'),
|
||||||
|
sa.Column('publishDate', sa.String(length=50), nullable=True, comment='发布日期'),
|
||||||
|
sa.Column('encodeUrl', sa.String(length=512), nullable=True, comment='加密URL'),
|
||||||
|
sa.Column('researcher', sa.String(length=255), nullable=True, comment='研究员'),
|
||||||
|
sa.Column('market', sa.String(length=50), nullable=True, comment='市场'),
|
||||||
|
sa.Column('industryCode', sa.String(length=50), nullable=True, comment='行业代码'),
|
||||||
|
sa.Column('industryName', sa.String(length=100), nullable=True, comment='行业名称'),
|
||||||
|
sa.Column('authorID', sa.String(length=255), nullable=True, comment='作者ID(逗号分隔)'),
|
||||||
|
sa.Column('count', sa.Integer(), nullable=True, comment='计数'),
|
||||||
|
sa.Column('orgType', sa.String(length=50), nullable=True, comment='机构类型'),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=False, comment='创建时间'),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=False, comment='更新时间'),
|
||||||
|
sa.Column('stockCode', sa.String(length=50), nullable=False, comment='股票代码(默认空字符串)'),
|
||||||
|
sa.Column('stockName', sa.String(length=100), nullable=False, comment='股票名称(默认空字符串)'),
|
||||||
|
sa.Column('attachPages', sa.Integer(), nullable=True, comment='附件页数'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('infoCode')
|
||||||
|
)
|
||||||
|
op.create_table('reports_newstrock',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='自增主键'),
|
||||||
|
sa.Column('infoCode', sa.String(length=255), nullable=False, comment='报告唯一标识'),
|
||||||
|
sa.Column('title', sa.String(length=512), nullable=True, comment='报告标题'),
|
||||||
|
sa.Column('stockName', sa.String(length=100), nullable=True, comment='股票名称'),
|
||||||
|
sa.Column('stockCode', sa.String(length=50), nullable=True, comment='股票代码'),
|
||||||
|
sa.Column('orgCode', sa.String(length=50), nullable=True, comment='机构代码'),
|
||||||
|
sa.Column('orgName', sa.String(length=255), nullable=True, comment='机构全称'),
|
||||||
|
sa.Column('orgSName', sa.String(length=100), nullable=True, comment='机构简称'),
|
||||||
|
sa.Column('publishDate', sa.String(length=50), nullable=True, comment='发布日期'),
|
||||||
|
sa.Column('column', sa.String(length=255), nullable=True, comment='栏目'),
|
||||||
|
sa.Column('actualLastTwoYearEps', sa.String(length=50), nullable=True, comment='前两年实际EPS'),
|
||||||
|
sa.Column('actualLastYearEps', sa.String(length=50), nullable=True, comment='去年实际EPS'),
|
||||||
|
sa.Column('industryCode', sa.String(length=50), nullable=True, comment='行业代码'),
|
||||||
|
sa.Column('industryName', sa.String(length=100), nullable=True, comment='行业名称'),
|
||||||
|
sa.Column('emIndustryCode', sa.String(length=50), nullable=True, comment='东方财富行业代码'),
|
||||||
|
sa.Column('indvInduCode', sa.String(length=50), nullable=True, comment='个性化行业代码'),
|
||||||
|
sa.Column('indvInduName', sa.String(length=100), nullable=True, comment='个性化行业名称'),
|
||||||
|
sa.Column('emRatingCode', sa.String(length=50), nullable=True, comment='东方财富评级代码'),
|
||||||
|
sa.Column('emRatingValue', sa.String(length=50), nullable=True, comment='东方财富评级值'),
|
||||||
|
sa.Column('emRatingName', sa.String(length=100), nullable=True, comment='东方财富评级名称'),
|
||||||
|
sa.Column('lastEmRatingCode', sa.String(length=50), nullable=True, comment='上次东方财富评级代码'),
|
||||||
|
sa.Column('lastEmRatingValue', sa.String(length=50), nullable=True, comment='上次东方财富评级值'),
|
||||||
|
sa.Column('lastEmRatingName', sa.String(length=100), nullable=True, comment='上次东方财富评级名称'),
|
||||||
|
sa.Column('ratingChange', sa.String(length=50), nullable=True, comment='评级变动'),
|
||||||
|
sa.Column('reportType', sa.Integer(), nullable=True, comment='报告类型'),
|
||||||
|
sa.Column('author', sa.String(length=255), nullable=True, comment='作者(逗号分隔)'),
|
||||||
|
sa.Column('indvIsNew', sa.String(length=20), nullable=True, comment='是否为新研报'),
|
||||||
|
sa.Column('researcher', sa.String(length=255), nullable=True, comment='研究员'),
|
||||||
|
sa.Column('newListingDate', sa.String(length=50), nullable=True, comment='新上市日期'),
|
||||||
|
sa.Column('newPurchaseDate', sa.String(length=50), nullable=True, comment='新买入日期'),
|
||||||
|
sa.Column('newIssuePrice', sa.Float(), nullable=True, comment='新发行价格'),
|
||||||
|
sa.Column('newPeIssueA', sa.Float(), nullable=True, comment='新发行市盈率A'),
|
||||||
|
sa.Column('indvAimPriceT', sa.String(length=50), nullable=True, comment='目标价上限'),
|
||||||
|
sa.Column('indvAimPriceL', sa.String(length=50), nullable=True, comment='目标价下限'),
|
||||||
|
sa.Column('attachType', sa.String(length=50), nullable=True, comment='附件类型'),
|
||||||
|
sa.Column('attachSize', sa.Integer(), nullable=True, comment='附件大小'),
|
||||||
|
sa.Column('attachPages', sa.Integer(), nullable=True, comment='附件页数'),
|
||||||
|
sa.Column('encodeUrl', sa.String(length=512), nullable=True, comment='加密URL'),
|
||||||
|
sa.Column('sRatingName', sa.String(length=100), nullable=True, comment='评级名称'),
|
||||||
|
sa.Column('sRatingCode', sa.String(length=50), nullable=True, comment='评级代码'),
|
||||||
|
sa.Column('market', sa.String(length=50), nullable=True, comment='市场'),
|
||||||
|
sa.Column('newStockSort', sa.String(length=50), nullable=True, comment='新股分类'),
|
||||||
|
sa.Column('authorID', sa.String(length=255), nullable=True, comment='作者ID(逗号分隔)'),
|
||||||
|
sa.Column('count', sa.Integer(), nullable=True, comment='计数'),
|
||||||
|
sa.Column('orgType', sa.String(length=50), nullable=True, comment='机构类型'),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=False, comment='创建时间'),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=False, comment='更新时间'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('infoCode')
|
||||||
|
)
|
||||||
|
op.create_table('reports_stock',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='自增主键'),
|
||||||
|
sa.Column('infoCode', sa.String(length=255), nullable=False, comment='报告唯一标识'),
|
||||||
|
sa.Column('title', sa.String(length=512), nullable=True, comment='报告标题'),
|
||||||
|
sa.Column('stockName', sa.String(length=100), nullable=True, comment='股票名称'),
|
||||||
|
sa.Column('stockCode', sa.String(length=50), nullable=True, comment='股票代码'),
|
||||||
|
sa.Column('orgCode', sa.String(length=50), nullable=True, comment='机构代码'),
|
||||||
|
sa.Column('orgName', sa.String(length=255), nullable=True, comment='机构全称'),
|
||||||
|
sa.Column('orgSName', sa.String(length=100), nullable=True, comment='机构简称'),
|
||||||
|
sa.Column('publishDate', sa.String(length=50), nullable=True, comment='发布日期'),
|
||||||
|
sa.Column('column', sa.String(length=255), nullable=True, comment='栏目'),
|
||||||
|
sa.Column('predictNextTwoYearEps', sa.String(length=50), nullable=True, comment='未来两年EPS预测'),
|
||||||
|
sa.Column('predictNextTwoYearPe', sa.String(length=50), nullable=True, comment='未来两年PE预测'),
|
||||||
|
sa.Column('predictNextYearEps', sa.String(length=50), nullable=True, comment='明年EPS预测'),
|
||||||
|
sa.Column('predictNextYearPe', sa.String(length=50), nullable=True, comment='明年PE预测'),
|
||||||
|
sa.Column('predictThisYearEps', sa.String(length=50), nullable=True, comment='今年EPS预测'),
|
||||||
|
sa.Column('predictThisYearPe', sa.String(length=50), nullable=True, comment='今年PE预测'),
|
||||||
|
sa.Column('predictLastYearEps', sa.String(length=50), nullable=True, comment='去年EPS预测'),
|
||||||
|
sa.Column('predictLastYearPe', sa.String(length=50), nullable=True, comment='去年PE预测'),
|
||||||
|
sa.Column('actualLastTwoYearEps', sa.String(length=50), nullable=True, comment='前两年实际EPS'),
|
||||||
|
sa.Column('actualLastYearEps', sa.String(length=50), nullable=True, comment='去年实际EPS'),
|
||||||
|
sa.Column('industryCode', sa.String(length=50), nullable=True, comment='行业代码'),
|
||||||
|
sa.Column('industryName', sa.String(length=100), nullable=True, comment='行业名称'),
|
||||||
|
sa.Column('emIndustryCode', sa.String(length=50), nullable=True, comment='东方财富行业代码'),
|
||||||
|
sa.Column('indvInduCode', sa.String(length=50), nullable=True, comment='个性化行业代码'),
|
||||||
|
sa.Column('indvInduName', sa.String(length=100), nullable=True, comment='个性化行业名称'),
|
||||||
|
sa.Column('emRatingCode', sa.String(length=50), nullable=True, comment='东方财富评级代码'),
|
||||||
|
sa.Column('emRatingValue', sa.String(length=50), nullable=True, comment='东方财富评级值'),
|
||||||
|
sa.Column('emRatingName', sa.String(length=100), nullable=True, comment='东方财富评级名称'),
|
||||||
|
sa.Column('lastEmRatingCode', sa.String(length=50), nullable=True, comment='上次东方财富评级代码'),
|
||||||
|
sa.Column('lastEmRatingValue', sa.String(length=50), nullable=True, comment='上次东方财富评级值'),
|
||||||
|
sa.Column('lastEmRatingName', sa.String(length=100), nullable=True, comment='上次东方财富评级名称'),
|
||||||
|
sa.Column('ratingChange', sa.Integer(), nullable=True, comment='评级变动'),
|
||||||
|
sa.Column('reportType', sa.Integer(), nullable=True, comment='报告类型'),
|
||||||
|
sa.Column('author', sa.String(length=255), nullable=True, comment='作者(逗号分隔)'),
|
||||||
|
sa.Column('indvIsNew', sa.String(length=20), nullable=True, comment='是否为新研报'),
|
||||||
|
sa.Column('researcher', sa.String(length=255), nullable=True, comment='研究员'),
|
||||||
|
sa.Column('newListingDate', sa.String(length=50), nullable=True, comment='新上市日期'),
|
||||||
|
sa.Column('newPurchaseDate', sa.String(length=50), nullable=True, comment='新买入日期'),
|
||||||
|
sa.Column('newIssuePrice', sa.Float(), nullable=True, comment='新发行价格'),
|
||||||
|
sa.Column('newPeIssueA', sa.Float(), nullable=True, comment='新发行市盈率A'),
|
||||||
|
sa.Column('indvAimPriceT', sa.String(length=50), nullable=True, comment='目标价上限'),
|
||||||
|
sa.Column('indvAimPriceL', sa.String(length=50), nullable=True, comment='目标价下限'),
|
||||||
|
sa.Column('attachType', sa.String(length=50), nullable=True, comment='附件类型'),
|
||||||
|
sa.Column('attachSize', sa.Integer(), nullable=True, comment='附件大小'),
|
||||||
|
sa.Column('attachPages', sa.Integer(), nullable=True, comment='附件页数'),
|
||||||
|
sa.Column('encodeUrl', sa.String(length=512), nullable=True, comment='加密URL'),
|
||||||
|
sa.Column('sRatingName', sa.String(length=100), nullable=True, comment='评级名称'),
|
||||||
|
sa.Column('sRatingCode', sa.String(length=50), nullable=True, comment='评级代码'),
|
||||||
|
sa.Column('market', sa.String(length=50), nullable=True, comment='市场'),
|
||||||
|
sa.Column('authorID', sa.String(length=255), nullable=True, comment='作者ID(逗号分隔)'),
|
||||||
|
sa.Column('count', sa.Integer(), nullable=True, comment='计数'),
|
||||||
|
sa.Column('orgType', sa.String(length=50), nullable=True, comment='机构类型'),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=False, comment='创建时间'),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=False, comment='更新时间'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('infoCode')
|
||||||
|
)
|
||||||
|
op.create_table('reports_strategy',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='自增主键'),
|
||||||
|
sa.Column('infoCode', sa.String(length=255), nullable=False, comment='报告唯一标识'),
|
||||||
|
sa.Column('title', sa.String(length=512), nullable=True, comment='报告标题'),
|
||||||
|
sa.Column('author', sa.String(length=255), nullable=True, comment='作者(逗号分隔)'),
|
||||||
|
sa.Column('orgName', sa.String(length=255), nullable=True, comment='机构全称'),
|
||||||
|
sa.Column('orgCode', sa.String(length=50), nullable=True, comment='机构代码'),
|
||||||
|
sa.Column('orgSName', sa.String(length=100), nullable=True, comment='机构简称'),
|
||||||
|
sa.Column('publishDate', sa.String(length=50), nullable=True, comment='发布日期'),
|
||||||
|
sa.Column('encodeUrl', sa.String(length=512), nullable=True, comment='加密URL'),
|
||||||
|
sa.Column('researcher', sa.String(length=255), nullable=True, comment='研究员'),
|
||||||
|
sa.Column('market', sa.String(length=50), nullable=True, comment='市场'),
|
||||||
|
sa.Column('industryCode', sa.String(length=50), nullable=True, comment='行业代码'),
|
||||||
|
sa.Column('industryName', sa.String(length=100), nullable=True, comment='行业名称'),
|
||||||
|
sa.Column('authorID', sa.String(length=255), nullable=True, comment='作者ID(逗号分隔)'),
|
||||||
|
sa.Column('count', sa.Integer(), nullable=True, comment='计数'),
|
||||||
|
sa.Column('orgType', sa.String(length=50), nullable=True, comment='机构类型'),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=False, comment='创建时间'),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=False, comment='更新时间'),
|
||||||
|
sa.Column('stockName', sa.String(length=100), nullable=False, comment='股票名称(默认空字符串)'),
|
||||||
|
sa.Column('stockCode', sa.String(length=50), nullable=False, comment='股票代码(默认空字符串)'),
|
||||||
|
sa.Column('attachPages', sa.Integer(), nullable=True, comment='附件页数'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('infoCode')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('reports_strategy')
|
||||||
|
op.drop_table('reports_stock')
|
||||||
|
op.drop_table('reports_newstrock')
|
||||||
|
op.drop_table('reports_macresearch')
|
||||||
|
op.drop_table('reports_industry')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
"""Auto update from stockdb
|
||||||
|
|
||||||
|
Revision ID: c72bb1f27166
|
||||||
|
Revises: 33c9c4443fa8
|
||||||
|
Create Date: 2025-08-10 18:36:58.748680
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = 'c72bb1f27166'
|
||||||
|
down_revision: Union[str, Sequence[str], None] = '33c9c4443fa8'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('reports_industry', sa.Column('curr_column', sa.String(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.add_column('reports_industry', sa.Column('count_all', sa.Integer(), nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_industry', 'column')
|
||||||
|
op.drop_column('reports_industry', 'count')
|
||||||
|
op.add_column('reports_macresearch', sa.Column('count_all', sa.Integer(), nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_macresearch', 'count')
|
||||||
|
op.add_column('reports_newstrock', sa.Column('curr_column', sa.String(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.add_column('reports_newstrock', sa.Column('count_all', sa.Integer(), nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_newstrock', 'column')
|
||||||
|
op.drop_column('reports_newstrock', 'count')
|
||||||
|
op.add_column('reports_stock', sa.Column('curr_column', sa.String(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.add_column('reports_stock', sa.Column('count_all', sa.Integer(), nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_stock', 'column')
|
||||||
|
op.drop_column('reports_stock', 'count')
|
||||||
|
op.add_column('reports_strategy', sa.Column('count_all', sa.Integer(), nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_strategy', 'count')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('reports_strategy', sa.Column('count', mysql.INTEGER(), autoincrement=False, nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_strategy', 'count_all')
|
||||||
|
op.add_column('reports_stock', sa.Column('count', mysql.INTEGER(), autoincrement=False, nullable=True, comment='计数'))
|
||||||
|
op.add_column('reports_stock', sa.Column('column', mysql.VARCHAR(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.drop_column('reports_stock', 'count_all')
|
||||||
|
op.drop_column('reports_stock', 'curr_column')
|
||||||
|
op.add_column('reports_newstrock', sa.Column('count', mysql.INTEGER(), autoincrement=False, nullable=True, comment='计数'))
|
||||||
|
op.add_column('reports_newstrock', sa.Column('column', mysql.VARCHAR(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.drop_column('reports_newstrock', 'count_all')
|
||||||
|
op.drop_column('reports_newstrock', 'curr_column')
|
||||||
|
op.add_column('reports_macresearch', sa.Column('count', mysql.INTEGER(), autoincrement=False, nullable=True, comment='计数'))
|
||||||
|
op.drop_column('reports_macresearch', 'count_all')
|
||||||
|
op.add_column('reports_industry', sa.Column('count', mysql.INTEGER(), autoincrement=False, nullable=True, comment='计数'))
|
||||||
|
op.add_column('reports_industry', sa.Column('column', mysql.VARCHAR(length=255), nullable=True, comment='栏目'))
|
||||||
|
op.drop_column('reports_industry', 'count_all')
|
||||||
|
op.drop_column('reports_industry', 'curr_column')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -1,6 +1,7 @@
|
|||||||
from sqlalchemy import BigInteger, Date, DateTime, Double, Float, Integer, String, text, Numeric
|
from sqlalchemy import BigInteger, Date, DateTime, Double, Float, Integer, String, text, Numeric
|
||||||
from sqlalchemy.dialects.mysql import TINYINT, VARCHAR
|
from sqlalchemy.dialects.mysql import TINYINT, VARCHAR
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
|
||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||||
import datetime
|
import datetime
|
||||||
@ -446,3 +447,227 @@ class FutuTradingDayModel(Base):
|
|||||||
String(20),
|
String(20),
|
||||||
comment="交易日类型"
|
comment="交易日类型"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsStock(Base):
|
||||||
|
__tablename__ = "reports_stock"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="自增主键")
|
||||||
|
infoCode: Mapped[str] = mapped_column(String(255), unique=True, comment="报告唯一标识")
|
||||||
|
title: Mapped[Optional[str]] = mapped_column(String(512), comment="报告标题")
|
||||||
|
stockName: Mapped[Optional[str]] = mapped_column(String(100), comment="股票名称")
|
||||||
|
stockCode: Mapped[Optional[str]] = mapped_column(String(50), comment="股票代码")
|
||||||
|
orgCode: Mapped[Optional[str]] = mapped_column(String(50), comment="机构代码")
|
||||||
|
orgName: Mapped[Optional[str]] = mapped_column(String(255), comment="机构全称")
|
||||||
|
orgSName: Mapped[Optional[str]] = mapped_column(String(100), comment="机构简称")
|
||||||
|
publishDate: Mapped[Optional[str]] = mapped_column(String(50), comment="发布日期")
|
||||||
|
curr_column: Mapped[Optional[str]] = mapped_column(String(255), comment="栏目") # 注意:column是SQL关键字,建议后续改名
|
||||||
|
predictNextTwoYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="未来两年EPS预测")
|
||||||
|
predictNextTwoYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="未来两年PE预测")
|
||||||
|
predictNextYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="明年EPS预测")
|
||||||
|
predictNextYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="明年PE预测")
|
||||||
|
predictThisYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="今年EPS预测")
|
||||||
|
predictThisYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="今年PE预测")
|
||||||
|
predictLastYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="去年EPS预测")
|
||||||
|
predictLastYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="去年PE预测")
|
||||||
|
actualLastTwoYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="前两年实际EPS")
|
||||||
|
actualLastYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="去年实际EPS")
|
||||||
|
industryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="行业代码")
|
||||||
|
industryName: Mapped[Optional[str]] = mapped_column(String(100), comment="行业名称")
|
||||||
|
emIndustryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富行业代码")
|
||||||
|
indvInduCode: Mapped[Optional[str]] = mapped_column(String(50), comment="个性化行业代码")
|
||||||
|
indvInduName: Mapped[Optional[str]] = mapped_column(String(100), comment="个性化行业名称")
|
||||||
|
emRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级代码")
|
||||||
|
emRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级值")
|
||||||
|
emRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="东方财富评级名称")
|
||||||
|
lastEmRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级代码")
|
||||||
|
lastEmRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级值")
|
||||||
|
lastEmRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="上次东方财富评级名称")
|
||||||
|
ratingChange: Mapped[Optional[int]] = mapped_column(Integer, comment="评级变动")
|
||||||
|
reportType: Mapped[Optional[int]] = mapped_column(Integer, comment="报告类型")
|
||||||
|
author: Mapped[Optional[str]] = mapped_column(String(255), comment="作者(逗号分隔)")
|
||||||
|
indvIsNew: Mapped[Optional[str]] = mapped_column(String(20), comment="是否为新研报")
|
||||||
|
researcher: Mapped[Optional[str]] = mapped_column(String(255), comment="研究员")
|
||||||
|
newListingDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新上市日期")
|
||||||
|
newPurchaseDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新买入日期")
|
||||||
|
newIssuePrice: Mapped[Optional[float]] = mapped_column(Float, comment="新发行价格")
|
||||||
|
newPeIssueA: Mapped[Optional[float]] = mapped_column(Float, comment="新发行市盈率A")
|
||||||
|
indvAimPriceT: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价上限")
|
||||||
|
indvAimPriceL: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价下限")
|
||||||
|
attachType: Mapped[Optional[str]] = mapped_column(String(50), comment="附件类型")
|
||||||
|
attachSize: Mapped[Optional[int]] = mapped_column(Integer, comment="附件大小")
|
||||||
|
attachPages: Mapped[Optional[int]] = mapped_column(Integer, comment="附件页数")
|
||||||
|
encodeUrl: Mapped[Optional[str]] = mapped_column(String(512), comment="加密URL")
|
||||||
|
sRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="评级名称")
|
||||||
|
sRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="评级代码")
|
||||||
|
market: Mapped[Optional[str]] = mapped_column(String(50), comment="市场")
|
||||||
|
authorID: Mapped[Optional[str]] = mapped_column(String(255), comment="作者ID(逗号分隔)")
|
||||||
|
count_all: Mapped[Optional[int]] = mapped_column(Integer, comment="计数")
|
||||||
|
orgType: Mapped[Optional[str]] = mapped_column(String(50), comment="机构类型")
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsIndustry(Base):
|
||||||
|
__tablename__ = "reports_industry"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="自增主键")
|
||||||
|
infoCode: Mapped[str] = mapped_column(String(255), unique=True, comment="报告唯一标识")
|
||||||
|
title: Mapped[Optional[str]] = mapped_column(String(512), comment="报告标题")
|
||||||
|
stockName: Mapped[Optional[str]] = mapped_column(String(100), comment="股票名称")
|
||||||
|
stockCode: Mapped[Optional[str]] = mapped_column(String(50), comment="股票代码")
|
||||||
|
orgCode: Mapped[Optional[str]] = mapped_column(String(50), comment="机构代码")
|
||||||
|
orgName: Mapped[Optional[str]] = mapped_column(String(255), comment="机构全称")
|
||||||
|
orgSName: Mapped[Optional[str]] = mapped_column(String(100), comment="机构简称")
|
||||||
|
publishDate: Mapped[Optional[str]] = mapped_column(String(50), comment="发布日期")
|
||||||
|
curr_column: Mapped[Optional[str]] = mapped_column(String(255), comment="栏目") # 注意:column是SQL关键字
|
||||||
|
predictNextTwoYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="未来两年EPS预测")
|
||||||
|
predictNextTwoYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="未来两年PE预测")
|
||||||
|
predictNextYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="明年EPS预测")
|
||||||
|
predictNextYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="明年PE预测")
|
||||||
|
predictThisYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="今年EPS预测")
|
||||||
|
predictThisYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="今年PE预测")
|
||||||
|
predictLastYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="去年EPS预测")
|
||||||
|
predictLastYearPe: Mapped[Optional[str]] = mapped_column(String(50), comment="去年PE预测")
|
||||||
|
actualLastTwoYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="前两年实际EPS")
|
||||||
|
actualLastYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="去年实际EPS")
|
||||||
|
industryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="行业代码")
|
||||||
|
industryName: Mapped[Optional[str]] = mapped_column(String(100), comment="行业名称")
|
||||||
|
emIndustryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富行业代码")
|
||||||
|
indvInduCode: Mapped[Optional[str]] = mapped_column(String(50), comment="个性化行业代码")
|
||||||
|
indvInduName: Mapped[Optional[str]] = mapped_column(String(100), comment="个性化行业名称")
|
||||||
|
emRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级代码")
|
||||||
|
emRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级值")
|
||||||
|
emRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="东方财富评级名称")
|
||||||
|
lastEmRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级代码")
|
||||||
|
lastEmRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级值")
|
||||||
|
lastEmRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="上次东方财富评级名称")
|
||||||
|
ratingChange: Mapped[Optional[str]] = mapped_column(String(50), comment="评级变动")
|
||||||
|
reportType: Mapped[Optional[int]] = mapped_column(Integer, comment="报告类型")
|
||||||
|
author: Mapped[Optional[str]] = mapped_column(String(255), comment="作者(逗号分隔)")
|
||||||
|
indvIsNew: Mapped[Optional[str]] = mapped_column(String(20), comment="是否为新研报")
|
||||||
|
researcher: Mapped[Optional[str]] = mapped_column(String(255), comment="研究员")
|
||||||
|
newListingDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新上市日期")
|
||||||
|
newPurchaseDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新买入日期")
|
||||||
|
newIssuePrice: Mapped[Optional[str]] = mapped_column(String(50), comment="新发行价格")
|
||||||
|
newPeIssueA: Mapped[Optional[str]] = mapped_column(String(50), comment="新发行市盈率A")
|
||||||
|
indvAimPriceT: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价上限")
|
||||||
|
indvAimPriceL: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价下限")
|
||||||
|
attachType: Mapped[Optional[str]] = mapped_column(String(50), comment="附件类型")
|
||||||
|
attachSize: Mapped[Optional[int]] = mapped_column(Integer, comment="附件大小")
|
||||||
|
attachPages: Mapped[Optional[int]] = mapped_column(Integer, comment="附件页数")
|
||||||
|
encodeUrl: Mapped[Optional[str]] = mapped_column(String(512), comment="加密URL")
|
||||||
|
sRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="评级名称")
|
||||||
|
sRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="评级代码")
|
||||||
|
market: Mapped[Optional[str]] = mapped_column(String(50), comment="市场")
|
||||||
|
authorID: Mapped[Optional[str]] = mapped_column(String(255), comment="作者ID(逗号分隔)")
|
||||||
|
count_all: Mapped[Optional[int]] = mapped_column(Integer, comment="计数")
|
||||||
|
orgType: Mapped[Optional[str]] = mapped_column(String(50), comment="机构类型")
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsNewstrock(Base):
|
||||||
|
__tablename__ = "reports_newstrock" # 注意:原表名可能存在笔误(应为newstock)
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="自增主键")
|
||||||
|
infoCode: Mapped[str] = mapped_column(String(255), unique=True, comment="报告唯一标识")
|
||||||
|
title: Mapped[Optional[str]] = mapped_column(String(512), comment="报告标题")
|
||||||
|
stockName: Mapped[Optional[str]] = mapped_column(String(100), comment="股票名称")
|
||||||
|
stockCode: Mapped[Optional[str]] = mapped_column(String(50), comment="股票代码")
|
||||||
|
orgCode: Mapped[Optional[str]] = mapped_column(String(50), comment="机构代码")
|
||||||
|
orgName: Mapped[Optional[str]] = mapped_column(String(255), comment="机构全称")
|
||||||
|
orgSName: Mapped[Optional[str]] = mapped_column(String(100), comment="机构简称")
|
||||||
|
publishDate: Mapped[Optional[str]] = mapped_column(String(50), comment="发布日期")
|
||||||
|
curr_column: Mapped[Optional[str]] = mapped_column(String(255), comment="栏目") # 注意:column是SQL关键字
|
||||||
|
actualLastTwoYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="前两年实际EPS")
|
||||||
|
actualLastYearEps: Mapped[Optional[str]] = mapped_column(String(50), comment="去年实际EPS")
|
||||||
|
industryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="行业代码")
|
||||||
|
industryName: Mapped[Optional[str]] = mapped_column(String(100), comment="行业名称")
|
||||||
|
emIndustryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富行业代码")
|
||||||
|
indvInduCode: Mapped[Optional[str]] = mapped_column(String(50), comment="个性化行业代码")
|
||||||
|
indvInduName: Mapped[Optional[str]] = mapped_column(String(100), comment="个性化行业名称")
|
||||||
|
emRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级代码")
|
||||||
|
emRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="东方财富评级值")
|
||||||
|
emRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="东方财富评级名称")
|
||||||
|
lastEmRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级代码")
|
||||||
|
lastEmRatingValue: Mapped[Optional[str]] = mapped_column(String(50), comment="上次东方财富评级值")
|
||||||
|
lastEmRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="上次东方财富评级名称")
|
||||||
|
ratingChange: Mapped[Optional[str]] = mapped_column(String(50), comment="评级变动")
|
||||||
|
reportType: Mapped[Optional[int]] = mapped_column(Integer, comment="报告类型")
|
||||||
|
author: Mapped[Optional[str]] = mapped_column(String(255), comment="作者(逗号分隔)")
|
||||||
|
indvIsNew: Mapped[Optional[str]] = mapped_column(String(20), comment="是否为新研报")
|
||||||
|
researcher: Mapped[Optional[str]] = mapped_column(String(255), comment="研究员")
|
||||||
|
newListingDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新上市日期")
|
||||||
|
newPurchaseDate: Mapped[Optional[str]] = mapped_column(String(50), comment="新买入日期")
|
||||||
|
newIssuePrice: Mapped[Optional[float]] = mapped_column(Float, comment="新发行价格")
|
||||||
|
newPeIssueA: Mapped[Optional[float]] = mapped_column(Float, comment="新发行市盈率A")
|
||||||
|
indvAimPriceT: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价上限")
|
||||||
|
indvAimPriceL: Mapped[Optional[str]] = mapped_column(String(50), comment="目标价下限")
|
||||||
|
attachType: Mapped[Optional[str]] = mapped_column(String(50), comment="附件类型")
|
||||||
|
attachSize: Mapped[Optional[int]] = mapped_column(Integer, comment="附件大小")
|
||||||
|
attachPages: Mapped[Optional[int]] = mapped_column(Integer, comment="附件页数")
|
||||||
|
encodeUrl: Mapped[Optional[str]] = mapped_column(String(512), comment="加密URL")
|
||||||
|
sRatingName: Mapped[Optional[str]] = mapped_column(String(100), comment="评级名称")
|
||||||
|
sRatingCode: Mapped[Optional[str]] = mapped_column(String(50), comment="评级代码")
|
||||||
|
market: Mapped[Optional[str]] = mapped_column(String(50), comment="市场")
|
||||||
|
newStockSort: Mapped[Optional[str]] = mapped_column(String(50), comment="新股分类")
|
||||||
|
authorID: Mapped[Optional[str]] = mapped_column(String(255), comment="作者ID(逗号分隔)")
|
||||||
|
count_all: Mapped[Optional[int]] = mapped_column(Integer, comment="计数")
|
||||||
|
orgType: Mapped[Optional[str]] = mapped_column(String(50), comment="机构类型")
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsStrategy(Base):
|
||||||
|
__tablename__ = "reports_strategy"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="自增主键")
|
||||||
|
infoCode: Mapped[str] = mapped_column(String(255), unique=True, comment="报告唯一标识")
|
||||||
|
title: Mapped[Optional[str]] = mapped_column(String(512), comment="报告标题")
|
||||||
|
author: Mapped[Optional[str]] = mapped_column(String(255), comment="作者(逗号分隔)")
|
||||||
|
orgName: Mapped[Optional[str]] = mapped_column(String(255), comment="机构全称")
|
||||||
|
orgCode: Mapped[Optional[str]] = mapped_column(String(50), comment="机构代码")
|
||||||
|
orgSName: Mapped[Optional[str]] = mapped_column(String(100), comment="机构简称")
|
||||||
|
publishDate: Mapped[Optional[str]] = mapped_column(String(50), comment="发布日期")
|
||||||
|
encodeUrl: Mapped[Optional[str]] = mapped_column(String(512), comment="加密URL")
|
||||||
|
researcher: Mapped[Optional[str]] = mapped_column(String(255), comment="研究员")
|
||||||
|
market: Mapped[Optional[str]] = mapped_column(String(50), comment="市场")
|
||||||
|
industryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="行业代码")
|
||||||
|
industryName: Mapped[Optional[str]] = mapped_column(String(100), comment="行业名称")
|
||||||
|
authorID: Mapped[Optional[str]] = mapped_column(String(255), comment="作者ID(逗号分隔)")
|
||||||
|
count_all: Mapped[Optional[int]] = mapped_column(Integer, comment="计数")
|
||||||
|
orgType: Mapped[Optional[str]] = mapped_column(String(50), comment="机构类型")
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
stockName: Mapped[str] = mapped_column(String(100), default="", nullable=False, comment="股票名称(默认空字符串)")
|
||||||
|
stockCode: Mapped[str] = mapped_column(String(50), default="", nullable=False, comment="股票代码(默认空字符串)")
|
||||||
|
attachPages: Mapped[Optional[int]] = mapped_column(Integer, comment="附件页数")
|
||||||
|
|
||||||
|
|
||||||
|
class ReportsMacresearch(Base):
|
||||||
|
__tablename__ = "reports_macresearch"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="自增主键")
|
||||||
|
infoCode: Mapped[str] = mapped_column(String(255), unique=True, comment="报告唯一标识")
|
||||||
|
json_id: Mapped[Optional[str]] = mapped_column(String(50), comment="JSON ID")
|
||||||
|
title: Mapped[Optional[str]] = mapped_column(String(512), comment="报告标题")
|
||||||
|
author: Mapped[Optional[str]] = mapped_column(String(255), comment="作者(逗号分隔)")
|
||||||
|
orgName: Mapped[Optional[str]] = mapped_column(String(255), comment="机构全称")
|
||||||
|
orgCode: Mapped[Optional[str]] = mapped_column(String(50), comment="机构代码")
|
||||||
|
orgSName: Mapped[Optional[str]] = mapped_column(String(100), comment="机构简称")
|
||||||
|
publishDate: Mapped[Optional[str]] = mapped_column(String(50), comment="发布日期")
|
||||||
|
encodeUrl: Mapped[Optional[str]] = mapped_column(String(512), comment="加密URL")
|
||||||
|
researcher: Mapped[Optional[str]] = mapped_column(String(255), comment="研究员")
|
||||||
|
market: Mapped[Optional[str]] = mapped_column(String(50), comment="市场")
|
||||||
|
industryCode: Mapped[Optional[str]] = mapped_column(String(50), comment="行业代码")
|
||||||
|
industryName: Mapped[Optional[str]] = mapped_column(String(100), comment="行业名称")
|
||||||
|
authorID: Mapped[Optional[str]] = mapped_column(String(255), comment="作者ID(逗号分隔)")
|
||||||
|
count_all: Mapped[Optional[int]] = mapped_column(Integer, comment="计数")
|
||||||
|
orgType: Mapped[Optional[str]] = mapped_column(String(50), comment="机构类型")
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||||||
|
stockCode: Mapped[str] = mapped_column(String(50), default="", nullable=False, comment="股票代码(默认空字符串)")
|
||||||
|
stockName: Mapped[str] = mapped_column(String(100), default="", nullable=False, comment="股票名称(默认空字符串)")
|
||||||
|
attachPages: Mapped[Optional[int]] = mapped_column(Integer, comment="附件页数")
|
||||||
|
|||||||
Reference in New Issue
Block a user