feat etf
This commit is contained in:
91
labs/analysis/etf/decide_list.py
Normal file
91
labs/analysis/etf/decide_list.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""名单决策依据:
|
||||
1) 逐标的对组合的净贡献(了结 + 未实现)
|
||||
2) 规模/成交额(流动性)是否够网格用
|
||||
3) 是否还有更贴题的品类 ETF(如真正的"存储")
|
||||
4) 剔除弱标的后的组合结果对照
|
||||
|
||||
用法: py -3.14 -B labs/analysis/etf/decide_list.py
|
||||
"""
|
||||
|
||||
import sys
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(HERE))
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
from backtest import SYMBOLS, SYMBOL_PARAMS, analyze, fetch_daily, simulate # noqa: E402
|
||||
from screen_etf import code_of, fetch_all, size_yi, turnover_yi # noqa: E402
|
||||
|
||||
CASH = 600_000.0
|
||||
data = {code: fetch_daily(code) for code in SYMBOLS}
|
||||
|
||||
# ---------- 1) 逐标的贡献 ----------
|
||||
result = simulate(data, start_cash=CASH, fill_mode="touch")
|
||||
print("== 逐标的净贡献(了结 + 未实现,按市价;账户 60 万)==")
|
||||
print(f"{'代码':11} {'了结净额':>10} {'未了结股数':>9} {'未实现':>9} {'净额':>10} {'买入名义':>10}")
|
||||
contrib = {}
|
||||
for code in SYMBOLS:
|
||||
book = result["books"][code]
|
||||
fills = [f for f in result["fills"] if f.code == code]
|
||||
closed = sum((f.price * f.volume if f.side == "SELL" else -f.price * f.volume) - f.fee
|
||||
for f in fills)
|
||||
cost = book.avg_cost * book.volume
|
||||
close = data[code][-1]["close"]
|
||||
unreal = close * book.volume - cost if book.volume else 0.0
|
||||
contrib[code] = closed + unreal
|
||||
print(f"{code:11} {closed:10,.0f} {book.volume:9} {unreal:9,.0f} {closed + unreal:10,.0f} "
|
||||
f"{sum(f.price * f.volume for f in fills if f.side == 'BUY'):10,.0f}")
|
||||
|
||||
# ---------- 2) 规模/成交额 ----------
|
||||
rows = fetch_all()
|
||||
info = {code_of(r): r for r in rows}
|
||||
print()
|
||||
print("== 流动性与规模 ==")
|
||||
print(f"{'代码':11} {'规模(亿)':>9} {'成交额(亿)':>10} {'名称':26} 评价")
|
||||
for code in SYMBOLS:
|
||||
row = info.get(code)
|
||||
if row is None:
|
||||
print(f"{code:11} {'?':>9} {'?':>10} 未在东财列表找到")
|
||||
continue
|
||||
size, turn = size_yi(row), turnover_yi(row)
|
||||
if size < 10 or turn < 0.3:
|
||||
verdict = "⚠️ 规模/成交偏小,网格成交与冲击成本风险高"
|
||||
elif size < 30 or turn < 1.0:
|
||||
verdict = "△ 中等,可接受但优先级靠后"
|
||||
else:
|
||||
verdict = "✓ 流动性充足"
|
||||
print(f"{code:11} {size:9.2f} {turn:10.3f} {str(row.get('f14')):26} {verdict}")
|
||||
|
||||
# ---------- 3) 剔除弱标的后的对照 ----------
|
||||
weak = [c for c in SYMBOLS
|
||||
if c in info and (size_yi(info[c]) < 10 or turnover_yi(info[c]) < 0.3)]
|
||||
if weak:
|
||||
print()
|
||||
print(f"== 剔除弱流动性标的 {weak} 后的组合 ==")
|
||||
kept = {c: data[c] for c in SYMBOLS if c not in weak}
|
||||
for label, universe in (("全部 16 只", data), (f"剔除 {len(weak)} 只 → {len(kept)} 只", kept)):
|
||||
res = simulate(universe, start_cash=CASH, fill_mode="touch")
|
||||
st = analyze(res)
|
||||
print(f" {label:24} 权益变动 {st['final_equity'] - CASH:10,.2f} "
|
||||
f"收益率 {st['return_pct']:6.2f}% 回撤 {st['max_dd_pct']:5.2f}% "
|
||||
f"底仓 {sum(1 for f in res['fills'] if f.kind == 'base'):4} "
|
||||
f"补仓 {sum(1 for f in res['fills'] if f.kind == 'add'):3} "
|
||||
f"佣金 {st['fees']:8,.2f}")
|
||||
else:
|
||||
print()
|
||||
print("== 没有规模/成交额低于阈值的标的 ==")
|
||||
|
||||
# ---------- 4) 更贴题的品类 ETF(存储) ----------
|
||||
print()
|
||||
print("== 存储/内存相关 ETF 全量搜索 ==")
|
||||
hits = [r for r in rows if any(k in str(r.get("f14") or "") for k in ("存储", "内存", "存储器"))]
|
||||
hits.sort(key=lambda r: -size_yi(r))
|
||||
for row in hits[:10]:
|
||||
print(f" {code_of(row):11} {str(row.get('f14')):26} 规模={size_yi(row):8.2f}亿 "
|
||||
f"成交额={turnover_yi(row):7.3f}亿")
|
||||
print(f" 共 {len(hits)} 只名称含存储/内存的 ETF")
|
||||
Reference in New Issue
Block a user