feat: 新增行业领涨股扫描 xiaoguo_scanner
- 新增 fetch_sector_leaders() 从 market.json 读取热门行业领涨股 - 三路并行:同花顺技术榜 + 行业领涨 + 东财热榜(502降级) - 优先级排序:行业领涨 > 同花顺榜 > 东财热榜 - 名称→代码映射使用本地缓存,避免频繁调用akshare - 更新文档
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -23,9 +23,15 @@ xiaoguo_scanner.py(每5分钟跑一轮)
|
|||||||
|
|
||||||
## 二、数据源
|
## 二、数据源
|
||||||
|
|
||||||
### 榜单来源
|
### 榜单来源(三路并行)
|
||||||
- 同花顺技术面榜单(akshare),覆盖技术指标类信号
|
1. **同花顺技术面榜单**(akshare,6看多+5看空轮换)— 技术指标类信号
|
||||||
- 东方财富热榜(akshare.stock_hot_rank_em)因502不可用,降级静默
|
2. **行业领涨股**(从 market.json 读取,每轮都跑)— 涨幅>2.5%板块的领涨龙头
|
||||||
|
3. **东方财富热榜**(akshare.stock_hot_rank_em)— 因502不可用,降级静默
|
||||||
|
|
||||||
|
### 三路数据合并规则
|
||||||
|
优先级:行业领涨 > 同花顺技术榜 > 东方财富热榜
|
||||||
|
同只股票不重复处理,最多15只/轮。
|
||||||
|
行业领涨股保证能被扫描到,不会被技术榜单的股票挤掉。
|
||||||
|
|
||||||
### 新闻来源
|
### 新闻来源
|
||||||
- 东方财富个股新闻API(akshare.stock_news_em)
|
- 东方财富个股新闻API(akshare.stock_news_em)
|
||||||
|
|||||||
+56
-3
@@ -45,6 +45,10 @@ BEARISH_BOARDS = [
|
|||||||
ALL_BOARDS = BULLISH_BOARDS + BEARISH_BOARDS
|
ALL_BOARDS = BULLISH_BOARDS + BEARISH_BOARDS
|
||||||
BULLISH_COUNT = len(BULLISH_BOARDS)
|
BULLISH_COUNT = len(BULLISH_BOARDS)
|
||||||
|
|
||||||
|
# 行业领涨股扫描(不轮换,每轮都跑)
|
||||||
|
# 从 market.json 读热门行业领涨股
|
||||||
|
SECTOR_HOT_THRESHOLD = 2.5 # 板块涨幅>2.5%时捞它的领涨股
|
||||||
|
|
||||||
|
|
||||||
def clean_proxy():
|
def clean_proxy():
|
||||||
for k in ['http_proxy','https_proxy','HTTP_PROXY','HTTPS_PROXY']:
|
for k in ['http_proxy','https_proxy','HTTP_PROXY','HTTPS_PROXY']:
|
||||||
@@ -112,6 +116,53 @@ def fetch_rotating_board():
|
|||||||
return [], is_bullish
|
return [], is_bullish
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_sector_leaders():
|
||||||
|
"""从 market.json 读热门行业领涨股"""
|
||||||
|
mkt_path = DATA_DIR / "market.json"
|
||||||
|
if not mkt_path.exists():
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
mkt = json.loads(mkt_path.read_text())
|
||||||
|
sectors = mkt.get("sectors", [])
|
||||||
|
|
||||||
|
# 代码→名称映射(优先用本地缓存,避免每次跑都调akshare)
|
||||||
|
cache_path = DATA_DIR / "stock_name_code_cache.json"
|
||||||
|
name_to_code = {}
|
||||||
|
if cache_path.exists():
|
||||||
|
name_to_code = json.loads(cache_path.read_text())
|
||||||
|
if not name_to_code:
|
||||||
|
try:
|
||||||
|
import akshare as ak
|
||||||
|
df = ak.stock_info_a_code_name()
|
||||||
|
for _, r in df.iterrows():
|
||||||
|
name_to_code[r["简称"]] = r["代码"]
|
||||||
|
cache_path.write_text(json.dumps(name_to_code, ensure_ascii=False))
|
||||||
|
print(f" 名称代码映射: {len(name_to_code)}只已缓存", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f" 名称代码映射加载失败: {e}", flush=True)
|
||||||
|
|
||||||
|
leaders = []
|
||||||
|
seen = set()
|
||||||
|
for s in sectors:
|
||||||
|
chg = s.get("change", 0) or 0
|
||||||
|
lead_name = s.get("lead_stock", "")
|
||||||
|
if chg < SECTOR_HOT_THRESHOLD or not lead_name or lead_name in seen:
|
||||||
|
continue
|
||||||
|
seen.add(lead_name)
|
||||||
|
code = name_to_code.get(lead_name, "")
|
||||||
|
if not code:
|
||||||
|
continue
|
||||||
|
leaders.append({
|
||||||
|
"code": code,
|
||||||
|
"name": lead_name,
|
||||||
|
"source": f"行业领涨-{s['name']}+{chg:+.1f}%",
|
||||||
|
})
|
||||||
|
return leaders
|
||||||
|
except Exception as e:
|
||||||
|
print(f" 行业领涨获取失败: {e}", flush=True)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_scanned_codes(conn):
|
def get_scanned_codes(conn):
|
||||||
"""取1小时内已扫描过的代码"""
|
"""取1小时内已扫描过的代码"""
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
@@ -192,10 +243,11 @@ def main():
|
|||||||
# 1. 拉板
|
# 1. 拉板
|
||||||
hot = fetch_hot_board()
|
hot = fetch_hot_board()
|
||||||
rotating, is_bullish = fetch_rotating_board()
|
rotating, is_bullish = fetch_rotating_board()
|
||||||
|
leaders = fetch_sector_leaders()
|
||||||
elapsed = time.time() - start_time
|
elapsed = time.time() - start_time
|
||||||
print(f"榜单: 东方财富{len(hot)}只, 同花顺{len(rotating)}只 ({elapsed:.0f}s)", flush=True)
|
print(f"榜单: 东方财富{len(hot)}只, 同花顺{len(rotating)}只, 行业领涨{len(leaders)}只 ({elapsed:.0f}s)", flush=True)
|
||||||
|
|
||||||
if not hot and not rotating:
|
if not hot and not rotating and not leaders:
|
||||||
conn.close()
|
conn.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -210,7 +262,8 @@ def main():
|
|||||||
|
|
||||||
# 2. 合并去重 + 看空榜只保留持仓股
|
# 2. 合并去重 + 看空榜只保留持仓股
|
||||||
all_stocks = {}
|
all_stocks = {}
|
||||||
for s in hot + rotating:
|
# 行业领涨优先(热门板块龙头)
|
||||||
|
for s in (leaders if is_bullish else []) + hot + rotating:
|
||||||
code = s["code"]
|
code = s["code"]
|
||||||
code_stripped = code.lstrip("0")
|
code_stripped = code.lstrip("0")
|
||||||
if not is_bullish:
|
if not is_bullish:
|
||||||
|
|||||||
Reference in New Issue
Block a user