99 lines
3.5 KiB
Python
Executable File
99 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
从 Notion 获取股票持仓数据
|
|
"""
|
|
|
|
import requests
|
|
|
|
# Notion 配置
|
|
NOTION_TOKEN = "ntn_c43902219395mirQBetIfYoww1qKCAF14GBRUQeDee29o2"
|
|
DATABASE_ID = "2fb105ad78738175bbbde5b87cf101d9"
|
|
|
|
def get_stock_holdings():
|
|
"""获取股票持仓数据"""
|
|
url = f"https://api.notion.com/v1/databases/{DATABASE_ID}/query"
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {NOTION_TOKEN}",
|
|
"Content-Type": "application/json",
|
|
"Notion-Version": "2022-06-28"
|
|
}
|
|
|
|
try:
|
|
response = requests.post(url, headers=headers, json={}, timeout=30)
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
holdings = []
|
|
|
|
for item in data.get("results", []):
|
|
props = item.get("properties", {})
|
|
|
|
# 解析字段
|
|
code_list = props.get("股票代码", {}).get("title", [])
|
|
code = code_list[0].get("plain_text", "") if code_list else ""
|
|
|
|
name_list = props.get("公司名称", {}).get("rich_text", [])
|
|
name = name_list[0].get("plain_text", "") if name_list else code
|
|
|
|
shares = props.get("持仓数量", {}).get("number", 0) or 0
|
|
current_price = props.get("当前价格", {}).get("number", 0) or 0
|
|
total_cost = props.get("总成本", {}).get("number", 0) or 0
|
|
|
|
if code or shares > 0:
|
|
holdings.append({
|
|
"code": code,
|
|
"name": name,
|
|
"shares": round(shares, 2),
|
|
"current_price": round(current_price, 2) if current_price else 0,
|
|
"total_cost": round(total_cost, 2)
|
|
})
|
|
|
|
return holdings
|
|
else:
|
|
print(f"❌ 获取失败: {response.status_code}")
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"❌ 错误: {e}")
|
|
return None
|
|
|
|
def main():
|
|
print("=" * 90)
|
|
print("📈 一、股票持仓报告 (Notion)")
|
|
print("=" * 90)
|
|
|
|
holdings = get_stock_holdings()
|
|
|
|
if holdings:
|
|
print(f"\n代码 名称 股数 当前价 市值 成本 盈亏")
|
|
print("-" * 90)
|
|
|
|
total_value = 0
|
|
total_cost = 0
|
|
|
|
for h in holdings:
|
|
value = round(h["shares"] * h["current_price"], 2)
|
|
cost = h["total_cost"]
|
|
pnl = round(value - cost, 2)
|
|
pnl_pct = round((pnl / cost * 100), 2) if cost > 0 else 0
|
|
|
|
total_value += value
|
|
total_cost += cost
|
|
|
|
emoji = "🟢" if pnl >= 0 else "🔴"
|
|
print(f"{h['code']:<12} {h['name'][:14]:<14} {h['shares']:<12.2f} ${h['current_price']:<11.2f} ${value:<12.2f} ${cost:<12.2f} {emoji}${pnl:<+12.2f} ({pnl_pct:+.2f}%)")
|
|
|
|
total_pnl = round(total_value - total_cost, 2)
|
|
total_pnl_pct = round((total_pnl / total_cost * 100), 2) if total_cost > 0 else 0
|
|
|
|
print("-" * 90)
|
|
total_emoji = "🟢" if total_pnl >= 0 else "🔴"
|
|
print(f"{'合计':<12} {'':<14} {'':<12} {'':<11} ${total_value:<12.2f} ${total_cost:<12.2f} {total_emoji}${total_pnl:<+12.2f} ({total_pnl_pct:+.2f}%)")
|
|
|
|
else:
|
|
print("\n❌ 无法获取数据")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|