def get_dividend_summary(update, context): ticker = update.message.text user = update.effective_user log().info("User %s entered ticker value %s.", user.first_name, ticker) years = 5 share = Share(ticker) if not share.is_valid: update.message.reply_text( "Invalid ticker. Please use /start to go back to the main menu" ) log().info("User %s entered an invalid ticker value %s.", user.first_name, ticker) return ConversationHandler.END a = share.get_dividend_summary(datetime.datetime.now().year, datetime.datetime.now().year - years) s = '<b>' + share.name + '</b>\n\n' for item in a: s += '<b>' + str(item.year) + ' (' + str( item.total) + ')</b>' + '\n' i = 1 for pay_date, pay_amount in zip(item.pay_date, item.amount): if pay_date == '-': continue s += pd.to_datetime(pay_date).strftime('%d %B') + ': ' + str( pay_amount).replace('SGD', 'SGD ') + '\n' i += 1 s += '\n' update.message.reply_text(s, parse_mode='HTML') return ConversationHandler.END
def __init__(self): self.config = BotConfig(dev=False) log().info('kubera version' + self.config.version + ' started') # db engine DBEngine() # loaded from config self.token = self.config.token # telegram api self.updater = Updater(self.token, use_context=True) # job queue self.job_queue = self.updater.job_queue # Get the dispatcher to register handlers self.dp = self.updater.dispatcher # error handling self.dp.add_error_handler(self.error) # controllers MainMenu(self.dp) DividendSummary(self.dp) UpdateWatchlist(self.dp) About(self.dp) # jobs # 5:15 PM singapore time (after market close) self.job_queue.run_daily(post_market_data, datetime.time(hour=9, minute=15), (0, 1, 2, 3, 4)) # start bot self.updater.start_polling() self.updater.idle()
def post_market_data(context: telegram.ext.CallbackContext): # connect to database log().info('post market data job started') total_users = 0 tickers = [] user_id = 0 db = DBEngine() row = db.custom_command('SELECT DISTINCT id FROM watchlist') # for each id for r in row: s = 'Here is your watchlist update for today:\n\n' user_id = r[0] rowx = db.custom_command('SELECT ticker FROM watchlist WHERE id=' + str(user_id)) # for each ticker that belongs to the user for x in rowx: tickers.append(x[0]) # print(tickers) for ticker in tickers: share = Share(ticker) s += '<b>' + share.name + ' (' + share.ticker + ')</b>\nOpen: ' + str(share.open) + \ '\nLow: ' + str(share.low) + '\nHigh: ' + str(share.high) + \ '\nClose: ' + str(share.price) + '\nPrev Close: ' + \ str(share.previous_close) + '\n50MA: ' + str(share.fifty_day_ma) + \ '\nVolume: ' + str(share.volume)+'\n\n' try: context.bot.send_message(chat_id=user_id, text=s, parse_mode='HTML') total_users += 1 tickers.clear() time.sleep(1) except TelegramError: tickers.clear() continue log().info('market data sent to ' + str(total_users) + ' users')
def get_ticker_shares(update, context): user = update.effective_user log().info("User %s wants to calculate using shares.", user.first_name) query = update.callback_query query.answer() query.edit_message_text( text="Enter ticker symbol (e.g D05)") return DIVIDENDCALCSHARESSTATE
def __end_chat(update, context): user = update.effective_user query = update.callback_query query.answer() log().info("User %s ended the conversation.", user.first_name) query.edit_message_text( 'Chat ended. Use /start to show the menu again.') return ConversationHandler.END
def get_ticker(update, context): user = update.effective_user log().info("User %s pressed the dividend summary button.", user.first_name) query = update.callback_query query.answer() query.edit_message_text(text="Enter ticker symbol (e.g D05)") return GETSUMMARY
def __init__(self, dbname): self.dbname = dbname try: self.conn = sqlite3.connect(dbname) self.cursor = self.conn.cursor() self.create_table('watchlist', 'id integer, ticker text') except sqlite3.Error as e: log().critical('local database initialisation error: "%s"', e) self.conn = None
def calculate_by_shares_second(self, update, context): self.amount = update.message.text user = update.effective_user log().info("User %s entered amount %s", user.first_name, self.amount) share = Share(self.stock_name) dividends = float(share.get_dividend_summary(2019).total.replace('SGD', '')) * int(self.amount) update.message.reply_text("Expected dividends based on last year's data: SGD " + str( dividends) + "\n\n Use /start to go back to main menu") return ConversationHandler.END
def calculate_by_amt_second(self, update, context): self.amount = update.message.text user = update.effective_user log().info("User %s entered amount %s", user.first_name, self.amount) share = Share(self.stock_name) # get 2019 dividends dividends = float(share.get_dividend_summary(2019).total.replace('SGD', '')) # get number of shares from amount tmp = int(int(self.amount) / float(share.price) / 100) no_of_shares = tmp * 100 # calculate returns returns = no_of_shares * dividends update.message.reply_text("Expected dividends based on last year's data: SGD " + str( returns) + "\n\n Use /start to go back to main menu") return ConversationHandler.END
def calculate_by_amt_first(self, update, context): self.stock_name = update.message.text user = update.effective_user log().info("User %s entered ticker value %s", user.first_name, self.stock_name) share = Share(self.stock_name) if not share.is_valid: update.message.reply_text("Invalid ticker. Please use /start to go back to the main menu") return ConversationHandler.END dividend_check = share.get_dividend_summary(2019) if dividend_check is None: update.message.reply_text("Sorry, dividend data is unavailable for this company. Please use /start to go " "back to the main menu") return ConversationHandler.END update.message.reply_text("Enter purchase amount in SGD") return DIVIDENDCALCAMTSTATEFINAL
def show_options(update, context): user = update.effective_user log().info("User %s pressed the dividend calculator button.", user.first_name) # answer query query = update.callback_query query.answer() # new keyboard keyboard = [ [InlineKeyboardButton("🔸 Calculate by amount", callback_data=str(DIVIDENDCALCAMT))], [InlineKeyboardButton("🔸 Calculate by shares", callback_data=str(DIVIDENDCALCSHARES))] ] reply_markup = InlineKeyboardMarkup(keyboard) query.edit_message_text( text="You can calculate expected dividends by entering either the number of shares bought or the amount " "paid for the shares", reply_markup=reply_markup ) return DIVIDENDCALCFIRST
def __yes(self, update, context): # send to users for user in DBEngine().get_items('users', 'id'): try: context.bot.send_message(chat_id=user[0], text=self.__message, parse_mode='HTML') log().info('Message has been sent to %s', user[0]) time.sleep(1) except TelegramError as e: log().warning(e) log().warning('User %s has blocked the bot', user[0]) # DBEngine().delete_item('users', 'id', user[0]) # log().info('User %s has been removed from the database', user[0]) continue # send message update.message.reply_text('Update sent to all users') return ConversationHandler.END
def post_market_analysis(context: telegram.ext.CallbackContext): # connect to database db = DBEngine() # fetch tickers tickers = db.get_items('stocks', 'ticker') # update values for ticker in tickers: share = Share(ticker[0]) # ignore tickers with missing volume information if share.volume == 'unavailable': continue # add volume to database db.update_item('stocks', 'volume', share.volume, 'ticker', ticker[0]) # add company name to database db.update_item('stocks', 'name', share.name, 'ticker', ticker[0]) # add change % to database db.update_item('stocks', 'change', share.change, 'ticker', ticker[0]) time.sleep(1) # get top 5 results from database sorted volume = db.custom_command('select name, volume from stocks order by volume desc limit 5') gainers = db.custom_command('select name, change from stocks order by change desc limit 5') losers = db.custom_command('select name, change from stocks order by change asc limit 5') # STI change sti_change_raw = Share('^STI').percent_changed # append '%' sti_change = str(sti_change_raw) + '%' # prepend '+' if the value is positive if sti_change_raw > 0: sti_change = '+' + sti_change # create string s = '<b>Market Statistics (' + datetime.today().strftime('%d %B %Y') + ')</b>\n\n' s += '<b>STI overall change: </b>' + sti_change + '\n\n' s += '<b>Highest volumes:</b>\n' for idx, row in enumerate(volume): s += '‣ ' + row[0] + ' [' + str(millify(row[1])) + ']\n' s += '\n' s += '<b>Top gainers:</b>\n' for idx, row in enumerate(gainers): s += '‣ ' + row[0] + ' [+' + str(row[1]) + ']' + '\n' s += '\n' s += '<b>Top losers:</b>\n' for idx, row in enumerate(losers): s += '‣ ' + row[0] + ' [' + str(row[1]) + ']' + '\n' total_users = 0 # send message to all users for user in DBEngine().get_items('users', 'id'): try: context.bot.send_message(chat_id=user[0], text=s, parse_mode='HTML') total_users += 1 time.sleep(1) except TelegramError: DBEngine().delete_item('users', 'id', user[0]) continue log().info('market statistics sent to ' + str(total_users) + ' users')
def error(update, context): log().warning('"%s"', context.error)
def get_upcoming_dividends(update, context): user = update.effective_user log().info("User %s pressed the upcoming dividends button.", user.first_name) query = update.callback_query query.answer() # query.edit_message_text(text='Fetching data...') f = open("Logs/upcoming1.pickle", "rb") array_1 = pickle.load(f) f.close() f = open("Logs/upcoming2.pickle", "rb") array_2 = pickle.load(f) f.close() f = open("Logs/upcoming3.pickle", "rb") array_3 = pickle.load(f) f.close() f = open("Logs/upcoming4.pickle", "rb") array_4 = pickle.load(f) f.close() f = open("Logs/upcoming5.pickle", "rb") array_5 = pickle.load(f) f.close() tmp = '' for a in array_1: tmp += '<b>' + a.name.lstrip() + ' (' + a.ticker + ')</b>\n‣ Market Cap: ' + str(a.market_cap) \ + '\n‣ BVPS (MRQ): ' + str(a.book_value) + '\n‣ Price: ' + str(a.price) + \ '\n‣ Amount: ' + str(a.payout_amount) + '\n‣ Yield: ' + a.yield_data + '\n‣ Date: ' + a.payout_date + '\n\n' context.bot.send_message(chat_id=update.callback_query.message.chat.id, text=tmp, parse_mode='html', silent=True) time.sleep(0.5) tmp = '' for b in array_2: tmp += '<b>' + b.name.lstrip() + ' (' + str(b.ticker) + ')</b>\n‣ Market cap: ' + str(b.market_cap) \ + '\n‣ Book value: ' + str(b.book_value) + '\n‣ Price: ' + str(b.price) + \ '\n‣ Amount: ' + str(b.payout_amount) + '\n‣ Yield: ' + b.yield_data + '\n‣ Date: ' + b.payout_date + '\n\n' context.bot.send_message(chat_id=update.callback_query.message.chat.id, text=tmp, parse_mode='html', silent=True) time.sleep(0.5) tmp = '' for c in array_3: tmp += '<b>' + c.name.lstrip() + ' (' + str(c.ticker) + ')</b>\n‣ Market cap: ' + str(c.market_cap) \ + '\n‣ Book value: ' + str(c.book_value) + '\n‣ Price:' + str(c.price) + \ '\n‣ Amount: ' + str(c.payout_amount) + '\n‣ Yield: ' + c.yield_data + '\n‣ Date: ' + c.payout_date + '\n\n' context.bot.send_message(chat_id=update.callback_query.message.chat.id, text=tmp, parse_mode='html', silent=True) time.sleep(0.5) tmp = '' for d in array_4: tmp += '<b>' + d.name.lstrip() + ' (' + str(d.ticker) + ')</b>\n‣ Market cap: ' + str(d.market_cap) \ + '\n‣ Book value: ' + str(d.book_value) + '\n‣ Price: ' + str(d.price) + \ '\n‣ Amount: ' + str(d.payout_amount) + '\n‣ Yield: ' + d.yield_data + '\n‣ Date: ' + d.payout_date + '\n\n' context.bot.send_message(chat_id=update.callback_query.message.chat.id, text=tmp, parse_mode='html', silent=True) time.sleep(0.5) tmp = '' for e in array_5: tmp += '<b>' + e.name.lstrip() + ' (' + str(e.ticker) + ')</b>\n‣ Market cap: ' + str(e.market_cap) \ + '\n‣ Book value: ' + str(e.book_value) + '\n‣ Price: ' + str(e.price) + \ '\n‣ Amount: ' + str(e.payout_amount) + '\n‣ Yield: ' + e.yield_data + '\n‣ Date: ' + e.payout_date + '\n\n' context.bot.send_message(chat_id=update.callback_query.message.chat.id, text=tmp, parse_mode='html', silent=True) return ConversationHandler.END