-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.py
executable file
·153 lines (118 loc) · 4.47 KB
/
bot.py
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python3
import datetime
from textwrap import dedent
from typing import cast
import click
from pydantic import BaseSettings
from telegram import Update, Chat
from telegram.ext import Updater, CommandHandler, CallbackContext, JobQueue, Job
from stocks import get_yesterday_trading_prices
from stocks import get_current_trading_prices
from watchfiles import run_process
def fetch_portfolio():
# FIXME Replace this code with fetching data from web service
return {
'MSFT': 20,
'AMZN': 15,
'GOOGL': 10,
'TSLA': 100,
}
class Settings(BaseSettings):
TELEGRAM_BOT_TOKEN: str
class Config:
env_file = '.env'
case_sensitive = True
env_nested_delimiter = '__'
PORTFOLIO = {
'MSFT': 20,
'AMZN': 15,
'GOOGL': 10,
'TSLA': 100,
}
def start(update: Update, context: CallbackContext) -> None:
chat_id = cast(Chat, update.effective_chat).id
update.message.reply_text('Привет! Я твой биржевой помощник!')
# This needed to exclude the situation when
# user presses /start multiple times and gets multiple jobs
job_title = f'yesterday-stocks#{chat_id}'
job_queue = cast(JobQueue, context.job_queue)
if job_title not in {job.name for job in job_queue.jobs()}:
job_queue.run_daily(
yesterday_stocks_job,
time=datetime.time(hour=7),
name=job_title,
context={'chat_id': chat_id},
)
def format_ticker_stats(ticker: str, amount: int, open_price: float, close_price: float) -> str:
diff = close_price - open_price
revenue = diff * amount
if revenue < 0:
result = 'потеряли'
else:
result = 'заработали'
return dedent(f'''
{ticker} ({amount})
открылись по {open_price:,.1f}$
закрылись по {close_price:,.1f}$
выручка с акции: {diff:,.1f}$
учитывая количество, {result} {revenue:,.1f}$
''')
def current_stocks(update: Update, context: CallbackContext) -> None:
msg = 'Ваши фин. показатели на текущий момент:\n\n'
day_revenue = 0.0
for ticker, amount in fetch_portfolio().items():
open_price, close_price = get_current_trading_prices(ticker)
diff = close_price - open_price
revenue = diff * amount
day_revenue += revenue
msg += format_ticker_stats(ticker, amount, open_price, close_price)
msg += dedent(f'''
Итоговая разница за день: {day_revenue:,.1f}$
''')
update.message.reply_text(msg)
def yesterday_stocks_job(context: CallbackContext) -> None:
msg = 'Ваши фин. показатели по итогу прошлого дня:\n\n'
job = cast(Job, context.job)
job_context = cast(CallbackContext, job.context)
job_context = dict(job_context) # type: ignore
chat_id = job_context['chat_id'] # type: ignore
day_revenue = 0.0
for ticker, amount in fetch_portfolio().items():
open_price, close_price = get_yesterday_trading_prices(ticker)
diff = close_price - open_price
revenue = diff * amount
day_revenue += revenue
msg += format_ticker_stats(ticker, amount, open_price, close_price)
msg += dedent(f'''
Итоговая разница за день: {day_revenue:,.1f}$
''')
context.bot.send_message(chat_id=chat_id, text=msg)
def yesterday_stocks(update: Update, context: CallbackContext) -> None:
chat_id = cast(Chat, update.effective_chat).id
job_title = f'yesterday-stocks#{chat_id}'
job_queue = cast(JobQueue, context.job_queue)
job_queue.run_once(
yesterday_stocks_job,
0,
name=job_title,
context={'chat_id': chat_id},
)
def run_bot() -> None:
settings = Settings()
updater = Updater(settings.TELEGRAM_BOT_TOKEN)
dispatcher = updater.dispatcher # type: ignore
dispatcher.add_handler(CommandHandler("start", start))
dispatcher.add_handler(CommandHandler("current_stocks", current_stocks))
dispatcher.add_handler(CommandHandler("yesterday_stocks", yesterday_stocks))
updater.start_polling()
updater.idle()
@click.command()
@click.option('--autoreload', default=False, is_flag=True)
def main(autoreload: bool) -> None:
if autoreload:
print('Autoreload is enabled.')
run_process('.', target=run_bot)
else:
run_bot()
if __name__ == '__main__':
main()