69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""每30分钟扫描所有持仓的分支状态,发现可操作的分支就推"""
|
|
import sys, json, os
|
|
sys.path.insert(0, '/home/hmo/MoFin')
|
|
sys.path.insert(0, '/home/hmo/web-dashboard')
|
|
from strategy_tree import detect_scenario
|
|
|
|
DEC_PATH = '/home/hmo/web-dashboard/data/decisions.json'
|
|
PF_PATH = '/home/hmo/web-dashboard/data/portfolio.json'
|
|
XMPP_BRIDGE = "http://127.0.0.1:5805/"
|
|
XMPP_USER = "hmo@yoin.fun"
|
|
|
|
def push(msg):
|
|
try:
|
|
from urllib.request import Request, urlopen
|
|
payload = json.dumps({"to": XMPP_USER, "body": msg, "type": "chat"}).encode()
|
|
req = Request(XMPP_BRIDGE, data=payload, headers={"Content-Type": "application/json"})
|
|
urlopen(req, timeout=5)
|
|
except Exception:
|
|
pass
|
|
|
|
def main():
|
|
scenario = detect_scenario()
|
|
if not scenario.get('id'):
|
|
return 0 # SILENT
|
|
|
|
alives = []
|
|
dec = json.load(open(DEC_PATH))
|
|
pf = json.load(open(PF_PATH))
|
|
pf_codes = {h['code'] for h in pf.get('holdings', [])}
|
|
|
|
for e in dec.get('decisions', []):
|
|
code = e.get('code', '')
|
|
tree = e.get('strategy_tree', {})
|
|
if not tree or not tree.get('branches'):
|
|
continue
|
|
branches = tree['branches']
|
|
price = e.get('price', 0)
|
|
shares = e.get('shares', 0)
|
|
cost = e.get('cost', 0)
|
|
if price <= 0:
|
|
continue
|
|
# 用 strategy_tree 评估
|
|
try:
|
|
from strategy_tree import evaluate_branches
|
|
results = evaluate_branches(code, scenario['id'], price, shares, cost)
|
|
for r in results:
|
|
if r.get('applicable') and r.get('action_type') != 'hold':
|
|
is_held = code in pf_codes
|
|
label = '持仓' if is_held else '自选'
|
|
alives.append(f" {label} {r.get('action_type','?')} {code}@{price} | 情景{scenario.get('label','')}→{r.get('branch_id','').split('_')[-1]}| {r.get('rationale','')[:30]}")
|
|
break
|
|
except Exception:
|
|
pass
|
|
|
|
if not alives:
|
|
return 0 # SILENT
|
|
|
|
# 只推单一情景行 + 操作列表
|
|
out_lines = [f"【知微】分支扫描 | {scenario.get('label','')}({scenario.get('id','')})"]
|
|
out_lines.extend(alives)
|
|
msg = '\n'.join(out_lines)
|
|
print(msg)
|
|
push(msg)
|
|
return 1
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|