-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathportfolio_report.py
More file actions
126 lines (107 loc) · 3.95 KB
/
portfolio_report.py
File metadata and controls
126 lines (107 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# ===============================
# Автоматизація звітності портфеля з Telegram
# ===============================
import pandas as pd
import yfinance as yf
from datetime import datetime, timedelta
import plotly.express as px
import requests
import os
# ===============================
# Налаштування портфеля
# ===============================
holdings = {
'AAPL': 16,
'TSLA': 15,
'TEAM': 7,
}
tickers = list(holdings.keys())
# ===============================
# Налаштування Telegram бота через GitHub Secrets
# ===============================
BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
if not BOT_TOKEN or not CHAT_ID:
raise ValueError("Telegram credentials are not set in environment variables")
def send_telegram_message(message: str):
"""
Надсилає повідомлення в Telegram
"""
url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
payload = {
"chat_id": CHAT_ID,
"text": message,
"parse_mode": "HTML"
}
response = requests.post(url, data=payload)
if not response.ok:
print("❌ Помилка надсилання Telegram повідомлення:", response.text)
# ===============================
# Завантаження даних за останні 7 днів
# ===============================
end_date = datetime.today()
start_date = end_date - timedelta(days=7)
data = yf.download(
tickers,
start=start_date.strftime('%Y-%m-%d'),
end=end_date.strftime('%Y-%m-%d'),
auto_adjust=True # скориговані ціни
)
if data.empty or 'Close' not in data.columns:
raise ValueError("Дані не були завантажені. Перевірте тикери або діапазон дат.")
# ===============================
# Обробка даних
# ===============================
close_prices = data['Close'].reset_index()
# Перетворюємо у long формат для графіка
close_long = pd.melt(
close_prices,
id_vars='Date',
value_vars=tickers,
var_name='Ticker',
value_name='Close'
)
# Вартість кожної позиції
close_long['Position_Value'] = close_long['Close'] * close_long['Ticker'].map(holdings)
# Загальна вартість портфеля по датах
total_value = close_long.groupby('Date')['Position_Value'].sum().reset_index()
total_value.rename(columns={'Position_Value': 'Total_Value'}, inplace=True)
# Додаємо Total Value у long DataFrame для графіка
total_long = total_value.copy()
total_long['Ticker'] = 'Total Value'
total_long.rename(columns={'Total_Value': 'Close'}, inplace=True)
plot_df = pd.concat([close_long[['Date','Ticker','Close']], total_long], ignore_index=True)
# ===============================
# Побудова графіка
# ===============================
fig = px.line(
plot_df,
x='Date',
y='Close',
color='Ticker',
title="Динаміка вартості портфеля та акцій"
)
fig.update_layout(
yaxis_title="Вартість ($)",
xaxis_title="Дата"
)
fig.write_html("portfolio_plot.html")
# ===============================
# Розрахунок відсоткової зміни Total Value
# ===============================
if len(total_value) >= 2:
today_val = total_value['Total_Value'].iloc[-1]
prev_val = total_value['Total_Value'].iloc[-2]
change_pct = (today_val - prev_val) / prev_val * 100
else:
today_val = total_value['Total_Value'].iloc[-1]
change_pct = 0
# ===============================
# Надсилаємо повідомлення у Telegram
# ===============================
message = f"📊 Total Value: ${today_val:,.2f} ({change_pct:+.3f}%)"
send_telegram_message(message)
# ===============================
# Зберігаємо CSV звіт
# ===============================
total_value.to_csv("portfolio_report.csv", index=False)