diff --git a/.gitignore b/.gitignore index c9ae237cbb7..ad895c01618 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ reports/* !notebooks/reports/.gitkeep .python-version exports/* +.idea diff --git a/exports/etf/movers/.gitkeep b/exports/etf/movers/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/exports/etf/screeners/.gitkeep b/exports/etf/screeners/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md index 07162e46ddf..59adaff809d 100644 --- a/gamestonk_terminal/README.md +++ b/gamestonk_terminal/README.md @@ -30,11 +30,11 @@ The main menu allows the following commands: ``` -usage: load [-t S_TICKER] [-s S_START_DATE] [-i {1,5,15,30,60}] [--source {yf,av,iex}] [-p] +usage: load [-t S_TICKER] [-s S_START_DATE] [-i {1,5,15,30,60}] [--source {yf,av,iex}] [-p] ``` * Load stock ticker to perform analysis on. When the data source is 'yf', an Indian ticker can be loaded by using '.NS' at the end, e.g. 'SBIN.NS'. See available market in . - * -t : Stock ticker + * -t : Stock ticker * -s : The starting date (format YYYY-MM-DD) of the stock * -i : Intraday stock minutes * --source : Source of historical data. 'yf' and 'av' available. Default 'yf' @@ -409,6 +409,13 @@ Command|Description|Source `fedfunds` | Effective Federal Funds Rate | `aaa` | Moody's Seasoned AAA Corporate Bond Yield | `dexcaus` | Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) | +`overview` | Market overview | +`indices` | US indices overview | +`futures` | Futures/commodities overview | +`us_bonds` | US bonds overview | +`gl_bonds` | Global bonds overview | +`currencies` | Global currencies overview | +   @@ -521,3 +528,6 @@ command|description `holdings`|show ETF holdings `compare`|compare multiple ETFs overview `screener`|screen ETFs +`gainers`|show top gainers +`decliners`|show top decliners +`active`|show most active diff --git a/gamestonk_terminal/economy/README.md b/gamestonk_terminal/economy/README.md index 57a908807ee..1e7be364752 100644 --- a/gamestonk_terminal/economy/README.md +++ b/gamestonk_terminal/economy/README.md @@ -31,10 +31,24 @@ This menu aims to assess economy data, and the usage of the following commands a * [dexcaus](#dexcaus) * Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) +[WSJ](#wsj) +* [overview](#overview) + * Get market overview +* [indices](#indices) + * Get us major indices overview +* [futures](#futures) + * Get top futures overview +* [us_bonds](#us_bonds) + * Get us bonds overview +* [gl_bonds](#gl_bonds) + * Get global bonds overview +* [currencies](#currencies) + * Get global currency overview + ## feargreed ```text -usage: feargreed [-i {jbd,mv,pco,mm,sps,spb,shd,index}] +usage: feargreed [-i {jbd,mv,pco,mm,sps,spb,shd,index}] ``` Display CNN Fear And Greed Index from https://money.cnn.com/data/fear-and-greed/. @@ -212,3 +226,42 @@ Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) * -t : Only output text data. ![dexcaus](https://user-images.githubusercontent.com/25267873/116769155-10b02c80-aa32-11eb-8ece-d8e92b8df1af.png) + +# WSJ +The following functions are meant to take the information from the [WSJ Market Data Page](https://www.wsj.com/market-data) + +## overview +```python +usage: overview +``` +Market overview + +## indices +```python +usage: indices +``` +US indices overview + +## futures +```python +usage: futures +``` +Top futures/commodities overview + +## us_bonds +```python +usage: us_bonds +``` +US bonds overview + +## gl_bonds +```python +usage: gl_bonds +``` +Global bonds overview + +## currencies +```python +usage: currencies +``` +Global currencies overview diff --git a/gamestonk_terminal/economy/econ_controller.py b/gamestonk_terminal/economy/econ_controller.py index a915a8a8934..70783f88616 100644 --- a/gamestonk_terminal/economy/econ_controller.py +++ b/gamestonk_terminal/economy/econ_controller.py @@ -11,6 +11,7 @@ from gamestonk_terminal.menu import session from gamestonk_terminal.economy import fred_view from gamestonk_terminal.economy import finnhub_view from gamestonk_terminal.economy import cnn_view +from gamestonk_terminal.economy import wsj_view class EconomyController: @@ -37,6 +38,13 @@ class EconomyController: "aaa", "dexcaus", "feargreed", + "overview", + "indices", + "futures", + "us_bonds", + "gl_bonds", + "futures", + "currencies", ] def __init__(self): @@ -76,6 +84,14 @@ class EconomyController: print(" aaa Moody's Seasoned AAA Corporate Bond Yield") print(" dexcaus Canada / U.S. Foreign Exchange Rate (CAD per 1 USD)") print("") + print("Wall St. Journal:") + print(" overview market data overview") + print(" indices us indices overview") + print(" futures futures overview") + print(" us_bonds us bond overview") + print(" gl_bonds global bonds overview") + print(" currencies currency overview") + print("") return def switch(self, an_input: str): @@ -178,6 +194,30 @@ class EconomyController: """Process feargreed command""" cnn_view.fear_and_greed_index(other_args) + def call_overview(self, other_args: List[str]): + """Process overview command""" + wsj_view.display_overview(other_args) + + def call_indices(self, other_args: List[str]): + """Process indices command""" + wsj_view.display_indices(other_args) + + def call_futures(self, other_args: List[str]): + """Process futures command""" + wsj_view.display_futures(other_args) + + def call_us_bonds(self, other_args: List[str]): + """Process us_bonds command""" + wsj_view.display_usbonds(other_args) + + def call_gl_bonds(self, other_args: List[str]): + """Process gl_bonds command""" + wsj_view.display_glbonds(other_args) + + def call_currencies(self, other_args: List[str]): + """Process curremcies command""" + wsj_view.display_currencies(other_args) + def menu(): """Econ Menu""" diff --git a/gamestonk_terminal/economy/wsj_model.py b/gamestonk_terminal/economy/wsj_model.py new file mode 100644 index 00000000000..977980ac043 --- /dev/null +++ b/gamestonk_terminal/economy/wsj_model.py @@ -0,0 +1,218 @@ +"""WSJ model""" +__docformat__ = "numpy" +import requests +import pandas as pd + + +def us_indices() -> pd.DataFrame: + """ + Get the top US indices + Returns + ------- + indices: pd.DataFrame + Dataframe containing name, price, net change and percent change + """ + data = requests.get( + "https://www.wsj.com/market-data/stocks?id=%7B%22application%22%3A%22WSJ%22%2C%22instruments%22%3A%5B%7B" + "%22symbol%22%3A%22INDEX%2FUS%2F%2FDJIA%22%2C%22name%22%3A%22DJIA%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F" + "%2FCOMP%22%2C%22name%22%3A%22Nasdaq%20Composite%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FSPX%22%2C%22name" + "%22%3A%22S%26P%20500%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FDWCF%22%2C%22name%22%3A%22DJ%20Total%20Stock" + "%20Market%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FRUT%22%2C%22name%22%3A%22Russell%202000%22%7D%2C%7B" + "%22symbol%22%3A%22INDEX%2FUS%2F%2FNYA%22%2C%22name%22%3A%22NYSE%20Composite%22%7D%2C%7B%22symbol%22%3A%22INDEX" + "%2FUS%2F%2FB400%22%2C%22name%22%3A%22Barron%27s%20400%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FVIX%22%2C%22" + "name%22%3A%22CBOE%20Volatility%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2FDJIA%20FUTURES%22%2C%22name%22%3A%" + "22DJIA%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2FS%26P%20500%20FUTURES%22%2C%22name%22%3A%22S%26P" + "%20500%20Futures%22%7D%5D%7D&type=mdc_quotes", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + + name, last_price, net_change, percent_change = [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["formattedName"]) + last_price.append(entry["lastPrice"]) + net_change.append(entry["priceChange"]) + percent_change.append(entry["percentChange"]) + + indices = pd.DataFrame( + {" ": name, "Price": last_price, "Chg": net_change, "%Chg": percent_change} + ) + + return indices + + +def market_overview() -> pd.DataFrame: + """ + Scrape data for market overview + Returns + ------- + overview: pd.DataFrame + Dataframe containing name, price, net change and percent change + """ + data = requests.get( + "https://www.wsj.com/market-data?id=%7B%22application%22%3A%22WSJ%22%2C%22instruments%22%3A%5B%7B%22symbol%22" + "%3A%22INDEX%2FUS%2F%2FDJIA%22%2C%22name%22%3A%22DJIA%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FSPX%22%2C%22" + "name%22%3A%22S%26P%20500%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FUS%2F%2FCOMP%22%2C%22name%22%3A%22Nasdaq%20" + "Composite%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FJP%2F%2FNIK%22%2C%22name%22%3A%22Japan%3A%20Nikkei%20225%22%7D%" + "2C%7B%22symbol%22%3A%22INDEX%2FUK%2F%2FUKX%22%2C%22name%22%3A%22UK%3A%20FTSE%20100%22%7D%2C%7B%22symbol%22%3A%" + "22FUTURE%2FUS%2F%2FCRUDE%20OIL%20-%20ELECTRONIC%22%2C%22name%22%3A%22Crude%20Oil%20Futures%22%7D%2C%7B%22symbol" + "%22%3A%22FUTURE%2FUS%2F%2FGOLD%22%2C%22name%22%3A%22Gold%20Futures%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2" + "F%2FUSDJPY%22%2C%22name%22%3A%22Yen%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FEURUSD%22%2C%22name%22%3A%" + "22Euro%22%7D%5D%7D&type=mdc_quotes", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + name, last_price, net_change, percent_change = [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["formattedName"]) + last_price.append(entry["lastPrice"]) + net_change.append(entry["priceChange"]) + percent_change.append(entry["percentChange"]) + + overview = pd.DataFrame( + {" ": name, "Price": last_price, "Chg": net_change, "%Chg": percent_change} + ) + + return overview + + +def top_commodities() -> pd.DataFrame: + """ + Scrape data for top commodities + Returns + ------- + commodities: pd.DataFrame + Dataframe containing name, price, net change and percent change + """ + data = requests.get( + "https://www.wsj.com/market-data/commodities?id=%7B%22application%22%3A%22WSJ%22%2C%22instruments%22%3A%5B%7" + "B%22symbol%22%3A%22FUTURE%2FUS%2F%2FCRUDE%20OIL%20-%20ELECTRONIC%22%2C%22name%22%3A%22Crude%20Oil%20Futures" + "%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUK%2F%2FBRENT%20CRUDE%22%2C%22name%22%3A%22Brent%20Crude%20Futures%22" + "%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2FGOLD%22%2C%22name%22%3A%22Gold%20Futures%22%7D%2C%7B%22symbol%22%" + "3A%22FUTURE%2FUS%2F%2FSILVER%22%2C%22name%22%3A%22Silver%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F" + "%2FNATURAL%20GAS%22%2C%22name%22%3A%22Natural%20Gas%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2" + "FUNLEADED%20GASOLINE%22%2C%22name%22%3A%22Unleaded%20Gasoline%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%" + "2FUS%2F%2FCOPPER%22%2C%22name%22%3A%22Copper%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2FCORN%22%2" + "C%22name%22%3A%22Corn%20Futures%22%7D%2C%7B%22symbol%22%3A%22FUTURE%2FUS%2F%2FWHEAT%22%2C%22name%22%3A%22Wheat" + "%20Futures%22%7D%2C%7B%22symbol%22%3A%22INDEX%2FXX%2F%2FBCOM%22%7D%5D%7D&type=mdc_quotes", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + name, last_price, net_change, percent_change = [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["formattedName"]) + last_price.append(entry["lastPrice"]) + net_change.append(entry["priceChange"]) + percent_change.append(entry["percentChange"]) + + commodities = pd.DataFrame( + {" ": name, "Price": last_price, "Chg": net_change, "%Chg": percent_change} + ) + + return commodities + + +def us_bonds() -> pd.DataFrame: + """ + Scrape data for us bonds + Returns + ------- + bonds: pd.DataFrame + Dataframe containing name, coupon rate, yield and change in yield + """ + + data = requests.get( + "https://www.wsj.com/market-data?id=%7B%22application%22%3A%22WSJ%22%2C%22instruments%22%3A%5B" + "%7B%22symbol%22%3A%22BOND%2FBX%2F%2FTMUBMUSD30Y%22%2C%22name%22%3A%2230-Year%20Bond%22%7D%2C%7" + "B%22symbol%22%3A%22BOND%2FBX%2F%2FTMUBMUSD10Y%22%2C%22name%22%3A%2210-Year%20Note%22%7D%2C%7B%2" + "2symbol%22%3A%22BOND%2FBX%2F%2FTMUBMUSD07Y%22%2C%22name%22%3A%227-Year%20Note%22%7D%2C%7B%22sym" + "bol%22%3A%22BOND%2FBX%2F%2FTMUBMUSD05Y%22%2C%22name%22%3A%225-Year%20Note%22%7D%2C%7B%22symbol" + "%22%3A%22BOND%2FBX%2F%2FTMUBMUSD03Y%22%2C%22name%22%3A%223-Year%20Note%22%7D%2C%7B%22symbol%22%" + "3A%22BOND%2FBX%2F%2FTMUBMUSD02Y%22%2C%22name%22%3A%222-Year%20Note%22%7D%2C%7B%22symbol%22%3A%" + "22BOND%2FBX%2F%2FTMUBMUSD01Y%22%2C%22name%22%3A%221-Year%20Bill%22%7D%2C%7B%22symbol%22%3A%22" + "BOND%2FBX%2F%2FTMUBMUSD06M%22%2C%22name%22%3A%226-Month%20Bill%22%7D%2C%7B%22symbol%22%3A%22BON" + "D%2FBX%2F%2FTMUBMUSD03M%22%2C%22name%22%3A%223-Month%20Bill%22%7D%2C%7B%22symbol%22%3A%22BOND%" + "2FBX%2F%2FTMUBMUSD01M%22%2C%22name%22%3A%221-Month%20Bill%22%7D%5D%7D&type=mdc_quotes", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + name, yield_pct, rate, yld_chng = [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["formattedName"]) + yield_pct.append(entry["bond"]["yield"]) + rate.append(entry["bond"]["couponRate"]) + yld_chng.append(entry["bond"]["yieldChange"]) + + bonds = pd.DataFrame( + {" ": name, "Rate (%)": rate, "Yld (%)": yield_pct, "Yld Chg (%)": yld_chng} + ) + return bonds + + +def global_bonds() -> pd.DataFrame: + """ + Scrape data for global bonds + Returns + ------- + bonds: pd.DataFrame + Dataframe containing name, coupon rate, yield and change in yield + """ + data = requests.get( + "https://www.wsj.com/market-data?id=%7B%22application%22%3A%22WSJ%22%2C%22bonds%22%3A%5" + "B%7B%22symbol%22%3A%22TMUBMUSD10Y%22%2C%22name%22%3A%22U.S.%2010%20Year%22%7D%2C%7B%22symbol" + "%22%3A%22TMBMKDE-10Y%22%2C%22name%22%3A%22Germany%2010%20Year%22%7D%2C%7B%22symbol%22%3A%22TMB" + "MKGB-10Y%22%2C%22name%22%3A%22U.K.%2010%20Year%22%7D%2C%7B%22symbol%22%3A%22TMBMKJP-10Y%22%2C%" + "22name%22%3A%22Japan%2010%20Year%22%7D%2C%7B%22symbol%22%3A%22TMBMKAU-10Y%22%2C%22name%22%3A%2" + "2Australia%2010%20Year%22%7D%2C%7B%22symbol%22%3A%22AMBMKRM-10Y%22%2C%22name%22%3A%22China%2010" + "%20Year%22%7D%5D%7D&type=mdc_governmentbonds", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + name, yield_pct, rate, yld_chng = [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["djLegalName"]) + yield_pct.append(entry["yieldPercent"]) + rate.append(entry["couponPercent"]) + yld_chng.append(entry["yieldChange"]) + + bonds = pd.DataFrame( + {" ": name, "Rate (%)": rate, "Yld (%)": yield_pct, "Yld Chg (%)": yld_chng} + ) + return bonds + + +def global_currencies() -> pd.DataFrame: + """ + Scrape data for global currencies + Returns + ------- + currencies: pd.DataFrame + Dataframe containing name, price, net change and percent change + """ + data = requests.get( + "https://www.wsj.com/market-data?id=%7B%22application%22%3A%22WSJ%22%2C%22instruments%22%3A%5" + "B%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FEURUSD%22%2C%22name%22%3A%22Euro%20(EUR%2FUSD)%22%7D%" + "2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FUSDJPY%22%2C%22name%22%3A%22Japanese%20Yen%20(USD%2F" + "JPY)%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FGBPUSD%22%2C%22name%22%3A%22U.K.%20Poun" + "d%20(GBP%2FUSD)%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FUSDCHF%22%2C%22name%22%3A%22Sw" + "iss%20Franc%20(USD%2FCHF)%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FUSDCNY%22%2C%22name%2" + "2%3A%22Chinese%20Yuan%20(USD%2FCNY)%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2FUSDCAD%22%2C" + "%22name%22%3A%22Canadian%20%24%20(USD%2FCAD)%22%7D%2C%7B%22symbol%22%3A%22CURRENCY%2FUS%2F%2F" + "USDMXN%22%2C%22name%22%3A%22Mexican%20Peso%20(USD%2FMXN)%22%7D%2C%7B%22symbol%22%3A%22CRYPTO" + "CURRENCY%2FUS%2F%2FBTCUSD%22%2C%22name%22%3A%22Bitcoin%20(BTC%2FUSD)%22%7D%2C%7B%22symbol%22%3A" + "%22INDEX%2FXX%2F%2FBUXX%22%2C%22name%22%3A%22WSJ%20Dollar%20Index%22%7D%2C%7B%22symbol%22%3A%2" + "2INDEX%2FUS%2F%2FDXY%22%2C%22name%22%3A%22U.S.%20Dollar%20Index%22%7D%5D%7D&type=mdc_quotes", + headers={"User-Agent": "Mozilla/5.0"}, + ).json() + + name, last_price, price_change, pct_change = [], [], [], [] + for entry in data["data"]["instruments"]: + name.append(entry["formattedName"]) + last_price.append(entry["lastPrice"]) + price_change.append(entry["priceChange"]) + pct_change.append(entry["percentChange"]) + + currencies = pd.DataFrame( + {" ": name, "Last": last_price, "Chng": price_change, "%Chng": pct_change} + ) + return currencies diff --git a/gamestonk_terminal/economy/wsj_view.py b/gamestonk_terminal/economy/wsj_view.py new file mode 100644 index 00000000000..be977b230b6 --- /dev/null +++ b/gamestonk_terminal/economy/wsj_view.py @@ -0,0 +1,202 @@ +"""WSJ view """ +__docformat__ = "numpy" + +import argparse +from typing import List +from tabulate import tabulate + +from gamestonk_terminal.economy.wsj_model import ( + market_overview, + us_bonds, + us_indices, + global_bonds, + global_currencies, + top_commodities, +) +from gamestonk_terminal.helper_funcs import parse_known_args_and_warn + + +def display_overview(other_args: List[str]): + """ + Display market overview + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="overview", description="WSJ market overview", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = market_overview() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") + + +def display_indices(other_args: List[str]): + """ + Display us indices + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="indices", description="WSJ US Indices", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = us_indices() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") + + +def display_futures(other_args: List[str]): + """ + Display futures/commodities + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="futures", description="WSJ futures/commodities", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = top_commodities() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") + + +def display_usbonds(other_args: List[str]): + """ + Display us bonds overview + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="usbonds", description="WSJ US Bonds overview", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = us_bonds() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") + + +def display_glbonds(other_args: List[str]): + """ + Display global bond overview + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="glbond", description="WSJ global bond overview", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = global_bonds() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") + + +def display_currencies(other_args: List[str]): + """ + Display global currencies + + Parameters + ---------- + other_args: List[str] + Argparse arguments + """ + parser = argparse.ArgumentParser( + prog="currencies", description="WSJ currency overview", add_help=False + ) + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = global_currencies() + print( + tabulate( + data, + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + print("") + except Exception as e: + print(e, "\n") diff --git a/gamestonk_terminal/etf/README.md b/gamestonk_terminal/etf/README.md index f1eb770d0c6..84023883c9d 100644 --- a/gamestonk_terminal/etf/README.md +++ b/gamestonk_terminal/etf/README.md @@ -16,6 +16,14 @@ Data is currently scraped from StockAnalysis.com/etf * [screener](#screener) * screen ETFs +[WSJ](#WSJ) +* [gainers](#gainers) + * show top gainers +* [decliners](#decliners) + * show top decliners +* [active](#active) + * show most active + ## web ```python usage: web @@ -160,3 +168,32 @@ ETFs downloaded │ XLU │ 64.52 │ 11640 │ 64.31 │ 0.12 │ 19.94 │ 0.35 │ 1.98 │ 3.07 │ ╘═════╧═════════╧══════════╧═══════╧═══════════╧═══════╧════════╧═══════╧════════════╛ ``` +# WSJ +The following functions atake the information from the [WSJ Market Data Page](https://www.wsj.com/market-data) + +## gainers + +```python +usage: gainers [-n NUM] [--export {csv,json,xlsx}] [-h] +``` +Shows top gaining ETFs +* -n/--num: Number to show. Defaults to 25, which is the max provided +* --export: Export data to one of {csv, json, xlsx}. + +## decliners + +```python +usage: decliners [-n NUM] [--export {csv,json,xlsx}] [-h] +``` +Shows highest declining ETFs +* -n/--num: Number to show. Defaults to 25, which is the max provided +* --export: Export data to one of {csv, json, xlsx}. + +## active + +```python +usage: active [-n NUM] [--export {csv,json,xlsx}] [-h] +``` +Shows most active ETFs +* -n/--num: Number to show. Defaults to 25, which is the max provided +* --export: Export data to one of {csv, json, xlsx}. diff --git a/gamestonk_terminal/etf/etf_controller.py b/gamestonk_terminal/etf/etf_controller.py index 351f860dc00..f76af703ae1 100644 --- a/gamestonk_terminal/etf/etf_controller.py +++ b/gamestonk_terminal/etf/etf_controller.py @@ -17,6 +17,7 @@ from gamestonk_terminal.etf.stockanalysis_model import ( etf_holdings, ) from gamestonk_terminal.etf.screener_model import etf_screener +from gamestonk_terminal.etf import wsj_view class ETFController: @@ -32,6 +33,9 @@ class ETFController: "compare", "holdings", "screener", + "gainers", + "decliners", + "active", ] def __init__(self): @@ -57,6 +61,10 @@ class ETFController: print(" holdings get top holdings for ETF") print(" compare compare overview of multiple ETF") print(" screener screen etfs based on overview data") + print("\n Wall St. Journal") + print(" gainers show top gainers") + print(" decliners show top decliners") + print(" active show most active") print("") def switch(self, an_input: str): @@ -127,6 +135,18 @@ class ETFController: """Process screener command""" etf_screener(other_args) + def call_gainers(self, other_args): + """Process gainers command""" + wsj_view.show_top_mover("gainers", other_args) + + def call_decliners(self, other_args): + """Process decliners command""" + wsj_view.show_top_mover("decliners", other_args) + + def call_active(self, other_args): + """Process gainers command""" + wsj_view.show_top_mover("active", other_args) + def menu(): etf_controller = ETFController() diff --git a/gamestonk_terminal/etf/screener_model.py b/gamestonk_terminal/etf/screener_model.py index ff4fef68a4d..99c2a1da539 100644 --- a/gamestonk_terminal/etf/screener_model.py +++ b/gamestonk_terminal/etf/screener_model.py @@ -183,7 +183,7 @@ def etf_screener(other_args: List[str]): export_data( ns_parser.export, - os.path.dirname(os.path.abspath(__file__)), + os.path.join(os.path.dirname(os.path.abspath(__file__)), "screeners"), param_string, df, ) diff --git a/gamestonk_terminal/etf/wsj_model.py b/gamestonk_terminal/etf/wsj_model.py new file mode 100644 index 00000000000..9a079eae03c --- /dev/null +++ b/gamestonk_terminal/etf/wsj_model.py @@ -0,0 +1,57 @@ +"""WSJ model""" +__docformat__ = "numpy" +import requests +import pandas as pd + + +def etf_movers(sort_type: str = "gainers") -> pd.DataFrame: + """ + Scrape data for top etf movers. + Parameters + ---------- + sort_type: str + Data to get. Can be "gainers", "decliners" or "activity + + Returns + ------- + etfmovers: pd.DataFrame + Datafame containing the name, price, change and the volume of the etf + """ + + if sort_type == "gainers": + url = ( + "https://www.wsj.com/market-data/mutualfunds-etfs/etfmovers?id=%7B%22application" + "%22%3A%22WSJ%22%2C%22etfMover%22%3A%22leaders%22%2C%22count%22%3A25%7D&type=mdc_etfmovers" + ) + elif sort_type == "decliners": + url = ( + "https://www.wsj.com/market-data/mutualfunds-etfs/etfmovers?id=%7B%22application" + "%22%3A%22WSJ%22%2C%22etfMover%22%3A%22laggards%22%2C%22count%22%3A25%7D&type=mdc_etfmovers" + ) + elif sort_type == "active": + url = ( + "https://www.wsj.com/market-data/mutualfunds-etfs/etfmovers?id=%7B%22application" + "%22%3A%22WSJ%22%2C%22etfMover%22%3A%22most_active%22%2C%22count%22%3A25%7D&type=mdc_etfmovers" + ) + + data = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}).json() + name, last_price, net_change, percent_change, volume = [], [], [], [], [] + + for entry in data["data"]["instruments"]: + name.append(entry["name"]) + last_price.append(entry["lastPrice"]) + net_change.append(entry["priceChange"]) + percent_change.append(entry["percentChange"]) + volume.append(entry["formattedVolume"]) + + etfmovers = pd.DataFrame( + { + " ": name, + "Price": last_price, + "Chg": net_change, + "%Chg": percent_change, + "Vol": volume, + } + ) + + return etfmovers diff --git a/gamestonk_terminal/etf/wsj_view.py b/gamestonk_terminal/etf/wsj_view.py new file mode 100644 index 00000000000..ca39397905d --- /dev/null +++ b/gamestonk_terminal/etf/wsj_view.py @@ -0,0 +1,63 @@ +"""WSJ view""" +__docformat__ = "numpy" + +import argparse +from typing import List +import os +from tabulate import tabulate + +from gamestonk_terminal.etf import wsj_model +from gamestonk_terminal.helper_funcs import parse_known_args_and_warn, export_data + + +def show_top_mover(sort_type: str, other_args: List[str]): + """ + Show top ETF movers from wsj.com + Parameters + ---------- + sort_type: str + What to show. Either Gainers, Decliners or Activity + other_args: List[str] + Argparse arguments + + """ + + parser = argparse.ArgumentParser( + prog="etfmovers", + description="Displays top ETF/Mutual fund movers from wsj.com/market-data", + add_help=False, + ) + parser.add_argument("-n", help="Number to show", type=int, default=25, dest="num") + + parser.add_argument( + "--export", + choices=["csv", "json", "xlsx"], + default="", + dest="export", + help="Export dataframe data to csv,json,xlsx file", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + data = wsj_model.etf_movers(sort_type) + print( + tabulate( + data.iloc[: ns_parser.num], + showindex=False, + headers=data.columns, + floatfmt=".2f", + tablefmt="fancy_grid", + ) + ) + export_data( + ns_parser.export, + os.path.join(os.path.dirname(os.path.abspath(__file__)), "movers"), + sort_type, + data, + ) + print("") + + except Exception as e: + print(e, "\n") diff --git a/poetry.lock b/poetry.lock index 32eed692cbd..d5fef8979e8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3119,6 +3119,10 @@ argon2-cffi = [ {file = "argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:9dfd5197852530294ecb5795c97a823839258dfd5eb9420233c7cfedec2058f2"}, {file = "argon2_cffi-20.1.0-cp39-cp39-win32.whl", hash = "sha256:e2db6e85c057c16d0bd3b4d2b04f270a7467c147381e8fd73cbbe5bc719832be"}, {file = "argon2_cffi-20.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a84934bd818e14a17943de8099d41160da4a336bcc699bb4c394bbb9b94bd32"}, + {file = "argon2_cffi-20.1.0-pp36-pypy36_pp73-macosx_10_7_x86_64.whl", hash = "sha256:b94042e5dcaa5d08cf104a54bfae614be502c6f44c9c89ad1535b2ebdaacbd4c"}, + {file = "argon2_cffi-20.1.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:8282b84ceb46b5b75c3a882b28856b8cd7e647ac71995e71b6705ec06fc232c3"}, + {file = "argon2_cffi-20.1.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3aa804c0e52f208973845e8b10c70d8957c9e5a666f702793256242e9167c4e0"}, + {file = "argon2_cffi-20.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:36320372133a003374ef4275fbfce78b7ab581440dfca9f9471be3dd9a522428"}, ] astroid = [ {file = "astroid-2.6.2-py3-none-any.whl", hash = "sha256:606b2911d10c3dcf35e58d2ee5c97360e8477d7b9f3efc3f24811c93e6fc2cd9"}, @@ -3243,8 +3247,8 @@ chardet = [ {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.1.tar.gz", hash = "sha256:ad0da505736fc7e716a8da15bf19a985db21ac6415c26b34d2fafd3beb3d927e"}, - {file = "charset_normalizer-2.0.1-py3-none-any.whl", hash = "sha256:b68b38179052975093d71c1b5361bf64afd80484697c1f27056e50593e695ceb"}, + {file = "charset-normalizer-2.0.3.tar.gz", hash = "sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12"}, + {file = "charset_normalizer-2.0.3-py3-none-any.whl", hash = "sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1"}, ] click = [ {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, @@ -3281,6 +3285,8 @@ cssselect = [ {file = "cssselect-1.1.0.tar.gz", hash = "sha256:f95f8dedd925fd8f54edb3d2dfb44c190d9d18512377d3c1e2388d16126879bc"}, ] cvxpy = [ + {file = "cvxpy-1.1.12-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:48e9bae36a43453659ca5d0c85e78f1eb0dfe629b8aa0f023f65aa59d0ac04d7"}, + {file = "cvxpy-1.1.12-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fe0bcb7f83b5d4deb760bf033cb72ab97c8e0770b116e08d96e9726cb1a52c01"}, {file = "cvxpy-1.1.12-cp36-cp36m-win_amd64.whl", hash = "sha256:86f8e4aa1a79482431b89aa526249d9fda04c74e04a3ec224d1175d281643d71"}, {file = "cvxpy-1.1.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:90b09a7361b9c614166fa673e1fe9321317df6939135330e1621b9a0bf10e3a8"}, {file = "cvxpy-1.1.12-cp37-cp37m-win_amd64.whl", hash = "sha256:084e5292f2a13133a1cd28d68f5af1df33a5119b0f1aec7cecf834eea3e2d11d"}, @@ -3288,6 +3294,8 @@ cvxpy = [ {file = "cvxpy-1.1.12-cp38-cp38-win_amd64.whl", hash = "sha256:76d04444cb50ad2840bbc72a625ac246b5eeeeb580ee20c71bec057822667738"}, {file = "cvxpy-1.1.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2de5e0e75316839bc71b5df2c2db0131cee7ef06dac566c6c44dc852c091502b"}, {file = "cvxpy-1.1.12-cp39-cp39-win_amd64.whl", hash = "sha256:9fa4d033ab31855aea090e4b358017b36880390a7d0e6e97ecc5226c77eab489"}, + {file = "cvxpy-1.1.12-py3.5-macosx-10.9-x86_64.egg", hash = "sha256:27ff263c80700b097d3714ba34161bd284f736f3029dfa89a95bf4c4a2801cb9"}, + {file = "cvxpy-1.1.12-py3.6-macosx-10.7-x86_64.egg", hash = "sha256:7c1c5371dda78580f0892fba6776abb6e43bdb45589311c3179a057f1a984110"}, {file = "cvxpy-1.1.12-py3.6-win-amd64.egg", hash = "sha256:d2c28e0eea1b6dc70262c9ed8b63c5c1747d85c28b3ec24cbaab07583b3ad729"}, {file = "cvxpy-1.1.12-py3.7-win-amd64.egg", hash = "sha256:44d0e3d60693831ac70bdc9b2e23faf84401347bfcdef4eb5da5ae22ac57f5ff"}, {file = "cvxpy-1.1.12-py3.8-win-amd64.egg", hash = "sha256:c86f8de9a63ccbd45844a4482df8099824688b5329060f089aad1c3beb939190"}, @@ -3700,30 +3708,40 @@ lxml = [ {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16"}, {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"}, {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"}, {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617"}, {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"}, {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"}, {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92"}, {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"}, {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"}, {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"}, {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"}, {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e"}, {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae"}, {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"}, {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"}, {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"}, {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"}, {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59"}, {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a"}, {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"}, {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"}, {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, @@ -4206,9 +4224,13 @@ protobuf = [ {file = "protobuf-3.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1"}, {file = "protobuf-3.17.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d"}, + {file = "protobuf-3.17.3-cp38-cp38-win32.whl", hash = "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1"}, + {file = "protobuf-3.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2"}, {file = "protobuf-3.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539"}, {file = "protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47"}, + {file = "protobuf-3.17.3-cp39-cp39-win32.whl", hash = "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554"}, + {file = "protobuf-3.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d"}, {file = "protobuf-3.17.3-py2.py3-none-any.whl", hash = "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e"}, {file = "protobuf-3.17.3.tar.gz", hash = "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b"}, ] @@ -4382,18 +4404,26 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},