Files
MoFin/scripts/process_trade.py
T

149 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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
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
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(替代 json.dump
pf["updated_at"] = now
try:
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 as e:
print(f" [DB写入失败] {e}", file=sys.stderr)
# [migrated to DB] — JSON cold backup removed
# 重算总资产
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()