TFinance
/
main.py
203 строки · 9.9 Кб
1# ----------------------------------------- Основной файл приложения ----------------------------------------- #
2# --------------- Импорт необходимых библиотек, функций, классов --------------- #
3# Встроенные библиотеки.
4import logging5import os6import warnings7
8# Для работы со временем.
9import datetime10import pytz11
12# Работа с telegram-bot-api.
13from telegram.ext import Updater, CommandHandler, ConversationHandler, CallbackQueryHandler14
15# Работа с акциями (загрузка, вывод, проверка, игра, визуализация, рассылка).
16from blast import notify_assignees, daily17from functions import create_user18from graphics.visualize import do_stock_image, pdr19from stock import check_stock, load_stocks, get_all_stocks20from database import Database21from game import game_menu, higher_game, lower_game, game_results # ORM (БД с данными о пользователях).22
23# Импортируем TOKEN из безопасного места
24from safety_key import TOKEN25
26# Запускаем логирование
27if not os.path.exists(f'{os.getcwd()}/logs'):28os.mkdir(f'{os.getcwd()}/logs')29logging.basicConfig(30format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.WARNING,31filename=f"{os.getcwd()}/logs/tfinance_main.log")32logger = logging.getLogger(__name__)33
34# Отключаем предупреждения пользователей библиотек
35warnings.simplefilter("ignore")36
37
38# Отправка всех акций из заданного диапазона (start, end).
39def send_stocks(update, start, end, templates):40msg = ''41for i in range(start, end):42msg += templates['stocks'][i] + ', '43update.message.reply_text(msg)44
45
46# Получение списка необходимых акций по команде /stocks [args]. Обработчик команды /stocks.
47def get_list_stocks(update, context):48try:49templates = load_stocks('stocks.json') # Загружаем список всех акций50
51# Проверка на наличие аргументов52if context.args[0] == 'all':53# Большим сообщением все сразу не отправится, поэтому разделяем на 3 поменьше.54send_stocks(update, 0, 700, templates)55send_stocks(update, 700, 1400, templates)56send_stocks(update, 1400, 2100, templates)57elif context.args[0].isdigit(): # Если аргумент - число, отсылаем первые n акций.58numb = int(context.args[0])59if numb > 700:60while numb > 700:61numb = 70062send_stocks(update, 0, numb, templates)63numb = int(context.args[0]) - 70064send_stocks(update, 0, numb, templates)65else: # Если аргумент - строка, выводим все акции на первую букву строки.66message = []67for el in templates['stocks']:68if el[0].lower() == context.args[0].lower()[0]:69message.append(el)70update.message.reply_text(', '.join(message))71except (IndexError, ValueError):72update.message.reply_text("Неверный способ ввода. /help")73
74
75# Обработчик команды /stock [stock_index]. Визуализирует график и отправляет его в прямом порядке.
76def get_stock_image(update, context):77try:78if context.args[0]:79update.message.reply_photo(do_stock_image(context.args[0]))80else:81raise ValueError82except (IndexError, ValueError):83update.message.reply_text("Неверный способ ввода. /stock [индекс акции]. Например: /stock AAPL")84except pdr._utils.RemoteDataError:85update.message.reply_text("Такой акции не было найдено в данных Yahoo Finance.")86
87
88# Обработчик команды /start. Добавляет пользователя в БД, тем самым открывая ему доступ к командам.
89def start(update, _):90user = create_user(update)91db.add_user(user)92update.message.reply_text(f"Привет, {user.first_name}! Теперь доступ к командам открыт.")93
94
95# Обработчик команды /help.
96def help(update, _):97update.message.reply_text(""" /stocks [количество акций] Например: /stocks 100 - посмотреть первые 100 акций98/stocks all - посмотреть все акции на бирже
99/stocks [буква алфавита] Например: /stocks A - посмотреть все акции,название которых начинается с 'A'
100/follow [stock_name] - добавить акцию в избранное
101/unfollow [stock_name] - удалить акцию из избранного
102/favourites - посмотреть список избранных акций
103/daily - установить ежедневную рассылку избранных акций
104/stats - посмотреть собственную статистику
105/game [stock_name] - начать игру с прогнозом выбранной акции""")106
107
108# Обработчик команды /favourites. Отправляет список любимых акций.
109def favourites(update, _):110user = create_user(update)111stocks = db.get_favourites_stocks(user)112if stocks and stocks[0]:113update.message.reply_text(', '.join(stocks[0].split()))114else:115update.message.reply_text('У вас нет избранных акций')116
117
118# Обработчик команды /follow. Возможность подписываться на другие акции.
119def follow(update, context):120user = create_user(update)121if context.args and context.args[0]:122context.args[0] = context.args[0].upper()123if db.check_favourites_stocks(user, context.args[0]):124update.message.reply_text('Акция уже в избранном')125else:126if check_stock(context.args[0]):127db.add_favourites_stocks(user, context.args[0])128update.message.reply_text('Акция добавлена в избранное')129else:130update.message.reply_text('Акция не найдена')131else:132update.message.reply_text('Неверный способ ввода. /follow [индекс акции]. Например: /follow AAPL')133
134
135# Обработчик команды /unfollow. Возможность отписки от акций.
136def unfollow(update, context):137user = create_user(update)138if context.args and context.args[0]:139context.args[0] = context.args[0].upper()140if not db.check_favourites_stocks(user, context.args[0]):141update.message.reply_text('Акции нет в избранном')142else:143db.remove_favourites_stock(user, context.args[0])144update.message.reply_text('Акция удалена из избранного')145else:146update.message.reply_text('Неверный способ ввода. /unfollow [индекс акции].')147
148
149# Обработчик команды /stats. Вывод статистики пользователя из БД.
150def stats(update, _):151user = create_user(update)152data = db.read_info(user)153try:154update.message.reply_text(f'UserName: {data[0]}\nИзбранные акции:'155f' {", ".join(data[1].split()) if data[1] else None}'156f'\nОчки, заработанные в игре: {data[2]}')157except TypeError:158update.message.reply_text('Вас нет в бд, запустите команду /start чтобы исправить ошибку')159
160
161# Основной цикл, активирующийся при запуске.
162def main():163# Получение и сохранение списка всех акций в stocks.json.164try:165get_all_stocks()166except Exception as e:167logging.error(e)168
169# Создаём объект updater.170updater = Updater(TOKEN)171dispatcher = updater.dispatcher172job_queue = updater.job_queue173
174# Ежедневные задачи.175job_queue.run_daily(notify_assignees, datetime.time(hour=8, tzinfo=pytz.timezone('Europe/Moscow')))176job_queue.run_daily(game_results, datetime.time(hour=3, tzinfo=pytz.timezone('Europe/Moscow')))177
178# ConversationHandler для игры.179game_handler = ConversationHandler(entry_points=[CommandHandler("game", game_menu)],180states={1: [CallbackQueryHandler(higher_game, pattern=f"^1$"),181CallbackQueryHandler(lower_game, pattern=f"^2$")]},182fallbacks=[CommandHandler("game", game_menu)])183dispatcher.add_handler(game_handler)184
185# Регистрируем обработчик команд.186dispatcher.add_handler(CommandHandler("daily", daily))187dispatcher.add_handler(CommandHandler("start", start))188dispatcher.add_handler(CommandHandler("help", help))189dispatcher.add_handler(CommandHandler("favourites", favourites))190dispatcher.add_handler(CommandHandler("follow", follow))191dispatcher.add_handler(CommandHandler("unfollow", unfollow))192dispatcher.add_handler(CommandHandler("stock", get_stock_image))193dispatcher.add_handler(CommandHandler("stocks", get_list_stocks))194dispatcher.add_handler(CommandHandler("stats", stats))195
196# Обработка сообщений.197updater.start_polling()198updater.idle()199
200
201if __name__ == '__main__':202db: Database = Database('data.db')203main()204