コード例 #1
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        search = args[0]
        msg = str()

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            self.handle_error(e, update)

        for entry in response:
            if search.lower() in entry["name"].lower():
                name = entry["name"]
                symbol = entry["symbol"]

                msg += f"`{name} - {symbol.upper()}`\n"

        if msg:
            msg = f"`Coin-search for '{search}'`\n\n" + msg
        else:
            msg = f"{emo.INFO} No coin with '*{search}*' found"

        update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
コード例 #2
0
ファイル: top.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        base_cur = "USD"
        fiat_symbol = "$"

        if args:
            base_cur = args[0].upper()
            if base_cur == "EUR":
                fiat_symbol = "€"

        if RateLimit.limit_reached(update):
            return

        try:
            market = CoinGecko().get_coins_markets(
                base_cur.lower(),
                per_page=30,
                page=1,
                order="market_cap_desc",
                sparkline=False,
                price_change_percentage=False)
        except Exception as e:
            return self.handle_error(e, update)

        msg = str()

        if market:
            for i in range(30):
                rank = market[i]['market_cap_rank']
                symbol = market[i]['symbol'].upper()
                name = market[i]['name']

                price = market[i]['current_price']
                price = utl.format(price, decimals=4, symbol=base_cur)

                if base_cur == "EUR":
                    price = f"{price} {fiat_symbol}"
                    mcap = f"{utl.format(market[i]['market_cap'])}{fiat_symbol}"
                    vol = f"{utl.format(market[i]['total_volume'])}{fiat_symbol}"
                elif base_cur == "USD":
                    price = f"{fiat_symbol}{price}"
                    mcap = f"{fiat_symbol}{utl.format(market[i]['market_cap'])}"
                    vol = f"{fiat_symbol}{utl.format(market[i]['total_volume'])}"
                else:
                    price = f"{price}"
                    mcap = f"{utl.format(market[i]['market_cap'])}"
                    vol = f"{utl.format(market[i]['total_volume'])}"

                msg += f"{rank}. *{symbol}* ({name}) - {price}\n" \
                       f"` M.Cap.: {mcap}`\n" \
                       f"` Volume: {vol}`\n"

        if msg:
            msg = f"*Top 30 Coins by Market Cap in {base_cur}*\n\n {msg}"
        else:
            msg = f"{emo.ERROR} Can't retrieve toplist"

        update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
コード例 #3
0
    def get_action(self, bot, update, args):
        if not args:
            if update.message:
                update.message.reply_text(
                    text=f"Usage:\n{self.get_usage()}",
                    parse_mode=ParseMode.MARKDOWN)
            return

        coin = args[0].upper()

        if RateLimit.limit_reached(update):
            return

        try:
            data = DecentralizedYet().coins()
        except Exception as e:
            return self.handle_error(e, update)

        if not data:
            update.message.reply_text(
                text=f"{emo.INFO} No data found",
                parse_mode=ParseMode.MARKDOWN)
            return

        msg = str()

        for c in data:
            if coin == c["symbol"]:
                name = c["name"]
                symbol = c["symbol"]
                notes = c["notes"] if "notes" in c else ""
                cons = c["consensus"] if "consensus" in c else ""
                nodes = c["public_nodes"] if "public_nodes" in c else ""
                incen = c["incentivized"] if "incentivized" in c else ""
                clients = c["client_codebases"] if "client_codebases" in c else ""

                msg = f"`Are We Decentralized Yet?`\n{msg}"
                msg += f"`{name} ({symbol})`\n\n"

                if notes:
                    notes = utl.esc_md(f"{notes}\n\n")
                    msg += f"`{notes}`"

                msg += f"`Consensus:    {cons}`\n"
                msg += f"`Public Nodes: {nodes}`\n"
                msg += f"`Incentivized: {incen}`\n"
                msg += f"`Clients:      {clients}`"

                break

        if not msg:
            msg = f"{emo.ERROR} Can't retrieve data for *{coin}*"

        update.message.reply_text(
            text=msg,
            parse_mode=ParseMode.MARKDOWN)
コード例 #4
0
ファイル: twitter.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        # Set tokens for Twitter access
        tw = twitter.Api(consumer_key=self._consumer_key,
                         consumer_secret=self._consumer_secret,
                         access_token_key=self._access_token_key,
                         access_token_secret=self._access_token_secret)

        coin = args[0].upper()

        # Get coin ID
        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        timeline = None
        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)

                coin_name = data["name"]
                tw_account = data["links"]["twitter_screen_name"]

                if tw_account:
                    timeline = tw.GetUserTimeline(screen_name=tw_account,
                                                  count=3,
                                                  include_rts=False,
                                                  trim_user=True,
                                                  exclude_replies=True)
                break

        if timeline:
            for tweet in [i.AsDict() for i in reversed(timeline)]:
                stats = f"{emo.HEART} {tweet['favorite_count']} " \
                        f"{emo.REPEAT} {tweet['retweet_count']}"

                msg = f"*Tweet from {coin_name}*\n" \
                      f"{tweet['created_at'].split('+')[0]}\n" \
                      f"{stats}\n\n" \
                      f"{tweet['text']}"

                update.message.reply_text(text=msg,
                                          parse_mode=ParseMode.MARKDOWN)
コード例 #5
0
ファイル: wallets.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        if not args:
            if update.message:
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coins = utl.get_kw(args, "coins")

        try:
            cp = CryptoCompare(token=self._token)
            wallets = cp.get_wallet_info()
        except Exception as e:
            return self.handle_error(e, update)

        if wallets["Response"] == "Error":
            if update.message:
                update.message.reply_text(
                    text=f"{emo.ERROR} {wallets['Message']}",
                    parse_mode=ParseMode.MARKDOWN)
            return

        found = False

        # Return wallets for specified coin(s)
        if coins:
            coin_list = coins.split(",")

            for _, wa in wallets["Data"].items():
                if all(x.strip().upper() in wa["Coins"] for x in coin_list):
                    update.message.reply_text(text=self._get_msg(wa),
                                              parse_mode=ParseMode.MARKDOWN)

                    found = True

        # Return info about specified wallet(s)
        else:
            wallet = " ".join(args)

            for _, wa in wallets["Data"].items():
                if wallet.upper() in wa["Name"].upper():
                    update.message.reply_text(text=self._get_msg(wa),
                                              parse_mode=ParseMode.MARKDOWN)

                    found = True

        if not found:
            update.message.reply_text(text=f"{emo.INFO} No wallet found",
                                      parse_mode=ParseMode.MARKDOWN)
コード例 #6
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        msg = str()

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            self.handle_error(e, update)

        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    self.handle_error(e, update)

                dev_data = data["developer_data"]

                for k, v in dev_data.items():
                    msg += f"`{k.title().replace('_', ' ')}: {str(v)}`\n"

                gh_links = data["links"]["repos_url"]["github"]

                if not gh_links:
                    break

                msg += "\n`GitHub links:`\n"

                for link in gh_links:
                    title_index = link.rfind("/")
                    msg += f"[{link[title_index+1:len(link)]}]({link})\n"

                break

        if msg:
            msg = f"`GitHub info for {coin}`\n\n" + msg
        else:
            msg = f"{emo.INFO} No developer data found for *{coin}*"

        update.message.reply_text(text=msg.replace("Pull Request", "PR"),
                                  parse_mode=ParseMode.MARKDOWN,
                                  disable_web_page_preview=True)
コード例 #7
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        if len(args) > 1:
            name = "-".join(args).lower()
        else:
            name = args[0]

        name_clean = name.replace('-', " ").title()
        msg = str()

        try:
            d = CoinPaprika().get_people_by_id(name)
        except Exception as e:
            return self.handle_error(e, update)

        if "description" in d and d["description"]:
            msg = f"`{d['description']}`\n\n"

        if "links" in d and d["links"]:
            for k, v in d["links"].items():
                url = v[0]["url"]
                fol = v[0]["followers"] if "followers" in v[0] else None

                fol_str = f"({utl.format(fol)} Followers)" if fol else ""
                msg += f"`{k.title()} {fol_str}`\n{utl.esc_md(url)}\n"

        if "positions" in d and d["positions"]:
            msg += "\n`Positions:`\n" if msg else "`Positions:`\n"

            for pos in d["positions"]:
                msg += f"`{pos['coin_symbol']} - {pos['position']}`\n"

        if not msg:
            update.message.reply_text(
                text=f"{emo.INFO} No person with name *'{name_clean}'* found",
                parse_mode=ParseMode.MARKDOWN)
            return

        msg = f"`{name_clean}`\n\n{msg}"

        update.message.reply_text(text=msg,
                                  parse_mode=ParseMode.MARKDOWN,
                                  disable_web_page_preview=True)
