update
This commit is contained in:
@@ -10,7 +10,7 @@ GRID_HIGH = 11 # 网格上限
|
||||
GRID_STEP = 1 # 网格间距(整数格)
|
||||
|
||||
# ---- 候选股过滤 ----
|
||||
FILTER_MIN_CLOSE = 8 # 最低收盘价
|
||||
FILTER_MIN_CLOSE = 5 # 最低收盘价(覆盖网格策略持仓股)
|
||||
FILTER_MAX_CLOSE = 13 # 最高收盘价
|
||||
REQUIRE_DAYS = 120 # 最少交易日数
|
||||
|
||||
|
||||
@@ -128,6 +128,18 @@ def load_candidates(trade_date: date) -> DataContext:
|
||||
PrintLog(LogLevel.INFO,
|
||||
f'[validator] 候选: {len(candidates)} 通过, {len(excluded)} 排除')
|
||||
|
||||
# 3.5 补充:强制加入网格持仓股(不受价格过滤限制)
|
||||
from core.sfgrid.model import SFGridTradeTarget
|
||||
pos_rows = list(SFGridTradeTarget
|
||||
.select(SFGridTradeTarget.stock_code)
|
||||
.where(SFGridTradeTarget.enabled == True)
|
||||
.dicts())
|
||||
pos_codes = [r['stock_code'].split('.')[0] for r in pos_rows]
|
||||
forced = [c for c in pos_codes if c not in candidates and c not in excluded]
|
||||
if forced:
|
||||
PrintLog(LogLevel.INFO, f'[validator] 强制加入网格持仓股: {forced}')
|
||||
candidates.extend(forced)
|
||||
|
||||
# 4. 裁剪K线到只含候选股 (保留最近180日)
|
||||
kline_df = kline_df[kline_df['stock_code'].isin(candidates)].copy()
|
||||
cut_date = trade_date - timedelta(days=365)
|
||||
|
||||
+37
-2
@@ -302,6 +302,22 @@ class _DataStore:
|
||||
elif ot == 24 and '空' not in tags: tags.append('空')
|
||||
return tags
|
||||
|
||||
def pool_action_tags(self, stock_code: str) -> list[str]:
|
||||
"""某标的的股票池待执行标记(eliminate/liquidate)"""
|
||||
plain = _plain(stock_code)
|
||||
from core.scoring.models import PendingPoolAction
|
||||
rows = list(PendingPoolAction
|
||||
.select(PendingPoolAction.action_type)
|
||||
.where(PendingPoolAction.stock_code == plain)
|
||||
.dicts())
|
||||
tags = []
|
||||
for r in rows:
|
||||
if r['action_type'] == 'eliminate' and '淘汰' not in tags:
|
||||
tags.append('淘汰')
|
||||
elif r['action_type'] == 'liquidate' and '沉寂' not in tags:
|
||||
tags.append('沉寂')
|
||||
return tags
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# GridPanel — 网格策略持仓表格
|
||||
@@ -326,7 +342,7 @@ class _GridPanel:
|
||||
|
||||
def _rebuild(self):
|
||||
# (width, expand): 0=固定宽, >0=弹性比重; 新增排名列(50px)
|
||||
_C = [(35, 0), (0, 2), (70, 1), (0, 2), (50, 1), (55, 1), (50, 0), (60, 1), (0, 1)]
|
||||
_C = [(35, 0), (0, 2), (70, 1), (80, 1), (50, 1), (55, 1), (50, 0), (60, 1), (0, 1)]
|
||||
H = ["ID", "股票", "市场价", "网格基准", "持仓", "成本", "排名", "状态", "操作"]
|
||||
header = []
|
||||
for h, (w, e) in zip(H, _C):
|
||||
@@ -414,7 +430,26 @@ class _GridPanel:
|
||||
on_click=lambda e, tt=t: self._dialogs.confirm_remove(tt)),
|
||||
]
|
||||
|
||||
cells_text = [str(tid), f'{t.stock_code} {t.stock_name}',
|
||||
# 股票列:名称 + 标记标签
|
||||
pool_tags = self._data.pool_action_tags(t.stock_code)
|
||||
tag_chips = []
|
||||
if pool_tags:
|
||||
# 有淘汰/沉寂时,显示操作标签,不显示默认标签
|
||||
for tag in pool_tags:
|
||||
color = '#E67E22' if tag == '淘汰' else '#E74C3C'
|
||||
tag_chips.append(ft.Container(
|
||||
_text(tag, color='white', bold=True, size=10),
|
||||
bgcolor=color, border_radius=4, padding=ft.Padding(2, 1, 2, 1),
|
||||
))
|
||||
else:
|
||||
# 无操作标签时,显示默认"网格"标签
|
||||
tag_chips.append(ft.Container(
|
||||
_text('网格', color='white', bold=True, size=10),
|
||||
bgcolor='#2E7D32', border_radius=4, padding=ft.Padding(2, 1, 2, 1),
|
||||
))
|
||||
name_cell = ft.Row([_text(f'{t.stock_code} {t.stock_name}')] + tag_chips, spacing=4)
|
||||
|
||||
cells_text = [str(tid), name_cell,
|
||||
f'{mp:.3f}', gcell,
|
||||
str(t.current_position),
|
||||
f'{self._data.avgPrices.get(tid, 0):.3f}',
|
||||
|
||||
Reference in New Issue
Block a user