87 lines
2.8 KiB
Python
87 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""生成策略评估摘要"""
|
|
from mo_data import read_decisions, read_portfolio
|
|
from mo_models import get_hk_rate
|
|
|
|
dec = read_decisions()
|
|
pf = read_portfolio()
|
|
|
|
holdings = pf.get('holdings', [])
|
|
cash = pf.get('cash', 321271)
|
|
hk_rate = get_hk_rate()
|
|
code_to_h = {h['code']: h for h in holdings}
|
|
|
|
decisions = dec.get('decisions', [])
|
|
hold_entries = [s for s in decisions if s.get('shares', 0) > 0]
|
|
wl_entries = [s for s in decisions if s.get('shares', 0) == 0]
|
|
|
|
hk_total_cny = 0
|
|
a_total = 0
|
|
for h in holdings:
|
|
mv = h['shares'] * h['price']
|
|
if h.get('currency') == 'HKD':
|
|
hk_total_cny += mv * hk_rate
|
|
else:
|
|
a_total += mv
|
|
total_mv = hk_total_cny + a_total
|
|
total_assets = total_mv + cash
|
|
position_pct = total_mv / total_assets * 100
|
|
|
|
weak_count = sum(1 for s in hold_entries if s.get('stock_category') in ('弱势','深套'))
|
|
|
|
print(f'总市值: {total_mv:.0f} CNY (HK${hk_total_cny:.0f} A¥{a_total:.0f})')
|
|
print(f'总资产: {total_assets:.0f} CNY')
|
|
print(f'仓位: {position_pct:.1f}% 现金: {cash:.0f}')
|
|
print(f'持仓: {len(hold_entries)}只 弱势/深套: {weak_count}只 ({weak_count/len(hold_entries)*100:.0f}%)')
|
|
print(f'自选: {len(wl_entries)}只')
|
|
print()
|
|
|
|
print('【持仓详情】')
|
|
for s in hold_entries:
|
|
code = s['code']
|
|
name = s['name']
|
|
shares = s['shares']
|
|
cost = s.get('cost', 0)
|
|
sl = s.get('stop_loss', 0)
|
|
tp = s.get('take_profit', 0)
|
|
cat = s.get('stock_category', '?')
|
|
sig = s.get('timing_signal', '?')
|
|
|
|
h = code_to_h.get(code)
|
|
price = h['price'] if h else 0
|
|
if h and h.get('currency') == 'HKD':
|
|
mv_val = h['shares'] * h['price'] * hk_rate
|
|
else:
|
|
mv_val = h['shares'] * h['price'] if h else 0
|
|
pl_pct = (price - cost) / cost * 100 if cost else 0
|
|
pct = mv_val / total_assets * 100
|
|
sl_dist = (price / sl - 1) * 100 if sl > 0 else 0
|
|
tp_dist = (tp / price - 1) * 100 if tp > 0 else 0
|
|
|
|
flags = []
|
|
if sl_dist < 5:
|
|
if pl_pct > 5:
|
|
flags.append('利润保护')
|
|
else:
|
|
flags.append(f'⚠️近止损({sl_dist:.0f}%)')
|
|
if tp_dist < 5 and tp_dist > 0:
|
|
flags.append('近止盈')
|
|
if cat in ('弱势','深套'):
|
|
flags.append(f'[{cat}]')
|
|
|
|
flag_str = ' '.join(flags) if flags else ''
|
|
print(f' {code} {name:10s} ¥{price:>7.2f} 浮{pl_pct:+.1f}% 仓{pct:.1f}% 损{sl}({sl_dist:.0f}%) 盈{tp}({tp_dist:.0f}%) {flag_str}')
|
|
|
|
print()
|
|
print('【自选关注】')
|
|
for s in wl_entries:
|
|
code = s['code']
|
|
name = s['name']
|
|
el = s.get('entry_low', 0)
|
|
eh = s.get('entry_high', 0)
|
|
sl = s.get('stop_loss', 0)
|
|
price = s.get('price', 0)
|
|
sig = s.get('timing_signal', '?')
|
|
in_zone = '✅在买入区' if el and eh and price and el <= price <= eh else ''
|
|
print(f' {code} {name:10s} ¥{price:>7.2f} 买区{el}~{eh} 损{sl} 信号{sig} {in_zone}')
|