コード例 #8
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(
                text=f"Usage:\n{self.get_usage()}",
                parse_mode=ParseMode.MARKDOWN)
            return

        if len(args) > 1:
            update.message.reply_text(
                text=f"{emo.ERROR} Only one argument allowed",
                parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        msg = str()

        try:
            response = APICache.get_cp_coin_list()
        except Exception as e:
            return self.handle_error(e, update)

        for c in response:
            if c["symbol"] == coin:
                try:
                    cp_coin_detail = CoinPaprika().get_coin_by_id(c["id"])["team"]
                except Exception as e:
                    return self.handle_error(e, update)

                for p in cp_coin_detail:
                    details = utl.esc_md(f"/_people__{p['id'].replace('-', '_')}")
                    msg += f"`{p['name']}\n{p['position']}`\n{details}\n\n"
                break

        if not msg:
            update.message.reply_text(
                text=f"{emo.INFO} No team data for *{coin}*",
                parse_mode=ParseMode.MARKDOWN)
            return

        msg = f"`Team behind {coin}`\n\n{msg}"

        for message in utl.split_msg(msg):
            update.message.reply_text(
                text=message,
                parse_mode=ParseMode.MARKDOWN,
                disable_web_page_preview=True)
コード例 #9
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        data = None

        try:
            coin_data = Crypto51().coins()
        except Exception as e:
            return self.handle_error(e, update)

        if not coin_data or not coin_data["coins"]:
            update.message.reply_text(text=f"{emo.INFO} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        # Get coin ID and data
        for entry in coin_data["coins"]:
            if entry["symbol"] == coin:
                data = entry
                break

        if not data:
            update.message.reply_text(text=f"{emo.INFO} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        name = data["name"]
        algo = data["algorithm"]
        mcap = data["market_cap_pretty"]
        hash = data["hash_rate_pretty"]
        atck = data["attack_hourly_cost_pretty"]
        hour = data["rentable_price_usd_hour"]

        update.message.reply_text(text=f"`PoW 51% Attack Cost\n`"
                                  f"`for {coin} ({name})\n\n`"
                                  f"`Algorithm      {algo}\n`"
                                  f"`Market Cap     {mcap}\n`"
                                  f"`Hashrate       {hash}\n`"
                                  f"`Attack Cost 1h {atck}\n`"
                                  f"`Rent. Price 1h {hour}`",
                                  parse_mode=ParseMode.MARKDOWN,
                                  disable_web_page_preview=True)
コード例 #10
0
    def get_action(self, bot, update, args):
        kw = utl.get_kw(args)

        limit = kw.get("limit", 5)
        kw.pop("limit", None)

        if RateLimit.limit_reached(update):
            return

        try:
            events = CoinGecko().get_events(**kw)
        except Exception as e:
            return self.handle_error(e, update)

        for i in range(int(limit)):
            if len(events["data"]) <= i:
                break

            event = events["data"][i]

            title = event["title"]
            event_type = event["type"]
            description = event["description"]
            organizer = event["organizer"]
            from_date = event["start_date"]
            to_date = event["end_date"]
            address = event["address"].strip()
            city = event["city"].strip()
            country = event["country"].strip()
            website = event["website"]

            org = f" by {organizer}" if organizer else ""

            msg = f"[{title}]({website})\n" \
                  f"{event_type}{org}\n\n" \
                  f"{utl.esc_md(description)}\n\n" \
                  f"*Date*\nStart {from_date}\nEnd   {to_date}\n\n" \
                  f"*Location*\n{address}\n{city}\n{country}\n\n"

            update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
コード例 #11
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        data = None

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)
                break

        if not data or not data["description"]["en"]:
            update.message.reply_text(text=f"{emo.INFO} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        coin_desc = data["description"]["en"]

        if len(coin_desc) > con.MAX_TG_MSG_LEN:
            url = f"https://www.coingecko.com/en/coins/{data['id']}"
            html_link = f'...\n\n<a href="{url}">Read whole description</a>'
            coin_desc = coin_desc[:(con.MAX_TG_MSG_LEN - 27)] + html_link

        update.message.reply_text(text=coin_desc,
                                  parse_mode=ParseMode.HTML,
                                  disable_web_page_preview=True)
コード例 #12
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(
                text=f"Usage:\n{self.get_usage()}",
                parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        data = None

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)
                break

        if not data or not data["description"]["en"]:
            update.message.reply_text(
                text=f"{emo.INFO} No data for *{coin}*",
                parse_mode=ParseMode.MARKDOWN)
            return

        coin_desc = data["description"]["en"]

        for message in utl.split_msg(coin_desc):
            update.message.reply_text(
                text=message,
                parse_mode=ParseMode.HTML,
                disable_web_page_preview=True)
コード例 #13
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        coin = args[0].upper()

        search = str()
        if len(args) > 1:
            search = args[1]

        try:
            link = self._from_allcryptowhitepaper(coin)

            if not link:
                if RateLimit.limit_reached(update):
                    return

                link = self._from_coinmarketcap(coin)

            if not link and search == "all":
                link = self._from_coinpaprika(coin)
        except Exception as e:
            self.handle_error(e, update)

        if link:
            try:
                update.message.reply_document(
                    document=link, caption=f"{self.name} Whitepaper")
            except BadRequest:
                msg = f"{self.name} Whitepaper\n{link}"
                update.message.reply_text(text=msg)
        else:
            update.message.reply_text(
                text=f"{emo.INFO} No whitepaper for *{coin}* found",
                parse_mode=ParseMode.MARKDOWN)
コード例 #14
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        msg = str()

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            self.handle_error(e, update)

        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    self.handle_error(e, update)

                if "ico_data" not in data:
                    break

                ico_start = data["ico_data"]["ico_start_date"][:10]
                ico_end = data["ico_data"]["ico_end_date"][:10]
                raised = data["ico_data"]["total_raised"]
                raised_cur = data["ico_data"]["total_raised_currency"]

                pre_sale_c = data["ico_data"]["quote_pre_sale_currency"]
                pre_sale_a = data["ico_data"]["base_pre_sale_amount"]
                pre_sale_p = data["ico_data"]["quote_pre_sale_amount"]

                pub_sale_c = data["ico_data"]["quote_public_sale_currency"]
                pub_sale_a = data["ico_data"]["base_public_sale_amount"]
                pub_sale_p = data["ico_data"]["quote_public_sale_amount"]

                kyc_req = data["ico_data"]["kyc_required"]

                raised = utl.format(raised) if raised is not None else raised

                if pre_sale_a:
                    pre_sale_a = utl.format(pre_sale_a, symbol=coin)
                if pre_sale_p:
                    pre_sale_p = utl.format(pre_sale_p, symbol=pre_sale_c)

                if pub_sale_a:
                    pub_sale_a = utl.format(pub_sale_a, symbol=coin)
                if pub_sale_p:
                    pub_sale_p = utl.format(pub_sale_p, symbol=pub_sale_c)

                if pre_sale_a:
                    pre_sale_str = f"{pre_sale_a} {coin} for {pre_sale_p} {pre_sale_c}\n"
                else:
                    pre_sale_str = "None\n"

                if pub_sale_a:
                    pub_sale_str = f"{pub_sale_a} {coin} for {pub_sale_p} {pub_sale_c}\n"
                else:
                    pub_sale_str = "None\n"

                msg = f"`" \
                      f"Start:    {ico_start}\n" \
                      f"End:      {ico_end}\n" \
                      f"Raised:   {raised} {raised_cur}\n" \
                      f"Pre-Sale: {pre_sale_str}" \
                      f"Pub-Sale: {pub_sale_str}" \
                      f"KYC:      {'Yes' if kyc_req == True else 'No'}" \
                      f"`"
                break

        if msg:
            msg = f"`ICO data for {coin}`\n\n" + msg
        else:
            msg = f"{emo.INFO} No ICO data for *{coin}*"

        update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
コード例 #15
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(
                text=f"Usage:\n{self.get_usage()}",
                parse_mode=ParseMode.MARKDOWN)
            return

        time_frame = 3  # Days
        base_coin = "BTC"

        if "-" in args[0]:
            pair = args[0].split("-", 1)
            base_coin = pair[0].upper()
            coin = pair[1].upper()
        else:
            coin = args[0].upper()

        if coin == "BTC" and base_coin == "BTC":
            base_coin = "USD"

        if coin == base_coin:
            update.message.reply_text(
                text=f"{emo.ERROR} Can't compare *{coin}* to itself",
                parse_mode=ParseMode.MARKDOWN)
            return

        if len(args) > 1 and args[1].isnumeric():
            time_frame = args[1]

        if RateLimit.limit_reached(update):
            return

        cg_thread = threading.Thread(target=self._get_cg_coin_id, args=[coin])
        cmc_thread = threading.Thread(target=self._get_cmc_coin_id, args=[coin])

        cg_thread.start()
        cmc_thread.start()

        cg_thread.join()

        if not self.cg_coin_id:
            update.message.reply_text(
                text=f"{emo.ERROR} Can't retrieve data for *{coin}*",
                parse_mode=ParseMode.MARKDOWN)
            return

        try:
            market = CoinGecko().get_coin_market_chart_by_id(
                self.cg_coin_id,
                base_coin.lower(),
                time_frame)
        except Exception as e:
            self.handle_error(e, update)

        # Volume
        df_volume = DataFrame(market["total_volumes"], columns=["DateTime", "Volume"])
        df_volume["DateTime"] = pd.to_datetime(df_volume["DateTime"], unit="ms")
        volume = go.Scatter(
            x=df_volume.get("DateTime"),
            y=df_volume.get("Volume"),
            name="Volume"
        )

        # Price
        df_price = DataFrame(market["prices"], columns=["DateTime", "Price"])
        df_price["DateTime"] = pd.to_datetime(df_price["DateTime"], unit="ms")
        price = go.Scatter(
            x=df_price.get("DateTime"),
            y=df_price.get("Price"),
            yaxis="y2",
            name="Price",
            line=dict(
                color=("rgb(22, 96, 167)"),
                width=2
            )
        )

        cmc_thread.join()

        if not self.cmc_coin_id:
            update.message.reply_text(
                text=f"{emo.ERROR} Can't retrieve data for *{coin}*",
                parse_mode=ParseMode.MARKDOWN)
            return

        margin_l = 140
        tickformat = "0.8f"

        max_value = df_price["Price"].max()
        if max_value > 0.9:
            if max_value > 999:
                margin_l = 110
                tickformat = "0,.0f"
            else:
                margin_l = 115
                tickformat = "0.2f"

        layout = go.Layout(
            images=[dict(
                source=f"{con.CMC_LOGO_URL_PARTIAL}{self.cmc_coin_id}.png",
                opacity=0.8,
                xref="paper", yref="paper",
                x=1.05, y=1,
                sizex=0.2, sizey=0.2,
                xanchor="right", yanchor="bottom"
            )],
            paper_bgcolor='rgb(233,233,233)',
            plot_bgcolor='rgb(233,233,233)',
            autosize=False,
            width=800,
            height=600,
            margin=go.layout.Margin(
                l=margin_l,
                r=50,
                b=85,
                t=100,
                pad=4
            ),
            yaxis=dict(
                domain=[0, 0.20]
            ),
            yaxis2=dict(
                title=dict(
                    text=base_coin,
                    font=dict(
                        size=18
                    )
                ),                domain=[0.25, 1],
                tickprefix="   ",
                ticksuffix=f"  "
            ),
            title=dict(
                text=coin,
                font=dict(
                    size=26
                )
            ),
            legend=dict(
                orientation="h",
                yanchor="top",
                xanchor="center",
                y=1.05,
                x=0.45
            ),
            shapes=[{
                "type": "line",
                "xref": "paper",
                "yref": "y2",
                "x0": 0,
                "x1": 1,
                "y0": market["prices"][len(market["prices"]) - 1][1],
                "y1": market["prices"][len(market["prices"]) - 1][1],
                "line": {
                    "color": "rgb(50, 171, 96)",
                    "width": 1,
                    "dash": "dot"
                }
            }],
        )

        try:
            fig = go.Figure(data=[price, volume], layout=layout)
        except Exception as e:
            self.handle_error(e, update)

        fig["layout"]["yaxis2"].update(tickformat=tickformat)

        update.message.reply_photo(
            photo=io.BufferedReader(BytesIO(pio.to_image(fig, format="jpeg"))),
            parse_mode=ParseMode.MARKDOWN)
コード例 #16
0
ファイル: worst.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        if args:
            t = args[0].lower()
            if not t == "hour" and not t == "day":
                update.message.reply_text(
                    text=
                    f"{emo.ERROR} First argument has to be `day` or `hour`",
                    parse_mode=ParseMode.MARKDOWN)
                return

        if len(args) > 1:
            entries = args[1]
            if not entries.isnumeric():
                update.message.reply_text(
                    text=f"{emo.ERROR} Second argument (# of positions "
                    f"to display) has to be a number",
                    parse_mode=ParseMode.MARKDOWN)
                return

        if len(args) > 2:
            entries = args[2]
            if not entries.isnumeric():
                update.message.reply_text(
                    text=f"{emo.ERROR} Third argument (min. volume) "
                    f"has to be a number",
                    parse_mode=ParseMode.MARKDOWN)
                return

        if RateLimit.limit_reached(update):
            return

        period = CoinData.HOUR
        volume = None
        entries = 10

        if args:
            # Period
            if args[0].lower() == "hour":
                period = CoinData.HOUR
            elif args[0].lower() == "day":
                period = CoinData.DAY
            else:
                period = CoinData.HOUR

            # Entries
            if len(args) > 1 and args[1].isnumeric():
                entries = int(args[1])

            # Volume
            if len(args) > 2 and args[2].isnumeric():
                volume = int(args[2])

        try:
            best = CoinData().get_movers(CoinData.WORST,
                                         period=period,
                                         entries=entries,
                                         volume=volume)
        except Exception as e:
            return self.handle_error(e, update)

        if not best:
            update.message.reply_text(
                text=f"{emo.ERROR} No matching data found",
                parse_mode=ParseMode.MARKDOWN)
            return

        msg = str()

        for coin in best:
            name = coin["Name"]
            symbol = coin["Symbol"]
            desc = f"{name} ({symbol})"

            if len(desc) > self.DESC_LEN:
                desc = f"{desc[:self.DESC_LEN-3]}..."

            if period == CoinData.HOUR:
                change = coin["Change_1h"]
            else:
                change = coin["Change_24h"]

            change = utl.format(change, decimals=2, force_length=True)
            change = "{1:>{0}}".format(self.DESC_LEN + 9 - len(desc), change)
            msg += f"`{desc}{change}%`\n"

        vol = str()
        if volume:
            vol = f" (vol > {utl.format(volume)})"

        update.message.reply_text(
            text=f"`Worst movers 1{period.lower()[:1]}{vol}\n\n`" + msg,
            parse_mode=ParseMode.MARKDOWN)
コード例 #17
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        msg = str()
        top = str()
        exchange = str()

        if args[0].lower().startswith("top="):
            top = args[0][4:]
        else:
            exchange = args[0]

        # ---------- TOP EXCHANGES ----------

        if top:
            if not top.isnumeric():
                update.message.reply_text(
                    text=f"{emo.ERROR} Value of `top` has to be a number",
                    parse_mode=ParseMode.MARKDOWN)
                return
            if int(top) > 100:
                update.message.reply_text(
                    text=f"{emo.ERROR} Max value for `top` is `100`",
                    parse_mode=ParseMode.MARKDOWN)
                return

            if RateLimit.limit_reached(update):
                return

            try:
                response = APICache.get_cg_exchanges_list()
            except Exception as e:
                self.handle_error(e, update)

            exchanges = sorted(response,
                               key=lambda k: float(k["trade_volume_24h_btc"]),
                               reverse=True)

            for i in range(int(top)):
                ex = exchanges[i]

                nr = f"#{i+1}"
                name = ex["name"]
                volume = ex["trade_volume_24h_btc"]

                msg += f"`{nr} {name}\n{utl.format(volume)} BTC`\n\n"

            msg = f"`Top {top} exchanges by 24h volume`\n\n{msg}"

        # ---------- EXCHANGE DETAILS ----------

        else:
            if RateLimit.limit_reached(update):
                return

            try:
                response = APICache.get_cg_exchanges_list()
            except Exception as e:
                self.handle_error(e, update)

            for ex in response:
                clean_ex = ex["name"].replace(" ", "")
                if exchange.lower() in clean_ex.lower():
                    nme = ex["name"] if ex["name"] else "N/A"
                    est = ex["year_established"] if ex[
                        "year_established"] else "N/A"
                    cnt = ex["country"] if ex["country"] else "N/A"
                    des = ex["description"] if ex[
                        "description"] else "(No description available)"
                    url = ex["url"] if ex["url"] else "(No link available)"
                    vol = ex["trade_volume_24h_btc"] if ex[
                        "trade_volume_24h_btc"] else "N/A"

                    msg += f"`{nme}`\n" \
                           f"{utl.url(url)}\n\n" \
                           f"`Country:     {cnt}`\n" \
                           f"`Volume 24h:  {utl.format(vol)} BTC`\n" \
                           f"`Established: {est}`\n\n" \
                           f"`{utl.remove_html_links(des)}`\n\n\n" \

        if not msg:
            update.message.reply_text(
                text=f"{emo.INFO} No exchange '{exchange}' found",
                parse_mode=ParseMode.MARKDOWN)
            return

        update.message.reply_text(text=msg,
                                  parse_mode=ParseMode.MARKDOWN,
                                  disable_web_page_preview=True)
コード例 #18
0
    def get_action(self, bot, update, args):
        keywords = utl.get_kw(args)
        arg_list = utl.del_kw(args)

        if not arg_list:
            if not keywords.get(Keyword.INLINE):
                update.message.reply_text(
                    text=f"Usage:\n{self.get_usage()}",
                    parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        vs_cur = "usd"

        if "-" in arg_list[0]:
            pair = arg_list[0].split("-", 1)
            vs_cur = pair[1].lower()
            coin = pair[0].upper()
        else:
            coin = arg_list[0].upper()

        ath_date = str()
        ath_price = str()
        cur_price = str()
        ath_change = str()

        # Get coin ID
        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        for entry in response:
            if entry["symbol"].lower() == coin.lower():
                try:
                    coin_info = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)

                cur_price = coin_info["market_data"]["current_price"]
                ath_price = coin_info["market_data"]["ath"]
                ath_date = coin_info["market_data"]["ath_date"]
                ath_change = coin_info["market_data"]["ath_change_percentage"]
                break

        msg = str()

        for c in vs_cur.split(","):
            if c in ath_price:
                ath_p = format(ath_price[c])
                cur_p = format(cur_price[c], template=ath_p)
                change = format(ath_change[c], decimals=2)

                date_time = ath_date[c]
                date_ath = date_time[:10]
                date_list = date_ath.split("-")
                y = int(date_list[0])
                m = int(date_list[1])
                d = int(date_list[2])

                ath = date(y, m, d)
                now = datetime.date.today()

                ath_p_str = f"Price ATH: {ath_p} {c.upper()}\n"
                cur_p_str = f"Price NOW: {cur_p.rjust(len(ath_p))} {c.upper()}\n"

                msg += f"`" \
                       f"{date_ath} ({(now - ath).days} days ago)\n" \
                       f"{ath_p_str}" \
                       f"{cur_p_str}" \
                       f"Change: {change}%\n\n" \
                       f"`"

        if msg:
            msg = f"`All-Time High for {coin}`\n\n {msg}"
        else:
            msg = f"{emo.ERROR} Can't retrieve data for *{coin}*"

        if keywords.get(Keyword.INLINE):
            return msg

        self.send_msg(msg, update, keywords)
コード例 #19
0
ファイル: market.py プロジェクト: 7h3v01c3/OpenCryptoBot
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()
        coin_info = None

        volume = False
        if len(args) > 1:
            if args[1].lower().startswith("vol"):
                volume = True

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        # Get coin ID and data
        for entry in response:
            if entry["symbol"].upper() == coin:
                try:
                    coin_info = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)
                break

        if not coin_info or not coin_info["tickers"]:
            update.message.reply_text(text=f"{emo.ERROR} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        # Sort markets by volume
        if volume:
            data = sorted(coin_info["tickers"],
                          key=lambda k: float(k["volume"]),
                          reverse=True)

            count = len(data)
            if count > 10:
                count = 10

            msg = str()
            for i in range(count):
                vs_cur = data[i]["target"]
                exchange = data[i]["market"]["name"]
                vol_usd = data[i]["converted_volume"]["usd"]
                vol_usd = utl.format(vol_usd, decimals=2, force_length=True)

                msg += f"{exchange} - {vs_cur}\nVolume: {vol_usd} USD\n\n"

            update.message.reply_text(text=f"`Exchanges that trade {coin}`\n"
                                      f"`Top 10 sorted by volume\n\n{msg}`",
                                      parse_mode=ParseMode.MARKDOWN)

        else:
            exchanges = set()
            for ticker in coin_info["tickers"]:
                exchanges.add(ticker['market']['name'])

            exchanges = "\n".join(sorted(exchanges))

            update.message.reply_text(
                text=f"`Exchanges that trade {coin}`\n\n`{exchanges}`",
                parse_mode=ParseMode.MARKDOWN)
コード例 #20
0
ファイル: stats.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        keywords = utl.get_kw(args)
        arg_list = utl.del_kw(args)

        if not arg_list:
            if not keywords.get(Keyword.INLINE):
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = arg_list[0].upper()
        data = None
        cgid = None

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        # Get coin ID and data
        for entry in response:
            if entry["symbol"].upper() == coin:
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)

                cgid = entry["id"]
                break

        if not data:
            update.message.reply_text(text=f"{emo.ERROR} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        name = data["name"]
        symbol = data["symbol"].upper()

        rank_mc = data["market_cap_rank"]
        rank_cg = data["coingecko_rank"]

        cs = int(float(data['market_data']['circulating_supply']))
        sup_c = f"{utl.format(cs)} {symbol}"

        if data["market_data"]["total_supply"]:
            ts = int(float(data["market_data"]["total_supply"]))
            sup_t = f"{utl.format(ts)} {symbol}"
        else:
            sup_t = "N/A"

        usd = data["market_data"]["current_price"]["usd"]
        eur = data["market_data"]["current_price"]["eur"]
        btc = data["market_data"]["current_price"]["btc"]
        eth = data["market_data"]["current_price"]["eth"]

        p_usd = utl.format(usd, force_length=True)
        p_eur = utl.format(eur, force_length=True, template=p_usd)
        p_btc = utl.format(btc, force_length=True, template=p_usd)
        p_eth = utl.format(eth, force_length=True, template=p_usd)

        p_usd = "{:>12}".format(p_usd)
        p_eur = "{:>12}".format(p_eur)
        p_btc = "{:>12}".format(p_btc)
        p_eth = "{:>12}".format(p_eth)

        # Do not display BTC or ETH price if coin is BTC or ETH
        btc_str = "" if coin == "BTC" else f"BTC {p_btc}\n"
        eth_str = "" if coin == "ETH" else f"ETH {p_eth}\n"

        v_24h = utl.format(
            int(float(data["market_data"]["total_volume"]["usd"])))
        m_cap = utl.format(int(float(
            data["market_data"]["market_cap"]["usd"])))

        if data["market_data"]["price_change_percentage_1h_in_currency"]:
            c_1h = data["market_data"][
                "price_change_percentage_1h_in_currency"]["usd"]
            c1h = utl.format(float(c_1h), decimals=2, force_length=True)
            h1 = "{:>10}".format(f"{c1h}%")
        else:
            h1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_24h_in_currency"]:
            c_1d = data["market_data"][
                "price_change_percentage_24h_in_currency"]["usd"]
            c1d = utl.format(float(c_1d), decimals=2, force_length=True)
            d1 = "{:>10}".format(f"{c1d}%")
        else:
            d1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_7d_in_currency"]:
            c_1w = data["market_data"][
                "price_change_percentage_7d_in_currency"]["usd"]
            c1w = utl.format(float(c_1w), decimals=2, force_length=True)
            w1 = "{:>10}".format(f"{c1w}%")
        else:
            w1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_30d_in_currency"]:
            c_1m = data["market_data"][
                "price_change_percentage_30d_in_currency"]["usd"]
            c1m = utl.format(float(c_1m), decimals=2, force_length=True)
            m1 = "{:>10}".format(f"{c1m}%")
        else:
            m1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_1y_in_currency"]:
            c_1y = data["market_data"][
                "price_change_percentage_1y_in_currency"]["usd"]
            c1y = utl.format(float(c_1y), decimals=2, force_length=True)
            y1 = "{:>10}".format(f"{c1y}%")
        else:
            y1 = "{:>10}".format("N/A")

        msg = f"`" \
              f"{name} ({symbol})\n\n" \
              f"USD {p_usd}\n" \
              f"EUR {p_eur}\n" \
              f"{btc_str}" \
              f"{eth_str}\n" \
              f"Hour  {h1}\n" \
              f"Day   {d1}\n" \
              f"Week  {w1}\n" \
              f"Month {m1}\n" \
              f"Year  {y1}\n\n" \
              f"Market Cap Rank: {rank_mc}\n" \
              f"Coin Gecko Rank: {rank_cg}\n\n" \
              f"Volume 24h: {v_24h} USD\n" \
              f"Market Cap: {m_cap} USD\n" \
              f"Circ. Supp: {sup_c}\n" \
              f"Total Supp: {sup_t}\n\n" \
              f"`" \
              f"Stats on [CoinGecko](https://www.coingecko.com/en/coins/{cgid}) & " \
              f"[Coinlib](https://coinlib.io/coin/{coin}/{coin})"

        if keywords.get(Keyword.INLINE):
            return msg

        self.send_msg(msg, update, keywords)
コード例 #21
0
ファイル: candlestick.py プロジェクト: cncoder/OpenCryptoBot
    def get_action(self, bot, update, args):
        keywords = utl.get_kw(args)
        arg_list = utl.del_kw(args)

        if not arg_list:
            if not keywords.get(Keyword.INLINE):
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
            return

        time_frame = 72
        resolution = "HOUR"
        base_coin = "BTC"

        # Coin or pair
        if "-" in arg_list[0]:
            pair = arg_list[0].split("-", 1)
            base_coin = pair[1].upper()
            coin = pair[0].upper()
        else:
            coin = arg_list[0].upper()

        if coin == "BTC" and base_coin == "BTC":
            base_coin = "USD"

        if coin == base_coin:
            update.message.reply_text(
                text=f"{emo.ERROR} Can't compare *{coin}* to itself",
                parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        cmc_thread = threading.Thread(target=self._get_cmc_coin_id,
                                      args=[coin])
        cmc_thread.start()

        # Time frame
        if len(arg_list) > 1:
            if arg_list[1].lower().endswith(
                    "m") and arg_list[1][:-1].isnumeric():
                resolution = "MINUTE"
                time_frame = arg_list[1][:-1]
            elif arg_list[1].lower().endswith(
                    "h") and arg_list[1][:-1].isnumeric():
                resolution = "HOUR"
                time_frame = arg_list[1][:-1]
            elif arg_list[1].lower().endswith(
                    "d") and arg_list[1][:-1].isnumeric():
                resolution = "DAY"
                time_frame = arg_list[1][:-1]
            else:
                update.message.reply_text(
                    text=f"{emo.ERROR} Argument *{arg_list[1]}* is invalid",
                    parse_mode=ParseMode.MARKDOWN)
                return

        try:
            if resolution == "MINUTE":
                ohlcv = CryptoCompare().get_historical_ohlcv_minute(
                    coin, base_coin, time_frame)
            elif resolution == "HOUR":
                ohlcv = CryptoCompare().get_historical_ohlcv_hourly(
                    coin, base_coin, time_frame)
            elif resolution == "DAY":
                ohlcv = CryptoCompare().get_historical_ohlcv_daily(
                    coin, base_coin, time_frame)
            else:
                ohlcv = CryptoCompare().get_historical_ohlcv_hourly(
                    coin, base_coin, time_frame)
        except Exception as e:
            return self.handle_error(e, update)

        if ohlcv["Response"] == "Error":
            if ohlcv["Message"] == "limit is larger than max value.":
                update.message.reply_text(
                    text=f"{emo.ERROR} Time frame can't be larger "
                    f"then *{con.CG_DATA_LIMIT}* data points",
                    parse_mode=ParseMode.MARKDOWN)
                return
            elif ohlcv["Message"].startswith(
                    "There is no data for the symbol"):
                ohlcv = None
            else:
                update.message.reply_text(
                    text=f"{emo.ERROR} CoinGecko ERROR: {ohlcv['Message']}",
                    parse_mode=ParseMode.MARKDOWN)
                return

        ohlcv = ohlcv["Data"]

        if ohlcv:
            try:
                o = [value["open"] for value in ohlcv]
                h = [value["high"] for value in ohlcv]
                l = [value["low"] for value in ohlcv]
                c = [value["close"] for value in ohlcv]
                t = [value["time"] for value in ohlcv]
            except:
                return self.handle_error(f"No OHLC data for {coin}", update)

        if not ohlcv or utl.all_same(o, h, l, c):
            if base_coin != "BTC" and base_coin != "USD":
                update.message.reply_text(
                    text=f"{emo.ERROR} Base currency for "
                    f"*{coin}* can only be *BTC* or *USD*",
                    parse_mode=ParseMode.MARKDOWN)
                return

            # Time frame
            if len(arg_list) > 1:
                if resolution != "DAY":
                    update.message.reply_text(
                        text=f"{emo.ERROR} Timeframe for *{coin}* "
                        f"can only be specified in days",
                        parse_mode=ParseMode.MARKDOWN)
                    return
                else:
                    time_frame = int(time_frame)
            else:
                time_frame = 60  # Days

            try:
                cp_ohlc = APICache.get_cp_coin_list()
            except Exception as e:
                return self.handle_error(e, update)

            for c in cp_ohlc:
                if c["symbol"] == coin:
                    # Current datetime in seconds
                    t_now = time.time()
                    # Convert chart time span to seconds
                    time_frame = time_frame * 24 * 60 * 60
                    # Start datetime for chart in seconds
                    t_start = t_now - int(time_frame)

                    try:
                        ohlcv = CoinPaprika().get_historical_ohlc(
                            c["id"],
                            int(t_start),
                            end=int(t_now),
                            quote=base_coin.lower(),
                            limit=366)
                    except Exception as e:
                        return self.handle_error(e, update)

                    cp_api = True
                    break

            if not ohlcv:
                update.message.reply_text(
                    text=f"{emo.ERROR} No OHLC data for *{coin}* "
                    f"available or time frame too big",
                    parse_mode=ParseMode.MARKDOWN)
                return

            try:
                o = [value["open"] for value in ohlcv]
                h = [value["high"] for value in ohlcv]
                l = [value["low"] for value in ohlcv]
                c = [value["close"] for value in ohlcv]
                t = [
                    time.mktime(dau.parse(value["time_close"]).timetuple())
                    for value in ohlcv
                ]
            except:
                return self.handle_error(f"No OHLC data for {coin}", update)

        margin_l = 140
        tickformat = "0.8f"

        max_value = max(h)
        if max_value > 0.9:
            if max_value > 999:
                margin_l = 120
                tickformat = "0,.0f"
            else:
                margin_l = 125
                tickformat = "0.2f"

        try:
            fig = fif.create_candlestick(o, h, l, c, pd.to_datetime(t,
                                                                    unit='s'))
        except Exception as e:
            return self.handle_error(e, update)

        fig['layout']['yaxis'].update(tickformat=tickformat,
                                      tickprefix="   ",
                                      ticksuffix=f"  ")

        fig['layout'].update(title=dict(text=coin, font=dict(size=26)),
                             yaxis=dict(title=dict(text=base_coin,
                                                   font=dict(size=18)), ))

        fig['layout'].update(shapes=[{
            "type": "line",
            "xref": "paper",
            "yref": "y",
            "x0": 0,
            "x1": 1,
            "y0": c[len(c) - 1],
            "y1": c[len(c) - 1],
            "line": {
                "color": "rgb(50, 171, 96)",
                "width": 1,
                "dash": "dot"
            }
        }])

        fig['layout'].update(paper_bgcolor='rgb(233,233,233)',
                             plot_bgcolor='rgb(233,233,233)',
                             autosize=False,
                             width=800,
                             height=600,
                             margin=go.layout.Margin(l=margin_l,
                                                     r=50,
                                                     b=85,
                                                     t=100,
                                                     pad=4))

        cmc_thread.join()

        fig['layout'].update(images=[
            dict(source=f"{con.CMC_LOGO_URL_PARTIAL}{self.cmc_coin_id}.png",
                 opacity=0.8,
                 xref="paper",
                 yref="paper",
                 x=1.05,
                 y=1,
                 sizex=0.2,
                 sizey=0.2,
                 xanchor="right",
                 yanchor="bottom")
        ])

        self.send_photo(
            io.BufferedReader(BytesIO(pio.to_image(fig, format='jpeg'))),
            update, keywords)
コード例 #22
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        sub_cmd = args[0]

        if not sub_cmd:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        msg = str()

        try:
            res = CoinGecko().get_global()
        except Exception as e:
            return self.handle_error(e, update)

        # ---------- Total Market Capital ----------

        if sub_cmd.lower() == "mcap":
            m_cap_usd = utl.format(res["total_market_cap"]["usd"])
            m_cap_eur = utl.format(res["total_market_cap"]["eur"])

            msg = f"`Total Market Capital`\n" \
                  f"`USD: {m_cap_usd}`\n" \
                  f"`EUR: {m_cap_eur}`"

        # ---------- Total Volume ----------

        elif sub_cmd.lower() == "vol":
            vol_usd = utl.format(res["total_volume"]["usd"])
            vol_eur = utl.format(res["total_volume"]["eur"])

            msg = f"`Total Volume (24h)`\n" \
                  f"`USD: {vol_usd}`\n" \
                  f"`EUR: {vol_eur}`"

        # ---------- Dominance ----------

        elif sub_cmd.lower() == "dom":
            m_cap_per = res["market_cap_percentage"]

            labels = list()
            values = list()

            msg = "`Dominance (Market Capital)`\n"
            for key in sorted(m_cap_per, key=m_cap_per.get, reverse=True):
                labels.append(key.upper())
                values.append(m_cap_per[key])

                value = utl.format(m_cap_per[key],
                                   decimals=2,
                                   force_length=True)
                tst = "{:>13}".format(f"{value}%")
                tst = key.upper() + tst[len(key):]
                msg += f"`{tst}`\n"

            labels.append("[Other]")
            values.append(100 - sum(values))

            layout = go.Layout(paper_bgcolor='rgb(233,233,233)',
                               plot_bgcolor='rgb(233,233,233)',
                               autosize=True,
                               margin=go.layout.Margin(l=20,
                                                       r=20,
                                                       b=20,
                                                       t=20,
                                                       pad=4))

            try:
                trace = go.Pie(labels=labels, values=values)
                fig = go.Figure(data=[trace], layout=layout)
            except Exception as e:
                return self.handle_error(e, update)

            update.message.reply_photo(photo=io.BufferedReader(
                BytesIO(pio.to_image(fig, format="jpeg"))),
                                       caption=msg,
                                       parse_mode=ParseMode.MARKDOWN)

            return

        if not msg:
            msg = f"{emo.ERROR} Can't retrieve global data*"

        update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
コード例 #23
0
ファイル: trends.py プロジェクト: sohailkhan-project/crypto
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        tf = str()
        for arg in args:
            if arg.startswith("t="):
                tf = arg.replace("t=", "")
                args.remove(arg)
                break

        if tf:
            if tf != "all":
                from datetime import datetime
                now = datetime.today()
                date = utl.get_date(now, tf)

                if not date:
                    update.message.reply_text(
                        text=f"{emo.ERROR} Timeframe not formatted correctly",
                        parse_mode=ParseMode.MARKDOWN)
                    return
                else:
                    tf = f"{str(date)[:10]} {str(now)[:10]}"
        else:
            tf = self.DEFAULT_T

        # Check for brackets and combine keywords
        args = self._combine_args(args)

        if len(args) > 5:
            update.message.reply_text(
                text=
                f"{emo.ERROR} Not possible to provide more then 5 keywords",
                parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        try:
            pytrends = TrendReq(hl='en-US', tz=360)
            pytrends.build_payload(args, cat=0, timeframe=tf, geo='', gprop='')

            data = pytrends.interest_over_time()
        except Exception as e:
            return self.handle_error(e, update)

        no_data = list()
        tr_data = list()
        for kw in args:
            if data.empty:
                no_data = args
                break

            if data.get(kw).empty:
                no_data.append(kw)
                continue

            tr_data.append(
                go.Scatter(x=data.get(kw).index,
                           y=data.get(kw).values,
                           name=kw))

        if no_data:
            update.message.reply_text(
                text=
                f"{emo.ERROR} No data for keyword(s): {', '.join(no_data)}",
                parse_mode=ParseMode.MARKDOWN)

        if len(args) == len(no_data):
            return

        layout = go.Layout(title="Google Trends - Interest Over Time",
                           paper_bgcolor='rgb(233,233,233)',
                           plot_bgcolor='rgb(233,233,233)',
                           yaxis=dict(title="Queries", showticklabels=False),
                           showlegend=True)

        try:
            fig = go.Figure(data=tr_data, layout=layout)
        except Exception as e:
            return self.handle_error(e, update)

        update.message.reply_photo(photo=io.BufferedReader(
            BytesIO(pio.to_image(fig, format="jpeg"))),
                                   parse_mode=ParseMode.MARKDOWN)
コード例 #24
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(
                text=f"Usage:\n{self.get_usage()}",
                parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        vs_cur = "usd"

        if "-" in args[0]:
            pair = args[0].split("-", 1)
            vs_cur = pair[1].lower()
            coin = pair[0].upper()
        else:
            coin = args[0].upper()

        data = None

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        # Get coin ID and data
        for entry in response:
            if entry["symbol"].upper() == coin:
                try:
                    data = CoinGecko().get_coin_by_id(entry["id"])
                except Exception as e:
                    return self.handle_error(e, update)
                break

        if not data:
            update.message.reply_text(
                text=f"{emo.INFO} No data for *{coin}*",
                parse_mode=ParseMode.MARKDOWN)
            return

        name = data["name"]
        symbol = data["symbol"].upper()

        if data["market_data"]["price_change_percentage_1h_in_currency"]:
            c_1h = data["market_data"]["price_change_percentage_1h_in_currency"][vs_cur]
            c1h = utl.format(float(c_1h), decimals=2, force_length=True)
            h1 = "{:>10}".format(f"{c1h}%")
        else:
            h1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_24h_in_currency"]:
            c_1d = data["market_data"]["price_change_percentage_24h_in_currency"][vs_cur]
            c1d = utl.format(float(c_1d), decimals=2, force_length=True)
            d1 = "{:>10}".format(f"{c1d}%")
        else:
            d1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_7d_in_currency"]:
            c_1w = data["market_data"]["price_change_percentage_7d_in_currency"][vs_cur]
            c1w = utl.format(float(c_1w), decimals=2, force_length=True)
            w1 = "{:>10}".format(f"{c1w}%")
        else:
            w1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_30d_in_currency"]:
            c_1m = data["market_data"]["price_change_percentage_30d_in_currency"][vs_cur]
            c1m = utl.format(float(c_1m), decimals=2, force_length=True)
            m1 = "{:>10}".format(f"{c1m}%")
        else:
            m1 = "{:>10}".format("N/A")

        if data["market_data"]["price_change_percentage_1y_in_currency"]:
            c_1y = data["market_data"]["price_change_percentage_1y_in_currency"]["usd"]
            c1y = utl.format(float(c_1y), decimals=2, force_length=True)
            y1 = "{:>10}".format(f"{c1y}%")
        else:
            y1 = "{:>10}".format("N/A")

        update.message.reply_text(
            text=f"`"
                 f"{name} ({symbol}) in {vs_cur.upper()}\n\n"
                 f"Hour  {h1}\n"
                 f"Day   {d1}\n"
                 f"Week  {w1}\n"
                 f"Month {m1}\n"
                 f"Year  {y1}\n\n"
                 f"`",
            parse_mode=ParseMode.MARKDOWN,
            disable_web_page_preview=True)
コード例 #25
0
ファイル: volume.py プロジェクト: 7h3v01c3/OpenCryptoBot
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        msg = str()
        top = str()
        coin = str()
        vs_cur = "usd"

        if args[0].lower().startswith("top="):
            top = args[0][4:]

            if not top.isnumeric():
                update.message.reply_text(
                    text=f"{emo.ERROR} Value of `top` has to be a number",
                    parse_mode=ParseMode.MARKDOWN)
                return
            if int(top) > 100:
                update.message.reply_text(
                    text=f"{emo.ERROR} Max value for `top` is `100`",
                    parse_mode=ParseMode.MARKDOWN)
                return
        else:
            if "-" in args[0]:
                pair = args[0].split("-", 1)
                vs_cur = pair[0].lower()
                coin = pair[1].lower()
            else:
                coin = args[0].lower()

        if RateLimit.limit_reached(update):
            return

        # ---------- TOP VOLUME ----------

        if top:
            try:
                data = CoinGecko().get_coins_markets(vs_cur,
                                                     per_page=top,
                                                     page=1,
                                                     order="volume_desc",
                                                     sparkline=False)
            except Exception as e:
                return self.handle_error(e, update)

            count = 0
            for entry in data:
                count += 1

                name = entry["name"]
                symbol = entry["symbol"].upper()
                vol = utl.format(entry["total_volume"])

                msg += f"#{count} {name} ({symbol})\n" \
                       f"{vol} {vs_cur.upper()}\n\n"

            msg = f"Top {top} by Total Volume\n\n{msg}"

        # ---------- TOTAL VOLUME ----------

        else:
            data = None

            try:
                response = APICache.get_cg_coins_list()
            except Exception as e:
                return self.handle_error(e, update)

            # Get coin ID and data
            for entry in response:
                if entry["symbol"] == coin:
                    try:
                        data = CoinGecko().get_coins_markets(
                            vs_cur, ids=entry["id"], order="volume_desc")
                    except Exception as e:
                        return self.handle_error(e, update)
                    break

            if not data:
                update.message.reply_text(
                    text=f"{emo.ERROR} No data for *{coin}*",
                    parse_mode=ParseMode.MARKDOWN)
                return

            name = data[0]["name"]
            vol = utl.format(data[0]["total_volume"])

            msg = f"{name} ({coin.upper()})\n\n" \
                  f"Total Volume:\n" \
                  f"{vol} {vs_cur.upper()}"

        if not msg:
            msg = f"{emo.ERROR} Can't retrieve data for *{coin.upper()}*"

        update.message.reply_text(text=f"`{msg}`",
                                  parse_mode=ParseMode.MARKDOWN)
コード例 #26
0
    def get_action(self, bot, update, args):
        vs_cur = str()

        if not args:
            if update.message:
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
            return

        if "-" in args[0]:
            pair = args[0].split("-", 1)
            vs_cur = pair[0].upper()
            coin = pair[1].upper()
        else:
            coin = args[0].upper()

        exchange = str()
        if len(args) > 1:
            exchange = args[1]

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            self.handle_error(e, update)

        coin_id = str()
        for entry in response:
            if entry["symbol"].upper() == coin:
                coin_id = entry["id"]
                break

        if RateLimit.limit_reached(update):
            return

        cg = CoinGecko()
        msg = str()

        if exchange:
            try:
                result = cg.get_coin_by_id(coin_id)
            except Exception as e:
                self.handle_error(e, update)

            if result:
                vs_list = list()

                if vs_cur:
                    vs_list = vs_cur.split(",")

                for ticker in result["tickers"]:
                    if ticker["market"]["name"].upper() == exchange.upper():
                        base_coin = ticker["target"]
                        if vs_list:
                            if base_coin in vs_list:
                                price = utl.format(ticker["last"],
                                                   force_length=True)
                                msg += f"`{base_coin}: {price}`\n"
                        else:
                            price = utl.format(ticker["last"],
                                               force_length=True)
                            msg += f"`{base_coin}: {price}`\n"
        else:
            if not vs_cur:
                if coin == "BTC":
                    vs_cur = "ETH,USD,EUR"
                elif coin == "ETH":
                    vs_cur = "BTC,USD,EUR"
                else:
                    vs_cur = "BTC,ETH,USD,EUR"

            try:
                result = cg.get_simple_price(coin_id, vs_cur)
            except Exception as e:
                self.handle_error(e, update)

            if result:
                for symbol, price in next(iter(result.values())).items():
                    if symbol in utl.get_fiat_list():
                        if decimal.Decimal(
                                str(price)).as_tuple().exponent > -3:
                            price = utl.format(price,
                                               decimals=2,
                                               force_length=True)
                        else:
                            price = utl.format(price, force_length=True)
                    else:
                        price = utl.format(price, force_length=True)

                    msg += f"`{symbol.upper()}: {price}`\n"

        if msg:
            if exchange:
                msg = f"`Price of {coin} on {exchange.capitalize()}`\n\n" + msg
            else:
                msg = f"`Price of {coin}`\n\n" + msg
        else:
            msg = f"{emo.ERROR} Can't retrieve data for *{coin}*"

        if update.message:
            update.message.reply_text(text=msg, parse_mode=ParseMode.MARKDOWN)
        else:
            return msg
コード例 #27
0
    def get_action(self, bot, update, args):
        # TODO: Do this in every plugin
        keywords = utl.get_kw(args)
        arg_list = utl.del_kw(args)

        # TODO: Do this in most other plugins
        if not arg_list:
            if not keywords.get(Keyword.INLINE):
                update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                          parse_mode=ParseMode.MARKDOWN)
            return

        vs_cur = str()

        if "-" in arg_list[0]:
            pair = arg_list[0].split("-", 1)
            vs_cur = pair[1].upper()
            coin = pair[0].upper()
        else:
            coin = arg_list[0].upper()

        exchange = str()
        if len(arg_list) > 1:
            exchange = arg_list[1]

        try:
            response = APICache.get_cg_coins_list()
        except Exception as e:
            return self.handle_error(e, update)

        coin_id = str()
        coin_name = str()
        for entry in response:
            if entry["symbol"].upper() == coin:
                coin_id = entry["id"]
                coin_name = entry["name"]
                break

        if RateLimit.limit_reached(update):
            return

        cg = CoinGecko()
        msg = str()

        if exchange:
            try:
                result = cg.get_coin_by_id(coin_id)
            except Exception as e:
                return self.handle_error(e, update)

            if result:
                vs_list = list()

                if vs_cur:
                    vs_list = vs_cur.split(",")

                for ticker_len in result["tickers"]:
                    if ticker_len["market"]["name"].upper() == exchange.upper(
                    ):
                        if ticker_len["base"] != coin:
                            base_coin = ticker_len["base"]
                        else:
                            base_coin = ticker_len["target"]

                        if vs_list:
                            if base_coin in vs_list:
                                price = utl.format(ticker_len["last"],
                                                   force_length=True)
                                msg += f"`{base_coin}: {price}`\n"
                        else:
                            price = utl.format(ticker_len["last"],
                                               force_length=True)
                            msg += f"`{base_coin}: {price}`\n"
        else:
            if not vs_cur:
                if coin == "BTC":
                    vs_cur = "ETH,USD,EUR"
                elif coin == "ETH":
                    vs_cur = "BTC,USD,EUR"
                else:
                    vs_cur = "BTC,ETH,USD,EUR"

            try:
                result = cg.get_simple_price(coin_id, vs_cur)
            except Exception as e:
                return self.handle_error(e, update)

            if result:
                for symbol, price in next(iter(result.values())).items():
                    if symbol in utl.get_fiat_list():
                        if decimal.Decimal(
                                str(price)).as_tuple().exponent > -3:
                            price = utl.format(price,
                                               decimals=2,
                                               force_length=True)
                        else:
                            price = utl.format(price, force_length=True)
                    else:
                        price = utl.format(price, force_length=True)

                    msg += f"`{symbol.upper()}: {price}`\n"

        if msg:
            if exchange:
                ticker_len = 0
                for line in msg.split("\n"):
                    length = len(line[:line.find(":")])
                    if ticker_len < length:
                        ticker_len = length

                message = str()
                for line in msg.split("\n"):
                    if line:
                        lst = line.split(" ")
                        index = ticker_len + 2 + len(lst[1]) - len(lst[0])
                        price = "{1:>{0}}".format(index, lst[1])
                        message += f"{lst[0]}{price}\n"

                msg = f"`{coin} ({coin_name}) on {exchange.capitalize()}`\n\n" + message
            else:
                msg = f"`{coin} ({coin_name})`\n\n" + msg

            # Add link to source of data (CoinGecko)
            msg += f"\n[Details on CoinGecko]({self.CG_URL}{coin_id})"
        else:
            msg = f"{emo.ERROR} Can't retrieve data for *{coin}*"

        if keywords.get(Keyword.INLINE):
            return msg

        self.send_msg(msg, update, keywords)
コード例 #28
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()

        try:
            data = TokenStats().get_roi_for_symbol(coin)
        except Exception as e:
            self.handle_error(e, update)

        if not data:
            update.message.reply_text(
                text=f"{emo.INFO} No data found for {coin}",
                parse_mode=ParseMode.MARKDOWN)
            return

        msg = str(f"`Return on Investment for {coin}`\n\n")

        roi_usd_x = utl.format(data["roix_usd"],
                               decimals=2,
                               force_length=True,
                               on_none="-")
        roi_usd_x = "{:>10}".format(roi_usd_x)

        roi_btc_x = utl.format(data["roix_btc"],
                               decimals=2,
                               force_length=True,
                               on_none="-")
        roi_btc_x = "{:>10}".format(roi_btc_x)

        roi_eth_x = utl.format(data["roix_eth"],
                               decimals=2,
                               force_length=True,
                               on_none="-")
        roi_eth_x = "{:>10}".format(roi_eth_x)

        # If all values are the same then this means
        # that there was no ICO and thus no ROI available
        if roi_usd_x == roi_btc_x == roi_eth_x:
            update.message.reply_text(
                text=f"{emo.ERROR} No ROI data for {coin}",
                parse_mode=ParseMode.MARKDOWN)
            return

        if data["roix_usd"]:
            msg += f"`ROI USD: {roi_usd_x}x`\n"
        else:
            msg += f"`ROI USD:  {roi_usd_x}`\n"

        if data["roix_btc"]:
            msg += f"`ROI BTC: {roi_btc_x}x`\n"
        else:
            msg += f"`ROI BTC:  {roi_btc_x}`\n"

        if data["roix_eth"]:
            msg += f"`ROI ETH: {roi_eth_x}x`\n\n"
        else:
            msg += f"`ROI ETH:  {roi_eth_x}`\n\n"

        pre_p_usd = data["usd_price_at_presale"]
        pre_p_usd_f = utl.format(pre_p_usd,
                                 decimals=2,
                                 force_length=True,
                                 on_zero='-')

        pre_p_btc = data["btc_price_at_presale"]
        pre_p_btc_f = utl.format(pre_p_btc, decimals=8, on_zero='-')

        pre_p_eth = data["eth_price_at_presale"]
        pre_p_eth_f = utl.format(pre_p_eth, decimals=8, on_zero='-')

        msg += f"`Presale Price USD: {pre_p_usd_f}`\n"
        msg += f"`Presale Price BTC: {pre_p_btc_f}`\n"
        msg += f"`Presale Price ETH: {pre_p_eth_f}`\n\n"

        lnc_p_usd = data["usd_price_at_launch"]
        lnc_p_usd_f = utl.format(lnc_p_usd,
                                 decimals=2,
                                 force_length=True,
                                 on_zero='-')

        lnc_p_btc = data["btc_price_at_launch"]
        lnc_p_btc_f = utl.format(lnc_p_btc, decimals=8, on_zero='-')

        lnc_p_eth = data["eth_price_at_launch"]
        lnc_p_eth_f = utl.format(lnc_p_eth, decimals=8, on_zero='-')

        msg += f"`Launch Price USD:  {lnc_p_usd_f}`\n"
        msg += f"`Launch Price BTC:  {lnc_p_btc_f}`\n"
        msg += f"`Launch Price ETH:  {lnc_p_eth_f}`\n\n"

        cur_p_usd = data["current_usd_price"]
        cur_p_usd_f = utl.format(cur_p_usd,
                                 decimals=2,
                                 force_length=True,
                                 on_zero='-')

        cur_p_btc = data["current_btc_price"]
        cur_p_btc_f = utl.format(cur_p_btc, decimals=8, on_zero='-')

        cur_p_eth = data["current_eth_price"]
        cur_p_eth_f = utl.format(cur_p_eth, decimals=8, on_zero='-')

        msg += f"`Current Price USD: {cur_p_usd_f}`\n"
        msg += f"`Current Price BTC: {cur_p_btc_f}`\n"
        msg += f"`Current Price ETH: {cur_p_eth_f}`"

        update.message.reply_text(text=msg,
                                  parse_mode=ParseMode.MARKDOWN,
                                  disable_web_page_preview=True)
コード例 #29
0
    def get_action(self, bot, update, args):
        if not args:
            update.message.reply_text(text=f"Usage:\n{self.get_usage()}",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        if RateLimit.limit_reached(update):
            return

        coin = args[0].upper()

        try:
            type_thread = threading.Thread(target=self._get_coin_type,
                                           args=[coin])
            type_thread.start()

            coin_info = CryptoCompare().get_coin_general_info(coin, "USD")
        except Exception as e:
            return self.handle_error(e, update)

        if coin_info["Message"] != "Success" or not coin_info["Data"]:
            update.message.reply_text(text=f"{emo.ERROR} No data for *{coin}*",
                                      parse_mode=ParseMode.MARKDOWN)
            return

        name = coin_info["Data"][0]["CoinInfo"]["FullName"]
        image = f"{self.LOGO_URL_PARTIAL}{coin_info['Data'][0]['CoinInfo']['ImageUrl']}"
        algo = coin_info["Data"][0]["CoinInfo"]["Algorithm"]
        proof = coin_info["Data"][0]["CoinInfo"]["ProofType"]
        h_per_s = coin_info["Data"][0]["CoinInfo"]["NetHashesPerSecond"]
        block = coin_info["Data"][0]["CoinInfo"]["BlockNumber"]
        block_time = coin_info["Data"][0]["CoinInfo"]["BlockTime"]
        block_reward = coin_info["Data"][0]["CoinInfo"]["BlockReward"]

        type_thread.join()

        if self.coin_type:
            type = f"{self.coin_type}"

            if self.based_on:
                type += f" ({self.based_on})"

        else:
            type = str("-")

        if self.coin_type == self.TOKEN:
            msg = f"`" \
                  f"Name:         {name}\n" \
                  f"Ticker:       {coin}\n" \
                  f"Type:         {type}\n" \
                  f"`"
        else:
            msg = f"`" \
                  f"Name:         {name}\n" \
                  f"Ticker:       {coin}\n" \
                  f"Type:         {type}\n" \
                  f"Algorithm:    {algo}\n" \
                  f"Proof type:   {proof}\n" \
                  f"Hashes (sec): {utl.format(int(h_per_s))}\n" \
                  f"Block:        {block}\n" \
                  f"Block time:   {block_time}\n" \
                  f"Block reward: {block_reward}" \
                  f"`"

        update.message.reply_photo(photo=image,
                                   caption=msg,
                                   parse_mode=ParseMode.MARKDOWN)
コード例 #30
0
    def get_action(self, bot, update, args):
        symbol = str()
        filter = str()
        msg = str()

        data = None

        if not args:
            if RateLimit.limit_reached(update):
                return

            try:
                data = CryptoPanic(token=self._token).get_posts()
            except Exception as e:
                return self.handle_error(e, update)

            msg = f"<b>Current news</b>\n\n"
        else:
            for arg in args:
                if arg.lower().startswith("filter="):
                    filter = arg[7:]
                else:
                    symbol = arg

            if len(args) > 2:
                update.message.reply_text(
                    text=f"{emo.ERROR} Only two arguments allowed",
                    parse_mode=ParseMode.MARKDOWN)
                return
            if len(args) == 2 and (not symbol or not filter):
                update.message.reply_text(text=f"{emo.ERROR} Wrong arguments",
                                          parse_mode=ParseMode.MARKDOWN)
                return
            if filter and filter.lower() not in self.filters:
                update.message.reply_text(
                    text=f"{emo.ERROR} Wrong filter. Choose from: "
                    f"{', '.join(self.filters)}",
                    parse_mode=ParseMode.MARKDOWN)
                return

            if RateLimit.limit_reached(update):
                return

            try:
                if symbol and filter:
                    data = CryptoPanic(token=self._token).get_multiple_filters(
                        symbol, filter)
                    msg = f"<b>News for {symbol} and filter '{filter}'</b>\n\n"
                elif symbol:
                    data = CryptoPanic(
                        token=self._token).get_currency_news(symbol)
                    msg = f"<b>News for {symbol}</b>\n\n"
                elif filter:
                    data = CryptoPanic(
                        token=self._token).get_filtered_news(filter)
                    msg = f"<b>News for filter '{filter}</b>'\n\n"
            except Exception as e:
                return self.handle_error(e, update)

        if not data or not data["results"]:
            update.message.reply_text(
                text=f"{emo.ERROR} Couldn't retrieve news",
                parse_mode=ParseMode.MARKDOWN)
            return

        for news in reversed(data["results"]):
            if news["kind"] == "news":
                published = news["published_at"]
                domain = news["domain"]
                title = news["title"]
                url = news["url"]

                t = datetime.fromisoformat(published.replace("Z", "+00:00"))
                month = f"0{t.month}" if len(str(t.month)) == 1 else t.month
                day = f"0{t.day}" if len(str(t.day)) == 1 else t.day
                hour = f"0{t.hour}" if len(str(t.hour)) == 1 else t.hour
                minute = f"0{t.minute}" if len(str(
                    t.minute)) == 1 else t.minute

                msg += f'{t.year}-{month}-{day} {hour}:{minute} - {domain}\n' \
                       f'<a href="{url}">{title.strip()}</a>\n\n'

        update.message.reply_text(text=msg,
                                  parse_mode=ParseMode.HTML,
                                  disable_web_page_preview=True)