#!/usr/bin/env python3 """process_trade.py — 处理交易截图,更新 portfolio.json Dad 发交易截图后,填入以下信息运行此脚本: python3 process_trade.py --action buy --code 600563 --shares 100 --price 189.20 它会: 1. 更新 holdings(加/减股数,归零则移除) 2. 更新 cash(买入减现金,卖出加现金) 3. 同步更新 decisions.json 的 shares 字段 4. 记录 changelog 用法: python3 process_trade.py --action sell --code 600563 --shares 100 --price 189.20 python3 process_trade.py --action buy --code 300308 --shares 50 --price 1230.00 """ import json, sys, os from datetime import datetime from mo_data import read_portfolio, read_decisions, read_watchlist PORTFOLIO_PATH = "/home/hmo/web-dashboard/data/portfolio.json" DECISIONS_PATH = "/home/hmo/web-dashboard/data/decisions.json" def parse_args(): args = {} for i, a in enumerate(sys.argv[1:]): if a.startswith("--"): key = a.lstrip("-") val = sys.argv[i+2] if i+2 < len(sys.argv) and not sys.argv[i+2].startswith("--") else None args[key] = val return args def main(): args = parse_args() action = args.get("action", "") code = args.get("code", "") shares = int(float(args.get("shares", 0))) price = float(args.get("price", 0)) name = args.get("name", "") if not action or not code or not shares or not price: print("用法: python3 process_trade.py --action sell --code 600563 --shares 100 --price 189.20") sys.exit(1) now = datetime.now().strftime("%Y-%m-%d %H:%M") cost = shares * price # 读数据 pf = mo_data.read_portfolio() dec = mo_data.read_decisions() if action == "sell": # 找持仓 found = None for h in pf["holdings"]: if h["code"] == code: found = h break if not found: print(f"❌ 错误: 代码 {code} 未在持仓中找到") sys.exit(1) old_shares = found.get("shares", 0) if old_shares < shares: print(f"❌ 错误: 持仓只有 {old_shares} 股,不够卖 {shares} 股") sys.exit(1) # 减股数 found["shares"] = old_shares - shares found["updated_at"] = now # 归零则移除 if found["shares"] <= 0: pf["holdings"] = [h for h in pf["holdings"] if h["code"] != code] print(f" 已全部清仓,从持仓移除") # 加现金 old_cash = pf.get("cash", 0) or 0 pf["cash"] = round(old_cash + cost, 2) print(f" ✅ 卖出 {name}({code}) {shares}股 @{price} = {cost:.2f}") print(f" 现金: {old_cash} → {pf['cash']}") elif action == "buy": # 找是否已有该股 found = None for h in pf["holdings"]: if h["code"] == code: found = h break if found: # 加权平均成本 old_shares = found.get("shares", 0) or 0 old_cost = found.get("cost", 0) or 0 total_cost = old_cost * old_shares + cost new_shares = old_shares + shares new_avg_cost = round(total_cost / new_shares, 2) if new_shares > 0 else price found["shares"] = new_shares found["cost"] = new_avg_cost found["updated_at"] = now else: pf["holdings"].append({ "code": code, "name": name, "shares": shares, "cost": price, "price": price, "updated_at": now }) # 减现金 old_cash = pf.get("cash", 0) or 0 pf["cash"] = round(old_cash - cost, 2) print(f" ✅ 买入 {name}({code}) {shares}股 @{price} = {cost:.2f}") print(f" 现金: {old_cash} → {pf['cash']}") # 同步 decisions.json 的 shares for d in dec.get("decisions", []): if d["code"] == code: old_dec_shares = d.get("shares", 0) or 0 d["shares"] = (d.get("shares", 0) or 0) + (shares if action == "buy" else -shares) if d["shares"] <= 0 and action == "sell": d["shares"] = 0 d["type"] = "自选策略" d.setdefault("changelog", []).append({ "time": now, "event": action, "shares": shares, "price": price, "total": cost }) break # 写入 — DB 优先 pf["updated_at"] = now try: sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mofin_db import get_conn, write_holdings_batch, write_portfolio_summary, write_holding_strategy conn = get_conn() write_holdings_batch(conn, pf.get('holdings', [])) write_portfolio_summary(conn, pf) for d in dec.get('decisions', []): write_holding_strategy(conn, d.get('code', ''), d.get('name', ''), d) conn.close() except Exception: pass json.dump(pf, open(PORTFOLIO_PATH, "w"), indent=2, ensure_ascii=False) json.dump(dec, open(DECISIONS_PATH, "w"), indent=2, ensure_ascii=False) # 重算总资产 total_mv = sum((h.get("shares",0) or 0) * (h.get("price",0) or 0) for h in pf["holdings"]) total = round(total_mv + (pf.get("cash",0) or 0), 2) print(f"\n📊 持仓市值: {total_mv:.2f}") print(f"📊 现金: {pf.get('cash',0):.2f}") print(f"📊 总资产: {total:.2f}") print(f"📊 持仓 {len(pf['holdings'])} 只") if __name__ == "__main__": main()