def processAlerts(self): if 'alerts' not in self.db: return higher = 'HIGHER' lower = 'LOWER' alerts = self.db['alerts'] toRemove = [] print(alerts) for chatId in alerts: for fsym in alerts[chatId]: ops = alerts[chatId][fsym] for op in ops: tsyms = ops[op] for tsym in tsyms: targets = tsyms[tsym] price = self.repository.get_price_if_valid(fsym, tsym) for target in targets: self.log.info( f"{chatId} {fsym}{tsym} = {price} target {op} {target} " ) if op == lower and price < target or op == higher and price > target: self.api.sendMessage( '{} is {} {} at {} {}'.format( self.repository.get_symbols()[fsym], 'below' if op == lower else 'above', format_price(target), format_price(price), tsym), chatId) toRemove.append( (fsym, tsym, target, chatId, op)) for tr in toRemove: self.removeAlert(tr[0], tr[1], tr[2], tr[3], tr[4])
def price(self, chatId, command): parts = command.split() if len(parts) > 3: self.sendMessage("Invalid command, enter 2 symbols, eg: BTC USD", chatId) return fsym = TgBot.DEFAULT_COIN if len(parts) >1: fsym = parts[1].upper() tsym = self.DEFAULT_FIAT if len(parts) > 2: tsym = parts[2].upper() if not self.repository.isPricePairValid(fsym, tsym): self.sendMessage("Invalid symbols {} {}".format(fsym,tsym), chatId) return price = self.get_price(fsym, tsym) resp = '1 {} = {} {}'.format(self.get_symbols()[fsym], format_price(price),tsym) chartFile = self.repository.get_chart_near(fsym, tsym) if chartFile != None: self.sendPhoto(chartFile, resp, chatId) else: self.sendMessage(resp, chatId)
def chart(self, chatId, command): parts = command.split() if len(parts) > 4: self.sendMessage("Invalid command, enter 2 symbols, eg: BTC USD", chatId) return fsym = TgBot.DEFAULT_COIN if len(parts) > 1: fsym = parts[1].upper() tsym = self.DEFAULT_FIAT tf = CandleInterval.ONE_HOUR if len(parts) > 2: tsym = parts[2].upper() if len(parts) > 3 and CandleInterval.has_value(parts[3]): tf = CandleInterval(parts[3]) chartFile = self.repository.get_chart(fsym, tsym, tf) if chartFile != None: price = self.get_price(fsym, tsym) if self.repository.isPricePairValid(fsym, tsym): resp = '1 {} = {} {}'.format(self.get_symbols()[fsym], format_price(price),tsym) else: resp = "Enjoy the binance chart!" self.sendPhoto(chartFile, resp, chatId) else: self.sendMessage(f"no chart for {fsym} {tsym} {tf}", chatId)
def draw_chart_frame(self, draw, minVal, maxVal, symbol): color = (255, 255, 255) left = self.CHART_MARGIN_LEFT right = self.IMG_WIDTH bottom = self.IMG_HEIGHT - self.CHART_MARGIN_BOTTOM top = 0 MARGIN = 2 font = ImageFont.truetype(self.FONT_PATH, 14) # valStr = "{:.1f}".format(minVal) # size = draw.textsize(str(valStr), font) # draw.text((left-size[0]-MARGIN, bottom - size[1]- self.CHART_PADDING - MARGIN), str(valStr), color, font) # length = int(math.floor(math.log10(math.floor(maxVal))+1)) if maxVal>=1 else 0 # precision = 8 - length color_bg = (100, 100, 100) LINES = 12 for i in range(0, LINES + 1): y = bottom - ( i / LINES) * (bottom - top - self.CHART_MARGIN_TOP - self.CHART_PADDING * 2) - self.CHART_PADDING draw.line([(left, y), (right, y)], color_bg, 1) x = left + (i / LINES) * (right - left) draw.line([(x, top), (x, bottom)], color_bg, 1) val = minVal + (i / LINES) * (maxVal - minVal) valStr = format_price(val) size = draw.textsize(valStr, font) draw.text((left - size[0] - MARGIN, y - size[1] - MARGIN), valStr, color, font) draw.line([(left, bottom), (right, bottom)], color, 1) draw.line([(left, top), (left, bottom)], color, 1) #draw legend font_legend = ImageFont.truetype(self.FONT_PATH, 18) draw.text((left, top), symbol, (255, 255, 0), font_legend)
def higher_lower(self, chatId, command): parts = command.upper().split() if len(parts) < 3 or len(parts) > 4: self.api.sendMessage("Invalid command", chatId) return op = parts[0] fsym = parts[1] if not fsym in self.repository.get_symbols().keys(): self.api.sendMessage('Invalid symbol "{}"'.format(fsym), chatId) return try: target = float(parts[2]) except ValueError: self.api.sendMessage('Invalid number "{}"'.format(parts[2]), chatId) return tsym = parts[3] if len(parts) > 3 else config.DEFAULT_FIAT if tsym == "SAT" or tsym == "SATS": target = target / (100.0 * 1000.0 * 1000.0) tsym = "BTC" if tsym not in self.repository.TSYMS: self.api.sendMessage('Invalid symbol {}'.format(tsym), chatId) return if 'alerts' not in self.db: self.db['alerts'] = {} alerts = self.db['alerts'][chatId] if chatId in self.db[ 'alerts'] else {} if fsym in alerts: alert = alerts[fsym] if op in alert and type(alert[op]) is dict: opObj = alert[op] if tsym in opObj: opObj[tsym].add(target) else: opObj[tsym] = set([target]) else: alert[op] = {tsym: set([target])} else: alerts[fsym] = {op: {tsym: set([target])}} self.db['alerts'][chatId] = alerts msg = 'Notification set for {} {} {} {}.'.format( self.repository.get_symbols()[fsym], 'below' if op == 'LOWER' else 'above', format_price(target), tsym) self.api.sendMessage(msg, chatId)
def processMessage(self, message): if "text" not in message: print(F"message doesn't have text! \n {message}" text = message['text'] chatId = message['chat']['id'] if('entities' in message and message['entities'][0]['type'] == 'bot_command'): self.dispatchCommand(message) def removeAlert(self, fsym, tsym, target, chatId, op): alerts = TgBot.db['alerts'] alerts[chatId][fsym][op][tsym].remove(target) if len(alerts[chatId][fsym][op][tsym]) == 0: alerts[chatId][fsym][op].pop(tsym) if len(alerts[chatId][fsym][op]) == 0: alerts[chatId][fsym].pop(op) if len(alerts[chatId][fsym]) == 0: alerts[chatId].pop(fsym) if len(alerts[chatId]) == 0: alerts.pop(chatId) def processAlerts(self): if 'alerts' not in TgBot.db: return higher = 'HIGHER' lower = 'LOWER' alerts = TgBot.db['alerts'] toRemove = [] for chatId in alerts: for fsym in alerts[chatId]: ops = alerts[chatId][fsym] for op in ops: tsyms = ops[op] for tsym in tsyms: targets = tsyms[tsym] price = self.get_price(fsym, tsym) for target in targets: if op == lower and price < target or op == higher and price > target: self.sendMessage('{} is {} {} at {} {}'.format(self.get_symbols()[fsym], 'below' if op == lower else 'above', format_price(target), format_price(price), tsym), chatId) toRemove.append((fsym, tsym, target, chatId, op)) for tr in toRemove: self.removeAlert(tr[0], tr[1], tr[2], tr[3], tr[4]) def getUpdates(self): offset = self.last_update+1 url = self.getTgUrl('getUpdates') r = self.request_session.post( url=url, data={'offset': offset, 'limit': 100, 'timeout': 9}) updates = r.json() if not 'ok' in updates or not updates['ok']: return None return updates['result'] def processUpdates(self, updates): for update in updates: print('processing {}...'.format(update['update_id'])) message = update['message'] if 'message' in update else update['edited_message'] try: self.processMessage(message) self.last_update = TgBot.db['last_update'] = update['update_id'] except: traceback.print_exc() def init(self): try: with open(TgBot.DB_FILENAME, 'rb') as fp: TgBot.db = pickle.load(fp) except: self.log("error loading db") TgBot.db = {} #self.log("db at start: {}".format(TgBot.db)) self.last_update = TgBot.db['last_update'] if 'last_update' in TgBot.db else 0 def persist_db(self): with open(TgBot.DB_FILENAME, 'wb') as fp: #self.log(f"db at save: {TgBot.db}") pickle.dump(TgBot.db, fp)