106 lines
4.0 KiB
Python
106 lines
4.0 KiB
Python
import pandas as pd
|
|
from sqlalchemy import create_engine
|
|
|
|
|
|
def analyze_stock_performance(start_date, end_date):
|
|
# --- 数据库配置 ---
|
|
try:
|
|
engine = create_engine(
|
|
"mysql+pymysql://yangfan@8.159.129.156:10836/level?charset=utf8mb4",
|
|
connect_args={
|
|
"password": "aA%8023321088"
|
|
},
|
|
pool_pre_ping=True
|
|
)
|
|
|
|
# 1. 获取涨停当日股票及价格
|
|
limit_query = f"""
|
|
SELECT l.ts_code, l.name, d.open AS limit_day_open, d.high AS limit_day_high
|
|
FROM stock_limit_data l
|
|
LEFT JOIN stock_daily d ON l.ts_code = d.ts_code AND l.trade_date = d.trade_date
|
|
WHERE l.trade_date = '{start_date}' AND l.status = 1
|
|
"""
|
|
df_limit = pd.read_sql(limit_query, engine)
|
|
|
|
if df_limit.empty:
|
|
print(f"提示:{start_date} 当日没有涨停记录。")
|
|
return
|
|
|
|
# 2. 获取行情区间数据
|
|
codes = df_limit['ts_code'].unique().tolist()
|
|
codes_tuple = f"('{codes[0]}')" if len(codes) == 1 else str(tuple(codes))
|
|
daily_query = f"""
|
|
SELECT ts_code, trade_date, high, low, close
|
|
FROM stock_daily
|
|
WHERE ts_code IN {codes_tuple} AND trade_date BETWEEN '{start_date}' AND '{end_date}'
|
|
ORDER BY trade_date ASC
|
|
"""
|
|
df_daily = pd.read_sql(daily_query, engine)
|
|
df_daily['trade_date'] = pd.to_datetime(df_daily['trade_date'])
|
|
|
|
# 3. 核心逻辑处理
|
|
final_report = []
|
|
for _, limit_row in df_limit.iterrows():
|
|
code = limit_row['ts_code']
|
|
stock_data = df_daily[df_daily['ts_code'] == code].copy()
|
|
|
|
if stock_data.empty: continue
|
|
|
|
# A. 找到区间内的最高价及其第一次出现的日期
|
|
max_high = float(stock_data['high'].max())
|
|
# 获取最高价所在的那一行(如果有多个相同最高价,取第一个)
|
|
max_high_row = stock_data[stock_data['high'] == max_high].iloc[0]
|
|
max_date = max_high_row['trade_date']
|
|
|
|
# B. 寻找最高价日期之后的最低价
|
|
post_max_data = stock_data[stock_data['trade_date'] > max_date]
|
|
|
|
if not post_max_data.empty:
|
|
min_low = float(post_max_data['low'].min())
|
|
last_close = float(post_max_data.iloc[-1]['close'])
|
|
|
|
price_diff = max_high - min_low
|
|
drop_pct = (price_diff / max_high * 100)
|
|
rebound_pct = ((last_close - min_low) / min_low * 100) if min_low > 0 else 0
|
|
else:
|
|
# 如果最高点出现在结束日当天,则没有“后期最低价”
|
|
min_low = None
|
|
price_diff = 0
|
|
drop_pct = 0
|
|
rebound_pct = 0
|
|
|
|
final_report.append({
|
|
"代码": code,
|
|
"名称": limit_row['name'],
|
|
"当日开盘": float(limit_row['limit_day_open'] or 0),
|
|
"当日最高": float(limit_row['limit_day_high'] or 0),
|
|
"区间最高": max_high,
|
|
"最高日期": max_date.strftime('%Y-%m-%d'),
|
|
"见顶后最低": min_low,
|
|
"最大回落幅%": round(drop_pct, 2),
|
|
"低位至期末波动%": round(rebound_pct, 2)
|
|
})
|
|
|
|
# 4. 排序与输出
|
|
if final_report:
|
|
result_df = pd.DataFrame(final_report)
|
|
result_df = result_df.sort_values(by="最大回落幅%", ascending=False)
|
|
|
|
print(f"\n分析区间: {start_date} 至 {end_date}")
|
|
print("说明: '见顶后最低' 指最高价日期之后的最低点")
|
|
print("=" * 120)
|
|
print(result_df.to_string(index=False, na_rep='N/A'))
|
|
print("=" * 120)
|
|
|
|
except Exception as e:
|
|
print(f"发生错误: {e}")
|
|
|
|
|
|
# ==========================================
|
|
# 设定日期
|
|
# ==========================================
|
|
if __name__ == "__main__":
|
|
START_INPUT = '2024-09-24'
|
|
END_INPUT = '2026-04-23'
|
|
|
|
analyze_stock_performance(START_INPUT, END_INPUT) |