From 9b100f4926f22bf1312da8d8586ddfd657e15343 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Thu, 11 Feb 2021 16:00:49 -0700 Subject: [PATCH] Happy with current coverage close # 46 --- bot.py | 6 +-- functions.py | 119 ++++++++++++++++++++++++++++----------------------- 2 files changed, 67 insertions(+), 58 deletions(-) diff --git a/bot.py b/bot.py index 04cb94c..baa3c22 100644 --- a/bot.py +++ b/bot.py @@ -182,11 +182,9 @@ def dividend(update: Update, context: CallbackContext): if symbols: context.bot.send_chat_action(chat_id=chat_id, action=telegram.ChatAction.TYPING) - - for reply in s.dividend_reply(symbols).items(): - + for symbol in symbols: update.message.reply_text( - text=reply[1], parse_mode=telegram.ParseMode.MARKDOWN + text=s.dividend_reply(symbol), parse_mode=telegram.ParseMode.MARKDOWN ) diff --git a/functions.py b/functions.py index 80a41c5..a65a308 100644 --- a/functions.py +++ b/functions.py @@ -1,6 +1,6 @@ import re from datetime import datetime -from typing import Optional +from typing import Optional, List, Tuple, Dict import pandas as pd import requests as r @@ -130,16 +130,18 @@ _Donations can only be made in a chat directly with @simplestockbot_ usage = r.get( f"https://cloud.iexapis.com/stable/account/metadata?token={self.IEX_TOKEN}" ).json() + try: + if ( + usage["messagesUsed"] >= usage["messageLimit"] - 10000 + and not usage["payAsYouGoEnabled"] + ): + return "Bot may be out of IEX Credits." + else: + return "Bot has available IEX Credits." + except KeyError: + return "**IEX API could not be reached.**" - if ( - usage["messagesUsed"] >= usage["messageLimit"] - 10000 - and not usage["payAsYouGoEnabled"] - ): - return "Bot may be out of IEX Credits." - else: - return "Bot has available IEX Credits" - - def search_symbols(self, search: str) -> list[list[str, str]]: + def search_symbols(self, search: str) -> List[Tuple[str, str]]: """Performs a fuzzy search to find stock symbols closest to a search term. Parameters @@ -149,7 +151,7 @@ _Donations can only be made in a chat directly with @simplestockbot_ Returns ------- - list[tuple[str, str]] + List[tuple[str, str]] A list tuples of every stock sorted in order of how well they match. Each tuple contains: (Symbol, Issue Name). """ @@ -179,7 +181,7 @@ _Donations can only be made in a chat directly with @simplestockbot_ self.searched_symbols[search] = symbol_list return symbol_list - def find_symbols(self, text: str) -> list[str]: + def find_symbols(self, text: str) -> List[str]: """Finds stock tickers starting with a dollar sign in a blob of text and returns them in a list. Only returns each match once. Example: Whats the price of $tsla? @@ -190,13 +192,13 @@ _Donations can only be made in a chat directly with @simplestockbot_ Returns ------- - list[str] + List[str] List of stock symbols as strings without dollar sign. """ return list(set(re.findall(self.SYMBOL_REGEX, text))) - def price_reply(self, symbols: list) -> dict[str, str]: + def price_reply(self, symbols: list) -> Dict[str, str]: """Returns current market price or after hours if its available for a given stock symbol. Parameters @@ -206,8 +208,9 @@ _Donations can only be made in a chat directly with @simplestockbot_ Returns ------- - dict[str, str] - Each symbol passed in is a key with its value being a human readable markdown formatted string of the symbols price and movement. + Dict[str, str] + Each symbol passed in is a key with its value being a human readable + markdown formatted string of the symbols price and movement. """ dataMessages = {} for symbol in symbols: @@ -216,33 +219,45 @@ _Donations can only be made in a chat directly with @simplestockbot_ response = r.get(IEXurl) if response.status_code == 200: IEXData = response.json() + keys = ( + "isUSMarketOpen", + "extendedChangePercent", + "extendedPrice", + "companyName", + "latestPrice", + "changePercent", + ) - try: # Some symbols dont return if the market is open - IEXData["isUSMarketOpen"] - except KeyError: - IEXData["isUSMarketOpen"] = True + if set(keys).issubset(IEXData): - if ( - IEXData["isUSMarketOpen"] - or (IEXData["extendedChangePercent"] is None) - or (IEXData["extendedPrice"] is None) - ): # Check if market is open. - message = f"The current stock price of {IEXData['companyName']} is $**{IEXData['latestPrice']}**" - change = round(IEXData["changePercent"] * 100, 2) + try: # Some symbols dont return if the market is open + IEXData["isUSMarketOpen"] + except KeyError: + IEXData["isUSMarketOpen"] = True + + if ( + IEXData["isUSMarketOpen"] + or (IEXData["extendedChangePercent"] is None) + or (IEXData["extendedPrice"] is None) + ): # Check if market is open. + message = f"The current stock price of {IEXData['companyName']} is $**{IEXData['latestPrice']}**" + change = round(IEXData["changePercent"] * 100, 2) + else: + message = ( + f"{IEXData['companyName']} closed at $**{IEXData['latestPrice']}**," + + f" after hours _(15 minutes delayed)_ the stock price is $**{IEXData['extendedPrice']}**" + ) + change = round(IEXData["extendedChangePercent"] * 100, 2) + + # Determine wording of change text + if change > 0: + message += f", the stock is currently **up {change}%**" + elif change < 0: + message += f", the stock is currently **down {change}%**" + else: + message += ", the stock hasn't shown any movement today." else: - message = ( - f"{IEXData['companyName']} closed at $**{IEXData['latestPrice']}**," - + f" after hours _(15 minutes delayed)_ the stock price is $**{IEXData['extendedPrice']}**" - ) - change = round(IEXData["extendedChangePercent"] * 100, 2) - - # Determine wording of change text - if change > 0: - message += f", the stock is currently **up {change}%**" - elif change < 0: - message += f", the stock is currently **down {change}%**" - else: - message += ", the stock hasn't shown any movement today." + message = f"The symbol: {symbol} encountered and error. This could be due to " else: message = f"The symbol: {symbol} was not found." @@ -251,7 +266,7 @@ _Donations can only be made in a chat directly with @simplestockbot_ return dataMessages - def dividend_reply(self, symbols: list) -> dict[str, str]: + def dividend_reply(self, symbol: str) -> Dict[str, str]: """Returns the most recent, or next dividend date for a stock symbol. Parameters @@ -261,10 +276,9 @@ _Donations can only be made in a chat directly with @simplestockbot_ Returns ------- - dict[str, str] + Dict[str, str] Each symbol passed in is a key with its value being a human readable formatted string of the symbols div dates. """ - divMessages = {} IEXurl = f"https://cloud.iexapis.com/stable/stock/msft/dividends/next?token={self.IEX_TOKEN}" response = r.get(IEXurl) @@ -287,11 +301,8 @@ _Donations can only be made in a chat directly with @simplestockbot_ else: price = f"{IEXData['amount']} {IEXData['currency']}" - # extract date from json - date = response.json() # Pattern IEX uses for dividend date. pattern = "%Y-%m-%d" - divDate = datetime.strptime(date, pattern) declared = datetime.strptime(IEXData["declaredDate"], pattern).strftime( "%A, %B %w" @@ -304,7 +315,7 @@ _Donations can only be made in a chat directly with @simplestockbot_ daysDelta = ( datetime.strptime(IEXData["paymentDate"], pattern) - datetime.now() ).days - print(self.symbol_list) + return ( f"The next dividend for ${self.symbol_list[self.symbol_list['symbol']==symbol.upper()]['description'].item()}" + f" is on {payment} which is in {daysDelta} days." @@ -314,7 +325,7 @@ _Donations can only be made in a chat directly with @simplestockbot_ return f"{symbol} either doesn't exist or pays no dividend." - def news_reply(self, symbols: list) -> dict[str, str]: + def news_reply(self, symbols: list) -> Dict[str, str]: """Gets recent english news on stock symbols. Parameters @@ -351,17 +362,17 @@ _Donations can only be made in a chat directly with @simplestockbot_ return newsMessages - def info_reply(self, symbols: list[str]) -> dict[str, str]: + def info_reply(self, symbols: List[str]) -> Dict[str, str]: """Gets information on stock symbols. Parameters ---------- - symbols : list[str] + symbols : List[str] List of stock symbols. Returns ------- - dict[str, str] + Dict[str, str] Each symbol passed in is a key with its value being a human readable formatted string of the symbols information. """ infoMessages = {} @@ -449,17 +460,17 @@ _Donations can only be made in a chat directly with @simplestockbot_ return pd.DataFrame() - def stat_reply(self, symbols: list[str]) -> dict[str, str]: + def stat_reply(self, symbols: List[str]) -> Dict[str, str]: """Gets key statistics for each symbol in the list Parameters ---------- - symbols : list[str] + symbols : List[str] List of stock symbols Returns ------- - dict[str, str] + Dict[str, str] Each symbol passed in is a key with its value being a human readable formatted string of the symbols statistics. """ infoMessages = {}