187 lines
6.7 KiB
Python
187 lines
6.7 KiB
Python
|
import sys
|
|||
|
|
|||
|
from loguru import logger
|
|||
|
from DB.model.StockDaily import get_stock_daily
|
|||
|
from DB.sqlite_db_main import SqliteDbMain, config
|
|||
|
from utils.tdxUtil import TdxUtil
|
|||
|
from utils.comm import *
|
|||
|
from fp.基本信息入库 import StockInfoMain
|
|||
|
|
|||
|
|
|||
|
class StockDailyMain:
|
|||
|
|
|||
|
def __init__(self, ts_code=None, symbol=None, restart_id=0):
|
|||
|
# 配置日志输出到文件和控制台
|
|||
|
logger.add("../log/StockDailyMain.log", rotation="500 MB", level="INFO")
|
|||
|
logger.add(sys.stderr, level="INFO")
|
|||
|
self.code_res = StockInfoMain().get_stock_basic(ts_code=ts_code, symbol=symbol, restart_id=restart_id)
|
|||
|
self.db_main = SqliteDbMain(config.stock_daily_db)
|
|||
|
self.tdx_util = TdxUtil("")
|
|||
|
|
|||
|
def __filter_stock(self, code, name):
|
|||
|
if 'ST' in name:
|
|||
|
return False
|
|||
|
if code.startswith('30'):
|
|||
|
return False
|
|||
|
if code.startswith('68'):
|
|||
|
return False
|
|||
|
return True
|
|||
|
|
|||
|
def init_data(self):
|
|||
|
"""
|
|||
|
全量入库操作
|
|||
|
:return:
|
|||
|
"""
|
|||
|
for result in self.code_res:
|
|||
|
tdx_util = TdxUtil("")
|
|||
|
s_type = tdx_util.get_security_type(code=result.ts_code)
|
|||
|
if s_type in tdx_util.SECURITY_TYPE and self.__filter_stock(result.ts_code, result.name):
|
|||
|
logger.info(f"{result.id},{result.ts_code},{result.name} 开始获取 daily 和 daily_basic_ts 数据!")
|
|||
|
self.save_by_code(result.ts_code)
|
|||
|
|
|||
|
def save_by_code(self, ts_code):
|
|||
|
df, df_basic = self.get_daily_data(ts_code=ts_code)
|
|||
|
if df is not None and df_basic is not None:
|
|||
|
# 创建表
|
|||
|
table_name = str(ts_code).split(".")[0] + "_daily"
|
|||
|
new_table_class = get_stock_daily(table_name=table_name)
|
|||
|
self.db_main.create_table(new_table_class)
|
|||
|
entries = []
|
|||
|
for index, row in df.iterrows():
|
|||
|
if '停牌' != row['trade_status']:
|
|||
|
basic_row = df_basic[df_basic['trade_date'] == row['trade_date']]
|
|||
|
if len(basic_row) > 0:
|
|||
|
basic_row = basic_row.drop(columns=['ts_code', 'trade_date', 'close'])
|
|||
|
if not basic_row.empty:
|
|||
|
row = pd.concat([row, basic_row.iloc[0]])
|
|||
|
entry = new_table_class(**row)
|
|||
|
entries.append(entry)
|
|||
|
# 保存记录
|
|||
|
self.db_main.insert_all_entry(entries)
|
|||
|
|
|||
|
def task_data(self, trade_date=datetime.now().strftime('%Y%m%d')):
|
|||
|
"""
|
|||
|
每日定时任务,补充数据操作
|
|||
|
:param trade_date:
|
|||
|
:return:
|
|||
|
"""
|
|||
|
df, df_basic = pd.DataFrame(), pd.DataFrame()
|
|||
|
# 日线行情数据
|
|||
|
for _ in range(5):
|
|||
|
try:
|
|||
|
df = xcsc_pro.daily(trade_date=trade_date)[::-1]
|
|||
|
break
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取 [{trade_date}] 日线行情 出现问题:", e)
|
|||
|
time.sleep(1)
|
|||
|
continue
|
|||
|
else:
|
|||
|
logger.error("daily 重试5次依然没有解决问题,请重视~!!!")
|
|||
|
# 获取全部股票每日重要的基本面指标
|
|||
|
for _ in range(5):
|
|||
|
try:
|
|||
|
df_basic = xcsc_pro.daily_basic_ts(trade_date=trade_date)[::-1]
|
|||
|
break
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取 [{trade_date}] daily_basic_ts 出现问题:", e)
|
|||
|
time.sleep(1)
|
|||
|
continue
|
|||
|
else:
|
|||
|
logger.error("daily_basic_ts 重试5次依然没有解决问题,请重视~!!!")
|
|||
|
df_basic = df_basic.fillna(0)
|
|||
|
print(f" 获取 daily 和 daily_basic_ts 数据完毕!")
|
|||
|
for index, row in df.iterrows():
|
|||
|
ts_code = row['ts_code']
|
|||
|
tdx_util = TdxUtil("")
|
|||
|
s_type = tdx_util.get_security_type(code=ts_code)
|
|||
|
if s_type in tdx_util.SECURITY_TYPE and '交易' == row['trade_status']:
|
|||
|
basic_row = df_basic[df_basic['ts_code'] == row['ts_code']]
|
|||
|
basic_row = basic_row.drop(columns=['ts_code', 'trade_date', 'close'])
|
|||
|
row = pd.concat([row, basic_row.iloc[0]])
|
|||
|
table_name = str(ts_code).split(".")[0] + "_daily"
|
|||
|
new_table_class = get_stock_daily(table_name=table_name)
|
|||
|
entry = new_table_class(**row)
|
|||
|
# 判断表是否存在
|
|||
|
if self.db_main.has_table(entry):
|
|||
|
self.db_main.insert_entry(entry)
|
|||
|
|
|||
|
# 批量创建trade_date唯一索引
|
|||
|
def create_index(self):
|
|||
|
for result in self.code_res:
|
|||
|
tdx_util = TdxUtil("")
|
|||
|
s_type = tdx_util.get_security_type(code=result.ts_code)
|
|||
|
if s_type in tdx_util.SECURITY_TYPE and self.__filter_stock(result.ts_code, result.name):
|
|||
|
print(f"{result.id},{result.ts_code},{result.name} 开始创建索引!")
|
|||
|
table_name = str(result.ts_code).split(".")[0] + "_daily"
|
|||
|
sql = f"CREATE UNIQUE INDEX idx_unique_trade_date_{table_name} ON `{table_name}`(trade_date)"
|
|||
|
self.db_main.execute_sql(sql)
|
|||
|
|
|||
|
# 删除指定日期的数据
|
|||
|
def del_data_by_date(self, trade_date):
|
|||
|
for result in self.code_res:
|
|||
|
tdx_util = TdxUtil("")
|
|||
|
s_type = tdx_util.get_security_type(code=result.ts_code)
|
|||
|
if s_type in tdx_util.SECURITY_TYPE and self.__filter_stock(result.ts_code, result.name):
|
|||
|
table_name = str(result.ts_code).split(".")[0] + "_daily"
|
|||
|
new_table_class = get_stock_daily(table_name=table_name)
|
|||
|
# 判断表是否存在
|
|||
|
if self.db_main.has_table(new_table_class):
|
|||
|
delete_condition = new_table_class.trade_date == trade_date
|
|||
|
self.db_main.delete_by_condition(new_table_class, delete_condition)
|
|||
|
|
|||
|
def get_daily_data(self, ts_code):
|
|||
|
i = 0
|
|||
|
df, df_basic = None, None
|
|||
|
while True:
|
|||
|
try:
|
|||
|
if i > 6:
|
|||
|
break
|
|||
|
# 尝试执行请求操作
|
|||
|
# 如果成功,可以跳出循环
|
|||
|
df = xcsc_pro.daily(ts_code=ts_code)[::-1]
|
|||
|
df_basic = xcsc_pro.daily_basic_ts(ts_code=ts_code)[::-1]
|
|||
|
df_basic = df_basic.fillna(0)
|
|||
|
logger.info(f"{ts_code} 获取 daily 和 daily_basic_ts 数据完毕!")
|
|||
|
break
|
|||
|
except Exception as e:
|
|||
|
i += 1
|
|||
|
# 捕获超时异常
|
|||
|
logger.warning("请求超时,等待2分钟后重试...")
|
|||
|
time.sleep(120) # 休眠2分钟
|
|||
|
return df, df_basic
|
|||
|
|
|||
|
def update_stock_basic(self):
|
|||
|
"""
|
|||
|
更新基础表,补齐股票表
|
|||
|
:return:
|
|||
|
"""
|
|||
|
# 1. 取 中国A股基本资料
|
|||
|
StockInfoMain().insert_stock_basic()
|
|||
|
self.code_res = StockInfoMain().get_stock_basic()
|
|||
|
for result in self.code_res:
|
|||
|
s_type = self.tdx_util.get_security_type(code=result.ts_code, name=result.name)
|
|||
|
if s_type not in self.tdx_util.SECURITY_TYPE:
|
|||
|
continue
|
|||
|
# 创建表
|
|||
|
table_name = str(result.ts_code).split(".")[0] + "_daily"
|
|||
|
new_table_class = get_stock_daily(table_name=table_name)
|
|||
|
# 2. 判断表是否存在,不存在则创建
|
|||
|
if not self.db_main.has_table(new_table_class):
|
|||
|
logger.info(f"{result.ts_code} 表不存在,开始创建!")
|
|||
|
# 3. 补齐数据
|
|||
|
self.save_by_code(result.ts_code)
|
|||
|
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
# current_date = datetime.now()
|
|||
|
current_date = datetime.strptime('20231024', "%Y%m%d")
|
|||
|
if if_run(current_date):
|
|||
|
trade_date = current_date.strftime('%Y%m%d')
|
|||
|
main = StockDailyMain()
|
|||
|
# main.init_data() # 初始化全市场的数据
|
|||
|
main.task_data(trade_date) # 指定日期数据入库
|
|||
|
# main.create_index() # 创建唯一索引
|
|||
|
# main.del_data_by_date('20230915') # 删除指定日期数据
|
|||
|
# main.save_by_code(ts_code='000050.SZ') # 指定更新的股票
|
|||
|
# main.update_stock_basic()
|