增加选股策略

This commit is contained in:
oficcejo
2025-12-12 19:46:38 +08:00
parent 595278100f
commit ad5865d3b4
25 changed files with 4818 additions and 20 deletions
+157
View File
@@ -0,0 +1,157 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
低价擒牛选股模块
使用pywencai获取低价高成长股票
"""
import pandas as pd
import pywencai
from datetime import datetime
from typing import Tuple, Optional
import time
class LowPriceBullSelector:
"""低价擒牛选股类"""
def __init__(self):
self.raw_data = None
self.selected_stocks = None
def get_low_price_stocks(self, top_n: int = 5) -> Tuple[bool, Optional[pd.DataFrame], str]:
"""
获取低价高成长股票
选股策略:
- 股价<10元
- 净利润增长率≥100%
- 非ST
- 非科创板
- 非创业板
- 深圳A股
- 成交额由小至大排名
Args:
top_n: 返回前N只股票
Returns:
(success, dataframe, message)
"""
try:
print(f"\n{'='*60}")
print(f"🐂 低价擒牛选股 - 数据获取中")
print(f"{'='*60}")
print(f"策略: 股价<10元 + 净利润增长率≥100% + 深圳A股")
print(f"目标: 筛选前{top_n}只股票")
# 构建查询语句(按成交额由小至大排名)
query = (
"股价<10元,"
"净利润增长率(净利润同比增长率)≥100%"
"非st"
"非科创板,"
"非创业板,"
"深圳A股,"
"成交额由小至大排名"
)
print(f"\n查询语句: {query}")
print(f"正在调用问财接口...")
# 调用pywencai
result = pywencai.get(query=query, loop=True)
if result is None:
return False, None, "问财接口返回None,请检查网络或稍后重试"
# 转换为DataFrame
df_result = self._convert_to_dataframe(result)
if df_result is None or df_result.empty:
return False, None, "未获取到符合条件的股票数据"
print(f"✅ 成功获取 {len(df_result)} 只股票")
# 显示获取到的列名
print(f"\n获取到的数据字段:")
for col in df_result.columns[:15]:
print(f" - {col}")
if len(df_result.columns) > 15:
print(f" ... 还有 {len(df_result.columns) - 15} 个字段")
# 保存原始数据
self.raw_data = df_result
# 取前N只
if len(df_result) > top_n:
selected = df_result.head(top_n)
print(f"\n{len(df_result)} 只股票中选出前 {top_n}")
else:
selected = df_result
print(f"\n{len(df_result)} 只符合条件的股票")
self.selected_stocks = selected
# 显示选中的股票
print(f"\n✅ 选中的股票:")
for idx, row in selected.iterrows():
code = row.get('股票代码', 'N/A')
name = row.get('股票简称', 'N/A')
price = row.get('股价', row.get('最新价', 'N/A'))
growth = row.get('净利润增长率', row.get('净利润同比增长率', 'N/A'))
turnover = row.get('成交额', 'N/A')
print(f" {idx+1}. {code} {name} - 股价:{price} 净利增长:{growth}% 成交额:{turnover}")
print(f"{'='*60}\n")
return True, selected, f"成功筛选出{len(selected)}只低价高成长股票"
except Exception as e:
error_msg = f"获取数据失败: {str(e)}"
print(f"{error_msg}")
import traceback
traceback.print_exc()
return False, None, error_msg
def _convert_to_dataframe(self, result) -> Optional[pd.DataFrame]:
"""将pywencai返回结果转换为DataFrame"""
try:
if isinstance(result, pd.DataFrame):
return result
elif isinstance(result, dict):
if 'data' in result:
return pd.DataFrame(result['data'])
elif 'result' in result:
return pd.DataFrame(result['result'])
else:
return pd.DataFrame(result)
elif isinstance(result, list):
return pd.DataFrame(result)
else:
print(f"⚠️ 未知的数据格式: {type(result)}")
return None
except Exception as e:
print(f"转换DataFrame失败: {e}")
return None
def get_stock_codes(self) -> list:
"""
获取选中股票的代码列表(去掉市场后缀)
Returns:
股票代码列表
"""
if self.selected_stocks is None or self.selected_stocks.empty:
return []
codes = []
for code in self.selected_stocks['股票代码'].tolist():
if isinstance(code, str):
# 去掉 .SZ 等后缀
clean_code = code.split('.')[0] if '.' in code else code
codes.append(clean_code)
else:
codes.append(str(code))
return codes