updata updatekline.py

This commit is contained in:
2025-08-20 14:09:35 +08:00
parent 3be41434e3
commit 786c669d62
12 changed files with 1137 additions and 957 deletions

View File

@@ -10,18 +10,20 @@
—— 根据股票代码,获取股票历史数据
—— 根据股票代码,获取流通股数量
—— 根据股票代码,新建/更新数据表
—— 更新完成需检查 ,数据是否完整 -> checktable.py 操作界面做好了之后,再融合到整体代码中
"""
from futu import *
from pymysql import Error
from MySQLHelper import MySQLHelper # MySQLHelper类保存为单独文件
from LogHelper import LogHelper
from datetime import datetime
import logging
from typing import Optional, List, Dict, Union, Tuple
import time
from typing import Optional, List, Dict
from ConditionalSelection import FutuStockFilter
from tqdm import tqdm
import pandas as pd
import time
# 基本用法(自动创建日期日志+控制台输出)
logger = LogHelper(logger_name = 'KLine').setup()
def get_market_data(market: Market) -> List[str]:
"""
@@ -39,13 +41,13 @@ def get_market_data(market: Market) -> List[str]:
if ret == RET_OK:
# 提取code列并转换为列表
codes = data['code'].astype(str).tolist()
logging.info(f"获取到 {market} 市场 {len(codes)} 个股票代码")
logger.info(f"获取到 {market} 市场 {len(codes)} 个股票代码")
return codes
else:
logging.error(f"获取股票代码失败: {data}")
logger.error(f"获取股票代码失败: {data}")
return []
except Exception as e:
logging.error(f"获取股票代码时发生异常: {str(e)}")
logger.error(f"获取股票代码时发生异常: {str(e)}")
return []
finally:
quote_ctx.close()
@@ -89,7 +91,7 @@ def preprocess_quote_data(df: pd.DataFrame, float_share: Optional[int] = None) -
}
processed_data.append(item)
except Exception as e:
logging.warning(f"处理行情数据时跳过异常行 {row.get('code', '未知')}: {str(e)}")
logger.warning(f"处理行情数据时跳过异常行 {row.get('code', '未知')}: {str(e)}")
continue
return processed_data
@@ -115,7 +117,7 @@ def get_float_share(quote_ctx: OpenQuoteContext, code: str) -> Optional[int]:
return int(float_share)
return None
except Exception as e:
logging.error(f"获取股票 {code} 的流通股数量失败: {str(e)}")
logger.error(f"获取股票 {code} 的流通股数量失败: {str(e)}")
return None
def get_float_share_data(db_config: dict, table_name: str) -> Optional[Dict[str, int]]:
@@ -139,7 +141,7 @@ def get_float_share_data(db_config: dict, table_name: str) -> Optional[Dict[str,
""")
if not data:
logging.error(f"{table_name} 中没有流通股本数据")
logger.error(f"{table_name} 中没有流通股本数据")
return None
# 构建股票代码到流通股数量的映射字典
@@ -150,11 +152,11 @@ def get_float_share_data(db_config: dict, table_name: str) -> Optional[Dict[str,
if stock_code and float_share is not None:
float_share_dict[stock_code] = int(float_share)
logging.info(f"成功从 {table_name} 表加载 {len(float_share_dict)} 条流通股数据")
logger.info(f"成功从 {table_name} 表加载 {len(float_share_dict)} 条流通股数据")
return float_share_dict
except Exception as e:
logging.error(f"从数据库读取流通股本数据失败: {str(e)}")
logger.error(f"从数据库读取流通股本数据失败: {str(e)}")
return None
def save_quotes_to_db(db_config: dict, quote_data: pd.DataFrame, table_name: str = 'stock_quotes', float_share: Optional[int] = None) -> bool:
@@ -173,7 +175,7 @@ def save_quotes_to_db(db_config: dict, quote_data: pd.DataFrame, table_name: str
# 预处理数据
processed_data = preprocess_quote_data(quote_data, float_share)
if not processed_data:
logging.error("没有有效数据需要保存")
logger.error("没有有效数据需要保存")
return False
# 动态生成SQL插入语句
@@ -230,13 +232,13 @@ def save_quotes_to_db(db_config: dict, quote_data: pd.DataFrame, table_name: str
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='股票行情数据表'
"""
db.execute_update(create_table_sql)
logging.info(f"创建了新表: {table_name}")
logger.info(f"创建了新表: {table_name}")
affected_rows = db.execute_many(insert_sql, processed_data)
logging.info(f"成功插入/更新 {affected_rows} 条行情记录到表 {table_name}")
logger.info(f"成功插入/更新 {affected_rows} 条行情记录到表 {table_name}")
return True
except Exception as e:
logging.error(f"保存行情数据到表 {table_name} 失败: {str(e)}")
logger.error(f"保存行情数据到表 {table_name} 失败: {str(e)}")
return False
def read_single_account_stock_codes(file_path='data\missing_tables_小航富途.txt'):
@@ -262,22 +264,28 @@ def get_stock_codes() -> List[str]:
results = db.execute_query(sql)
return [row['stock_code'] for row in results if row['stock_code']]
except Exception as e:
logging.error(f"获取股票代码失败: {str(e)}")
logger.error(f"获取股票代码失败: {str(e)}")
return []
def write_missing_codes_to_txt(missing_codes: list, filename: str = "config\HK_futu.txt"):
"""将缺失的股票代码追加到TXT文件如果文件不存在则创建"""
try:
# 确保目录存在
directory = os.path.dirname(filename)
if directory and not os.path.exists(directory):
os.makedirs(directory)
logger.info(f"创建目录: {directory}")
# # 检查文件是否存在
# file_exists = os.path.exists(filename)
with open(filename, 'a', encoding='utf-8') as f:
for code in missing_codes:
f.write(f"\n{code}")
logger.info(f"已将 {len(missing_codes)} 个缺失表对应的股票代码写入 {filename}")
except Exception as e:
logger.error(f"写入TXT文件失败: {str(e)}")
if __name__ == "__main__":
# 基本用法(自动创建日期日志+控制台输出)
logger = LogHelper().setup()
# # 高级用法(自定义配置)
# logger = LogHelper(
# level=logging.DEBUG,
# log_dir="my_logs",
# format='%(levelname)s - %(message)s'
# ).setup()
# 数据库配置
db_config = {
'host': 'localhost',
@@ -286,19 +294,25 @@ if __name__ == "__main__":
'database': 'hk_kline_1d'
}
# 创建导入器并运行, 用于每日更新流通股数量
# 创建导入器并运行, 用于每日更新流通股数量 -> 操作界面中增加一个开关,每天只需要更新一次
futuStockFilter = FutuStockFilter(db_config)
futuStockFilter.run_direct_import()
# 每个账号获取的数据独立开来
# 每个账号获取的数据独立开来 -> 操作见面可以选择
market_data_all = get_stock_codes()
market_data_hang = read_single_account_stock_codes('config\hang_futu.txt')
market_data_kevin= read_single_account_stock_codes('config\kevin_futu.txt')
market_data = list(set(market_data_all) - set(market_data_hang) - set(market_data_kevin))
market_data_HK= read_single_account_stock_codes('config\HK_futu.txt')
market_data_new = list(set(market_data_all) - set(market_data_hang) - set(market_data_kevin) - set(market_data_HK))
# 每天收盘后更新数据
start_date = (datetime.now() - timedelta(days = 3 * 365)).strftime("%Y-%m-%d")
# write_missing_codes_to_txt(market_data_new) # 新股票添加到文件中 -> 暂时手动设置
# 动态调整
"""*********************************************"""
market_data = market_data_new
# 每天收盘后更新数据 -> 操作界面中,这个参数需要放出来
start_date = (datetime.now() - timedelta(days = 5)).strftime("%Y-%m-%d")
end_date = (datetime.now() + timedelta(days = 1)).strftime("%Y-%m-%d")
# 获取流通股数据字典
@@ -319,7 +333,7 @@ if __name__ == "__main__":
if float_share is not None:
logger.info(f"从API获取股票 {code} 的流通股数量: {float_share}")
else:
logging.warning(f"无法获取股票 {code} 的流通股数量")
logger.warning(f"无法获取股票 {code} 的流通股数量")
# 获取历史K线数据
ret, data, page_req_key = quote_ctx.request_history_kline(code, start=start_date, end=end_date, max_count=100)
@@ -341,9 +355,9 @@ if __name__ == "__main__":
else:
logger.error(f'error:{ data}')
time.sleep(1)
time.sleep(0.7)
if isWhile == False:
time.sleep(1)
time.sleep(0.7)
quote_ctx.close() # 结束后记得关闭当条连接,防止连接条数用尽