diff --git a/.github/workflows/Mac.yml b/.github/workflows/Mac.yml
index 75a8a6f540b..b83ed2eedfd 100644
--- a/.github/workflows/Mac.yml
+++ b/.github/workflows/Mac.yml
@@ -2,6 +2,7 @@ name: Mac OS X Full Clean Build with ML
env:
GTFF_USE_PROMPT_TOOLKIT: false
GTFF_USE_ION: false
+ GTFF_ENABLE_QUICK_EXIT: true
on:
push:
branches:
@@ -47,6 +48,7 @@ jobs:
run: |
conda install numpy=1.19.5
conda install gensim=3.8.3
+ conda install -c conda-forge cvxpy
- name: Install dependencies (Bash)
shell: bash -l {0}
@@ -63,3 +65,7 @@ jobs:
- name: Run tests (Bash)
shell: bash -l {0}
run: pytest tests/
+
+ - name: Start Terminal and exit
+ shell: bash -l {0}
+ run: python terminal.py
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 17f52d31bea..52d673da809 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,6 +2,7 @@ name: Tests
env:
GTFF_USE_PROMPT_TOOLKIT: false
GTFF_USE_ION: false
+ GTFF_ENABLE_QUICK_EXIT: true
on: [pull_request, push]
jobs:
linting:
@@ -31,7 +32,8 @@ jobs:
- run: mypy --ignore-missing-imports .
- run: shopt -s globstar && pyupgrade --py36-plus **/*.py
- run: safety check
- - run: pylint **/*.py
+ - run: |
+ pylint terminal.py gamestonk_terminal tests
test:
name: ubuntu-latest - Python 3.8
needs: linting
@@ -47,8 +49,9 @@ jobs:
architecture: x64
- name: Install Poetry
- uses: snok/install-poetry@v1.1.1
+ uses: snok/install-poetry@v1.1.4
with:
+ version: 1.1.6
virtualenvs-create: true
virtualenvs-in-project: true
@@ -72,6 +75,11 @@ jobs:
run: |
source $VENV
pytest tests/
+
+ - name: Start Terminal and exit
+ run: |
+ source $VENV
+ python terminal.py
tests-python:
name: Python (${{ matrix.python-version }}, ${{ matrix.os }})
needs: test
@@ -95,8 +103,9 @@ jobs:
architecture: x64
- name: Install Poetry
- uses: snok/install-poetry@v1.1.1
+ uses: snok/install-poetry@v1.1.4
with:
+ version: 1.1.6
virtualenvs-create: true
virtualenvs-in-project: true
@@ -114,12 +123,23 @@ jobs:
- name: Install Package
run: poetry install --no-interaction
+ - name: List installed packages
+ shell: bash -l {0}
+ run: |
+ source $VENV
+ pip list
+
- name: Run tests
env:
MPLBACKEND: Agg
run: |
source $VENV
pytest tests/
+
+ - name: Start Terminal and exit
+ run: |
+ source $VENV
+ python terminal.py
tests-conda:
name: Conda (${{ matrix.python-version }}, ${{ matrix.os }})
needs: test
@@ -175,15 +195,25 @@ jobs:
shell: cmd /C CALL {0}
run: >-
c:\windows\system32\icacls C:\Users\runneradmin\AppData\Local\Temp /grant "everyone":F /t
+
- name: Install dependencies (Bash)
shell: bash -l {0}
run: |
conda info
+ conda install numpy=1.19.5
+ conda install -c conda-forge cvxpy
pip install --user --requirement requirements.txt
+
- name: List installed packages (Bash)
shell: bash -l {0}
- run: conda list
+ run: |
+ conda list
+ pip list
- name: Run tests (Bash)
shell: bash -l {0}
run: pytest tests/
+
+ - name: Start Terminal and exit
+ shell: bash -l {0}
+ run: python terminal.py
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 93723499e8c..e91b3bc3a6e 100755
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -2,6 +2,7 @@ name: Windows 10 Full Clean Build with ML
env:
GTFF_USE_PROMPT_TOOLKIT: false
GTFF_USE_ION: false
+ GTFF_ENABLE_QUICK_EXIT: true
on:
push:
branches:
@@ -55,6 +56,7 @@ jobs:
conda install -c conda-forge fbprophet=0.6
conda install spyder
conda install gensim=3.8.3
+ conda install -c conda-forge cvxpy
- name: Install dependencies (Bash)
shell: bash -l {0}
@@ -72,3 +74,6 @@ jobs:
shell: bash -l {0}
run: pytest tests/
+ - name: Start Terminal and exit
+ shell: bash -l {0}
+ run: python terminal.py
diff --git a/.pylintrc b/.pylintrc
index ceaa81904dc..c8806cea49c 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -54,7 +54,7 @@ confidence=
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
# disable=too-many-instance-attributes,len-as-condition,too-few-public-methods,anomalous-backslash-in-string,no-else-return,simplifiable-if-statement,too-many-arguments,duplicate-code,no-name-in-module,no-member,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,missing-docstring,invalid-name,bad-whitespace,consider-using-enumerate,unexpected-keyword-arg
-disable=useless-return,missing-docstring,invalid-name,import-error,bad-continuation,broad-except,unnecessary-lambda,no-self-use,duplicate-code,consider-using-generator
+disable=useless-return,missing-docstring,invalid-name,import-error,bad-continuation,broad-except,unnecessary-lambda,no-self-use,duplicate-code,consider-using-generator,unbalanced-tuple-unpacking
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
@@ -397,7 +397,7 @@ valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
-max-args=5
+max-args=8
# Maximum number of attributes for a class (see R0902).
# max-attributes=7
@@ -416,7 +416,7 @@ max-locals=40
max-parents=7
# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
+max-public-methods=30
# Maximum number of return / yield for function / method body
max-returns=9
diff --git a/README.md b/README.md
index 7c13cbe50b2..440bcf03b46 100644
--- a/README.md
+++ b/README.md
@@ -260,6 +260,8 @@ These are the ones where a key is necessary:
* Tradier: https://developer.tradier.com/getting_started
* Oanda API: https://developer.oanda.com
+When these are obtained, don't forget to update [config_terminal.py](/gamestonk_terminal/config_terminal.py).
+
Alternatively, you can also set them to the following environment variables: GT_API_KEY_ALPHAVANTAGE, GT_API_KEY_FINANCIALMODELINGPREP, GT_API_KEY_QUANDL, GT_API_REDDIT_CLIENT_ID, GT_API_REDDIT_CLIENT_SECRET, GT_API_REDDIT_USERNAME, GT_API_REDDIT_USER_AGENT, GT_API_REDDIT_PASSWORD, GT_API_TWITTER_KEY, GT_API_TWITTER_SECRET_KEY, GT_API_TWITTER_BEARER_TOKEN, GT_API_POLYGON_KEY, GT_FRED_API_KEY, GT_API_NEWS_TOKEN, GT_OANDA_TOKEN, GT_OANDA_ACCOUNT, GT_TRADIER_TOKEN.
Example:
@@ -267,6 +269,11 @@ Example:
export GT_API_REDDIT_USERNAME=SexyYear
```
+Environment variables can also be set in a `.env` file at the top of the repo. This file is ignored by git so your API keys will stay secret. The above example stored in `.env` would be:
+```
+GT_API_REDDIT_USERNAME=SexyYear
+```
+
Note that it is not necessary to have a valid Alpha Vantage key to get daily OHLC values.
### Usage
@@ -359,6 +366,9 @@ Distributed under the MIT License. See [LICENSE](https://github.com/DidierRLopes
[Artem Veremy](https://www.linkedin.com/in/veremey/) - artem@veremey.net
[James Maslek](https://www.linkedin.com/in/james-maslek-b6810186/) - jmaslek11@gmail.com
+
+Feel free to share loss porn, memes or any questions at https://discord.gg/Up2QGbMKHY
+
## Acknowledgments
* [VICE article](https://www.vice.com/en/article/qjp9vp/gamestonk-terminal-is-a-diy-meme-stock-version-of-bloomberg-terminal)
diff --git a/ROADMAP.md b/ROADMAP.md
index 82d5b910ed9..5242e32bfb3 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -20,6 +20,7 @@
* [Credit Analysis](#Credit-Analysis)
* [Cryptocurrencies](#Cryptocurrencies)
* [Screener](#Screener)
+* [Forex](#Forex)
## Additional
@@ -36,6 +37,8 @@
* [x] Analyse sectors/industry performance, overview and valuation from Finviz (@didier) - [PR #315](https://github.com/DidierRLopes/GamestonkTerminal/pull/315)
* [x] Add latest and trending news commands (@hinxx) - [PR #347](https://github.com/DidierRLopes/GamestonkTerminal/pull/347)
* [x] Add top ratings updates (@hinxx) - [PR #357](https://github.com/DidierRLopes/GamestonkTerminal/pull/357)
+* [x] Add dark pool (ATS) data of tickers with growing trades activity (@didier) - [PR #372](https://github.com/DidierRLopes/GamestonkTerminal/pull/372)
+
**NEXT**
@@ -61,6 +64,7 @@
## Fundamental Analysis
* [x] Rearrange FA menu to have AV and FMP as submenus (@didier) - [PR #166](https://github.com/DidierRLopes/GamestonkTerminal/pull/166)
+* [x] Add Fundamental Analysis score (@didier) - [PR #383](https://github.com/DidierRLopes/GamestonkTerminal/pull/383)
**NEXT**
* [ ] Add Treasury Yield Curve data (@aia) - [PR #281](https://github.com/DidierRLopes/GamestonkTerminal/pull/281)
@@ -79,6 +83,8 @@
---
## Due Diligence
+* [x] Add dark pools (ATS) vs Non-ATS data over time (@didier) - [PR #363](https://github.com/DidierRLopes/GamestonkTerminal/pull/363)
+* [x] Add failure to deliver command (@hinxx) - [PR #366](#https://github.com/DidierRLopes/GamestonkTerminal/pull/366)
**NEXT**
@@ -147,7 +153,7 @@
* [ ] Refactoring
* [ ] Summaries / tear sheets (@jmaslek)
-___
+___
## Portfolio Optimization
* [x] Basic Optimization through PyPortFolioOpt(@jmaslek) - [PR #329](https://github.com/DidierRLopes/GamestonkTerminal/pull/329)
@@ -169,6 +175,7 @@ ___
## Options
* [x] Add Volume graph (@lolrenx) - [PR #209](https://github.com/DidierRLopes/GamestonkTerminal/pull/209)
* [x] Add Open Interest graph (@lolrenx) - [PR #209](https://github.com/DidierRLopes/GamestonkTerminal/pull/209)
+* [x] Add options information data (IV rank, etc) (@jmaslek) - [PR #375](https://github.com/DidierRLopes/GamestonkTerminal/pull/375)
**NEXT**
* [ ] Add max pain graph (@lolrenx)
@@ -185,11 +192,13 @@ ___
## Cryptocurrencies
* [x] Add Coingecko (@jmaslek) - [PR #283](#https://github.com/DidierRLopes/GamestonkTerminal/pull/283)
+* [x] view top coins from coinmarketcap (@jmaslek) - [PR #378](https://github.com/DidierRLopes/GamestonkTerminal/pull/378)
**NEXT**
* [ ] Add [Coinpaprika](https://coinpaprika.com/api/)
* [ ] Add crypto charts
-
+* [ ] Add binance
+* [ ] Add top altcoin lists
---
## Screener
@@ -203,6 +212,13 @@ ___
---
+## Forex
+* [x] Add entire forex menu through Oanda (@alokan) - [PR #360](https://github.com/DidierRLopes/GamestonkTerminal/pull/360)
+
+**NEXT**
+
+---
+
## Backend
**NEXT**
diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md
index 192f21ca288..211b0a008e7 100644
--- a/gamestonk_terminal/README.md
+++ b/gamestonk_terminal/README.md
@@ -17,6 +17,7 @@
* [FRED](#FRED-)
* [Options](#Options-)
* [Screener](#Screener-)
+* [Forex](#Forex-)
## Main
@@ -83,6 +84,7 @@ Command|Description|Source
`latest` |latest news |[Seeking Alpha](https://seekingalpha.com/)
`trending` |trending news |[Seeking Alpha](https://seekingalpha.com/)
`ratings ` |top ratings updates |[MarketBeat](https://marketbeat.com)
+`darkpool` |dark pool tickers with growing activity |[FINRA](https://www.finra.org)
@@ -144,6 +146,7 @@ Command|Description
----- | ---------
`screener` |screen info about the company ([Finviz](https://finviz.com/))
`mgmt` |management team of the company ([Business Insider](https://markets.businessinsider.com/))
+`score` |investing score from Warren Buffett, Joseph Piotroski and Benjamin Graham ([FMP](https://financialmodelingprep.com/))
[Market Watch API](https://markets.businessinsider.com/) |
`income` |income statement of the company
`balance` |balance sheet of the company
@@ -213,6 +216,8 @@ Command|Description|Source
`sec` |SEC filings |[MarketWatch](https://www.marketwatch.com/)
`short` |short interest |[Quandl](https://www.quandl.com/)
`warnings` |company warnings according to Sean Seah book |[MarketWatch](https://www.marketwatch.com/)
+`dp` |dark pools (ATS) vs OTC data [FINRA](https://www.finra.org/#/)
+`ftd` |display fails-to-deliver data [SEC](https://www.sec.gov)
@@ -269,6 +274,7 @@ Command|Description
------ | ------------
`load`| load cryptocurrency data
`view`| load and view cryptocurrency data
+`top` | view top coins from coinmarketcap
## Comparison Analysis [»](comparison_analysis/README.md)
@@ -341,6 +347,8 @@ Command|Description|Source
`volume` | volume + open interest options trading plot |[Yahoo Finance](https://finance.yahoo.com/)
`vcalls` | calls volume + open interest plot |[Yahoo Finance](https://finance.yahoo.com/)
`vputs` | puts volume + open interest plot |[Yahoo Finance](https://finance.yahoo.com/)
+`chains` | displays option chains |[Tradier](https://developer.tradier.com/)
+`info` | display option information | [Barchart](https://barchart.com/)
@@ -359,5 +367,26 @@ performance |performance (e.g. Perf Week, Perf YTD, Volatility M)
technical |technical (e.g. Beta, SMA50, 52W Low, RSI, Change)
signals |view filter signals (e.g. -s top_gainers)
+
+
+
+## Forex [»](forex/README.md)
+Command|Description
+------ | --------
+summary |display a summary of your account
+calendar |get information about past or upcoming events which may impact the price
+list |list your order history
+pending |get information about pending orders
+cancel |cancel a pending order by ID
+positions |get information about your positions
+trades |see a list of open trades
+closetrade |close a trade by ID
+load |specify an instrument to use
+candles |get a candlestick chart for the forex instrument
+price |show the current price for the forex instrument
+order |place a limit order
+orderbook |display the orderbook if Oanda provides one for the forex instrument
+positionbook |display the positionbook if Oanda provides one for the forex instrument
+
diff --git a/gamestonk_terminal/behavioural_analysis/ba_controller.py b/gamestonk_terminal/behavioural_analysis/ba_controller.py
index 57e9a66cbe6..e8ae8f60aee 100644
--- a/gamestonk_terminal/behavioural_analysis/ba_controller.py
+++ b/gamestonk_terminal/behavioural_analysis/ba_controller.py
@@ -4,6 +4,7 @@ __docformat__ = "numpy"
import argparse
from typing import List
from datetime import datetime
+from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
@@ -14,7 +15,6 @@ from gamestonk_terminal.behavioural_analysis import (
stocktwits_view,
finbrain_view,
)
-from prompt_toolkit.completion import NestedCompleter
class BehaviouralAnalysisController:
diff --git a/gamestonk_terminal/behavioural_analysis/finbrain_view.py b/gamestonk_terminal/behavioural_analysis/finbrain_view.py
index 090327aff73..e5d1907e485 100644
--- a/gamestonk_terminal/behavioural_analysis/finbrain_view.py
+++ b/gamestonk_terminal/behavioural_analysis/finbrain_view.py
@@ -9,13 +9,14 @@ import matplotlib.dates as mdates
import pandas as pd
from pandas.plotting import register_matplotlib_converters
import numpy as np
+from colorama import Fore, Style
+
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
plot_autoscale,
)
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal import feature_flags as gtff
-from colorama import Fore, Style
register_matplotlib_converters()
diff --git a/gamestonk_terminal/behavioural_analysis/reddit_view.py b/gamestonk_terminal/behavioural_analysis/reddit_view.py
index fdf6b1396d1..231f1728276 100644
--- a/gamestonk_terminal/behavioural_analysis/reddit_view.py
+++ b/gamestonk_terminal/behavioural_analysis/reddit_view.py
@@ -189,17 +189,6 @@ def popular_tickers(l_args):
wallstreetbets
""",
)
- """
- parser.add_argument(
- "-d",
- "--days",
- action="store",
- dest="n_days",
- type=check_positive,
- default=1,
- help="look for the tickers from those n past days.",
- )
- """
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
@@ -502,17 +491,6 @@ def spac(l_args):
default=5,
help="limit of posts with SPACs retrieved.",
)
- """
- parser.add_argument(
- "-d",
- "--days",
- action="store",
- dest="n_days",
- type=check_positive,
- default=5,
- help="look for the tickers from those n past days.",
- )
- """
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
diff --git a/gamestonk_terminal/comparison_analysis/__init__.py b/gamestonk_terminal/comparison_analysis/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/gamestonk_terminal/comparison_analysis/ca_controller.py b/gamestonk_terminal/comparison_analysis/ca_controller.py
index 499b6c9cd39..3772807b71a 100644
--- a/gamestonk_terminal/comparison_analysis/ca_controller.py
+++ b/gamestonk_terminal/comparison_analysis/ca_controller.py
@@ -2,23 +2,24 @@
__docformat__ = "numpy"
import argparse
-import requests
import random
from typing import List
from datetime import datetime
+import requests
import pandas as pd
from matplotlib import pyplot as plt
+from finvizfinance.screener.overview import Overview
+from prompt_toolkit.completion import NestedCompleter
+
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal import config_terminal as cfg
-from finvizfinance.screener.overview import Overview
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
-from gamestonk_terminal.comparison_analysis import yahoo_finance_api as yf_api
-from gamestonk_terminal.comparison_analysis import market_watch_api as mw_api
-from gamestonk_terminal.comparison_analysis import finbrain_api as f_api
+from gamestonk_terminal.comparison_analysis import yahoo_finance_view
+from gamestonk_terminal.comparison_analysis import market_watch_view
+from gamestonk_terminal.comparison_analysis import finbrain_view
from gamestonk_terminal.comparison_analysis import finviz_compare_view
from gamestonk_terminal.portfolio_optimization import po_controller
from gamestonk_terminal.menu import session
-from prompt_toolkit.completion import NestedCompleter
class ComparisonAnalysisController:
@@ -54,9 +55,23 @@ class ComparisonAnalysisController:
start: datetime,
interval: str,
similar: List[str],
- user: bool,
):
- """Constructor"""
+ """Constructor
+
+ Parameters
+ ----------
+ stock : pd.DataFrame
+ Stock data
+ ticker : str
+ Stock ticker
+ start : datetime
+ Start time
+ interval : str
+ Time interval
+ similar : List[str]
+ List of similar tickers
+ """
+
self.similar = similar
self.user = ""
self.stock = stock
@@ -69,7 +84,6 @@ class ComparisonAnalysisController:
choices=self.CHOICES,
)
- @staticmethod
def print_help(self):
"""Print help"""
@@ -108,14 +122,21 @@ class ComparisonAnalysisController:
print(" performance brief performance comparison")
print(" technical brief technical comparison")
print("")
+
if self.similar:
print(" > po portfolio optimization for selected tickers")
print("")
return
- @staticmethod
def get_similar_companies(self, other_args: List[str]):
- """ Get similar companies. [Source: Polygon API] """
+ """Get similar companies. [Source: Polygon API]
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="get",
@@ -189,9 +210,15 @@ class ComparisonAnalysisController:
print("")
return
- @staticmethod
def select_similar_companies(self, other_args: List[str]):
- """ Select similar companies, e.g. NIO,XPEV,LI"""
+ """Select similar companies, e.g. NIO,XPEV,LI
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="select",
@@ -242,7 +269,7 @@ class ComparisonAnalysisController:
def call_help(self, _):
"""Process Help command"""
- self.print_help(self)
+ self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
@@ -254,43 +281,43 @@ class ComparisonAnalysisController:
def call_get(self, other_args: List[str]):
"""Process get command"""
- self.get_similar_companies(self, other_args)
+ self.get_similar_companies(other_args)
def call_select(self, other_args: List[str]):
"""Process select command"""
- self.select_similar_companies(self, other_args)
+ self.select_similar_companies(other_args)
def call_historical(self, other_args: List[str]):
"""Process historical command"""
- yf_api.historical(
+ yahoo_finance_view.historical(
other_args, self.stock, self.ticker, self.start, self.interval, self.similar
)
def call_hcorr(self, other_args: List[str]):
"""Process historical correlation command"""
- yf_api.correlation(
+ yahoo_finance_view.correlation(
other_args, self.stock, self.ticker, self.start, self.interval, self.similar
)
def call_income(self, other_args: List[str]):
"""Process income command"""
- mw_api.compare_income(other_args, self.ticker, self.similar)
+ market_watch_view.compare_income(other_args, self.ticker, self.similar)
def call_balance(self, other_args: List[str]):
"""Process balance command"""
- mw_api.compare_balance(other_args, self.ticker, self.similar)
+ market_watch_view.compare_balance(other_args, self.ticker, self.similar)
def call_cashflow(self, other_args: List[str]):
"""Process cashflow command"""
- mw_api.compare_cashflow(other_args, self.ticker, self.similar)
+ market_watch_view.compare_cashflow(other_args, self.ticker, self.similar)
def call_sentiment(self, other_args: List[str]):
"""Process sentiment command"""
- f_api.sentiment_compare(other_args, self.ticker, self.similar)
+ finbrain_view.sentiment_compare(other_args, self.ticker, self.similar)
def call_scorr(self, other_args: List[str]):
"""Process sentiment correlation command"""
- f_api.sentiment_correlation(other_args, self.ticker, self.similar)
+ finbrain_view.sentiment_correlation(other_args, self.ticker, self.similar)
def call_overview(self, other_args: List[str]):
"""Process overview command"""
@@ -324,11 +351,21 @@ class ComparisonAnalysisController:
def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
- """Comparison Analysis Menu"""
+ """Comparison Analysis Menu
- ca_controller = ComparisonAnalysisController(
- stock, ticker, start, interval, [], False
- )
+ Parameters
+ ----------
+ stock : pd.DataFrame
+ Stock data
+ ticker : str
+ Stock ticker
+ start : datetime
+ Time start
+ interval : str
+ Time interval
+ """
+
+ ca_controller = ComparisonAnalysisController(stock, ticker, start, interval, [])
ca_controller.call_help(None)
while True:
diff --git a/gamestonk_terminal/comparison_analysis/finbrain_api.py b/gamestonk_terminal/comparison_analysis/finbrain_view.py
similarity index 99%
rename from gamestonk_terminal/comparison_analysis/finbrain_api.py
rename to gamestonk_terminal/comparison_analysis/finbrain_view.py
index c1cb629d893..cc0ee139d64 100644
--- a/gamestonk_terminal/comparison_analysis/finbrain_api.py
+++ b/gamestonk_terminal/comparison_analysis/finbrain_view.py
@@ -10,6 +10,7 @@ import pandas as pd
from pandas.plotting import register_matplotlib_converters
import numpy as np
import seaborn as sns
+
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
plot_autoscale,
@@ -33,6 +34,7 @@ def sentiment_compare(other_args: List[str], ticker: str, similar: List[str]):
similar : List[str]
Similar companies to compare income with
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="sentiment_compare",
@@ -98,6 +100,7 @@ def sentiment_correlation(other_args: List[str], ticker: str, similar: List[str]
similar : List[str]
Similar companies to compare income with
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="sentiment_compare",
@@ -164,6 +167,7 @@ def get_sentiments(similar: List[str]) -> pd.DataFrame:
DataFrame()
Contains sentiment analysis from several tickers
"""
+
df_sentiment = pd.DataFrame()
for ticker in similar:
result = requests.get(f"https://api.finbrain.tech/v0/sentiments/{ticker}")
@@ -196,6 +200,7 @@ def plot_sentiments(df_sentiment: pd.DataFrame, similar: List[str]):
similar : List[str]
List of similar companies
"""
+
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
for idx, ticker in enumerate(similar):
@@ -251,6 +256,7 @@ def plot_correlation(df_sentiment: pd.DataFrame, similar: List[str]):
similar : List[str]
List of similar companies
"""
+
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
mask = np.zeros((len(similar), len(similar)), dtype=bool)
diff --git a/gamestonk_terminal/comparison_analysis/market_watch_api.py b/gamestonk_terminal/comparison_analysis/market_watch_view.py
similarity index 99%
rename from gamestonk_terminal/comparison_analysis/market_watch_api.py
rename to gamestonk_terminal/comparison_analysis/market_watch_view.py
index 5067cdeae38..4cef54e2b79 100644
--- a/gamestonk_terminal/comparison_analysis/market_watch_api.py
+++ b/gamestonk_terminal/comparison_analysis/market_watch_view.py
@@ -27,6 +27,7 @@ def compare_income(other_args: List[str], ticker: str, similar: List[str]):
similar : List[str]
Similar companies to compare income with
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="income",
@@ -132,6 +133,7 @@ def compare_balance(other_args: List[str], ticker: str, similar: List[str]):
similar : List[str]
Similar companies to compare income with
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="compare_balance",
@@ -237,6 +239,7 @@ def compare_cashflow(other_args: List[str], ticker: str, similar: List[str]):
similar : List[str]
Similar companies to compare income with
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="compare_cashflow",
diff --git a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py b/gamestonk_terminal/comparison_analysis/yahoo_finance_view.py
similarity index 77%
rename from gamestonk_terminal/comparison_analysis/yahoo_finance_api.py
rename to gamestonk_terminal/comparison_analysis/yahoo_finance_view.py
index 72df9f825ad..d2552845e61 100644
--- a/gamestonk_terminal/comparison_analysis/yahoo_finance_api.py
+++ b/gamestonk_terminal/comparison_analysis/yahoo_finance_view.py
@@ -1,4 +1,9 @@
+""" Comparison Analysis Yahoo Finance View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
+from datetime import datetime
import numpy as np
import pandas as pd
from pandas.plotting import register_matplotlib_converters
@@ -21,18 +26,56 @@ d_candle_types = {
def check_one_of_ohlca(type_candles: str) -> str:
- if (
- type_candles == "o"
- or type_candles == "h"
- or type_candles == "l"
- or type_candles == "c"
- or type_candles == "a"
- ):
+ """Convert a candle type
+
+ Parameters
+ ----------
+ type_candles : str
+ OHLCA candle type
+
+ Returns
+ -------
+ str
+ Converted candle type
+
+ Raises
+ ------
+ argparse.ArgumentTypeError
+ Unknown candle type
+ """
+
+ if type_candles in ("o", "h", "l", "c", "a"):
return type_candles
+
raise argparse.ArgumentTypeError("The type of candles specified is not recognized")
-def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
+def historical(
+ other_args: List[str],
+ df_stock: pd.DataFrame,
+ ticker: str,
+ start: datetime,
+ interval: str,
+ similar: List[str],
+):
+ """Display historical data from Yahoo Finance
+
+ Parameters
+ ----------
+ other_args : List[str]
+ Command line arguments to be processed with argparse
+ df_stock : pd.DataFrame
+ Stock data
+ ticker : str
+ Ticker symbol
+ start : datetime
+ Time start
+ interval : str
+ Time interval
+ similar : List[str]
+ List of similar tickers
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="historical",
@@ -66,11 +109,11 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
)
try:
- if s_interval != "1440min":
+ if interval != "1440min":
print("Intraday historical data analysis comparison is not yet available.")
# Alpha Vantage only supports 5 calls per minute, we need another API to get intraday data
else:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -80,16 +123,14 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
similar += ns_parser.l_also
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
- plt.title(f"Similar companies to {s_ticker}")
- df_stock = yf.download(
- s_ticker, start=s_start, progress=False, threads=False
- )
+ plt.title(f"Similar companies to {ticker}")
+ df_stock = yf.download(ticker, start=start, progress=False, threads=False)
plt.plot(
df_stock.index, df_stock[d_candle_types[ns_parser.type_candle]].values
)
# plt.plot(df_stock.index, df_stock["5. adjusted close"].values, lw=2)
l_min = [df_stock.index[0]]
- l_leg = [s_ticker]
+ l_leg = [ticker]
l_stocks = similar[:]
@@ -98,7 +139,7 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
for symbol in l_stocks:
try:
df_similar_stock = yf.download(
- symbol, start=s_start, progress=False, threads=False
+ symbol, start=start, progress=False, threads=False
)
if not df_similar_stock.empty:
plt.plot(
@@ -141,7 +182,25 @@ def historical(l_args, df_stock, s_ticker, s_start, s_interval, similar):
print(e, "\n")
-def correlation(l_args, df_stock, s_ticker, s_start, s_interval, similar):
+def correlation(other_args, df_stock, ticker, start, interval, similar):
+ """[summary]
+
+ Parameters
+ ----------
+ other_args : [type]
+ Command line arguments to be processed with argparse
+ df_stock : pd.DataFrame
+ Stock data
+ ticker : str
+ Ticker symbol
+ start : datetime
+ Time start
+ interval : str
+ Time interval
+ similar : [type]
+ List of similar tickers
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="corr",
@@ -176,11 +235,11 @@ def correlation(l_args, df_stock, s_ticker, s_start, s_interval, similar):
)
try:
- if s_interval != "1440min":
+ if interval != "1440min":
print("Intraday historical data analysis comparison is not yet available.")
# Alpha Vantage only supports 5 calls per minute, we need another API to get intraday data
else:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -193,21 +252,21 @@ def correlation(l_args, df_stock, s_ticker, s_start, s_interval, similar):
print("Provide at least a similar company for correlation")
else:
d_stock = {}
- d_stock[s_ticker] = yf.download(s_ticker, start=s_start, progress=False)
- l_min = [d_stock[s_ticker].index[0]]
+ d_stock[ticker] = yf.download(ticker, start=start, progress=False)
+ l_min = [d_stock[ticker].index[0]]
for symbol in similar:
- d_stock[symbol] = yf.download(symbol, start=s_start, progress=False)
+ d_stock[symbol] = yf.download(symbol, start=start, progress=False)
if not d_stock[symbol].empty:
l_min.append(d_stock[symbol].index[0])
min_start_date = max(l_min)
- df_stock = d_stock[s_ticker][
+ df_stock = d_stock[ticker][
d_candle_types[ns_parser.type_candle]
- ].rename(s_ticker)
+ ].rename(ticker)
for symbol in d_stock:
- if symbol != s_ticker:
+ if symbol != ticker:
if not d_stock[symbol].empty:
df_stock = pd.concat(
[
diff --git a/gamestonk_terminal/config_terminal.py b/gamestonk_terminal/config_terminal.py
index 874e1181edc..556b088f77c 100644
--- a/gamestonk_terminal/config_terminal.py
+++ b/gamestonk_terminal/config_terminal.py
@@ -1,4 +1,7 @@
import os
+from dotenv import load_dotenv
+
+load_dotenv()
# https://www.alphavantage.co
API_KEY_ALPHAVANTAGE = os.getenv("GT_API_KEY_ALPHAVANTAGE") or "REPLACE_ME"
@@ -36,9 +39,16 @@ API_NEWS_TOKEN = os.getenv("GT_API_NEWS_TOKEN") or "REPLACE_ME"
RH_USERNAME = os.getenv("GT_RH_USERNAME") or "REPLACE_ME"
RH_PASSWORD = os.getenv("GT_RH_PASSWORD") or "REPLACE_ME"
-# Oanda
+# https://developer.oanda.com
OANDA_ACCOUNT = os.getenv("GT_OANDA_ACCOUNT") or "REPLACE ME"
OANDA_TOKEN = os.getenv("GT_OANDA_TOKEN") or "REPLACE ME"
# https://tradier.com/products/market-data-api
TRADIER_TOKEN = os.getenv("GT_TRADIER_TOKEN") or "REPLACE_ME"
+
+# Selenium Webbrowser drivers can be found at https://selenium-python.readthedocs.io/installation.html
+WEBDRIVER_TO_USE = "chrome"
+PATH_TO_SELENIUM_DRIVER = None # Replace with "PATH"
+
+# https://coinmarketcap.com/api/
+COINMARKETCAP_KEY = os.getenv("GT_CMC_API_KEY") or "REPLACE_ME"
diff --git a/gamestonk_terminal/cryptocurrency/README.md b/gamestonk_terminal/cryptocurrency/README.md
index fd5ac92c10e..4a1b7b48fea 100644
--- a/gamestonk_terminal/cryptocurrency/README.md
+++ b/gamestonk_terminal/cryptocurrency/README.md
@@ -1,41 +1,52 @@
-# Cryptocurrency
+# CRYPTOCURRENCY
-This page gives an overview of the ability to load cryptocurrency data.
-
-Current crypto data is [Powered by CoinGecko API](#https://www.coingecko.com/en).
-This is an awesome service that currently requires no API Key!
-
-Current functionality is aimed to be similar to loading a stock ticker.
+This menu aims to explore crypto world, and the usage of the following commands along with an example will be exploited below.
* [load](#load)
+ * load a given coin vs a given currency [CoinGecko]
* [view](#view)
+ * plot the loaded crypto data
+* [top](#top)
+ * view top coins from coinmarketcap [coinmarketcap.com]
+
## load
-Load a given coin vs a given currency:
````
usage: load [-c --coin] [-d --days] [--vs]
````
+
+Load a given coin vs a given currency. Currently only retrieves price, not volume or MarketCap. The current crypto data is [Powered by CoinGecko API](#https://www.coingecko.com/en), which is an awesome service that currently requires no API Key!
+
* -c/--coin The coin you wish to load. This can either be the symbol or the name. `load -c btc` and `load -c bitcoin`
will load. The -c flag is optional, the above is equivalent to `load btc`.
-
* -d/--days The number of days to look. Defaults to 30 days. As per the API: Minutely data will be used for duration within 1 day,
Hourly data will be used for duration between 1 day and 90 days, Daily data will be used for duration above 90 days.
-
* --vs The currency to look against. Defaults to "usd".
-Currently only retrieves price, not volume or MarketCap.
-
-Example doge/eur for the past day:
-````
-load -c doge -d 1 --vs eur
-````
## view
-Plot the loaded crypto data.
+
````
usage: view
````
-After loading the above 1 day dogecoin/eur. Running view plots the data:
-
+Plot the loaded crypto data.
+
+
+
+
+## top
+
+````
+top [-n] [-s --sort SORTBY] [--descend]
+````
+
+This command displays the top n cryptocurrencies from coinmarketcap.com.
+
+* -n: Number of coins to look at (after sort). Defaults to 10.
+* -s/--sort : Column to sort by. One of {Symbol,CMC_Rank,LastPrice,DayPctChange,MarketCap}. Defaults to sorting by the CMC rank.
+* --descend : Flag to change the sorting order. Sorts in ascending order (since default order is the Rank which starts at 1).
+
+
+
diff --git a/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py b/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py
new file mode 100644
index 00000000000..a8820889d33
--- /dev/null
+++ b/gamestonk_terminal/cryptocurrency/coinmarketcap_view.py
@@ -0,0 +1,100 @@
+"""CoinMarketCap API"""
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+import pandas as pd
+from tabulate import tabulate
+from coinmarketcapapi import CoinMarketCapAPI
+from gamestonk_terminal.config_terminal import COINMARKETCAP_KEY
+from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
+
+sort_options = ["Symbol", "CMC_Rank", "LastPrice", "DayPctChange", "MarketCap"]
+
+sort_map = {
+ "Symbol": "Symbol",
+ "CMC_Rank": "CMC_Rank",
+ "LastPrice": "Last Price",
+ "DayPctChange": "1 Day Pct Change",
+ "MarketCap": "Market Cap ($B)",
+}
+
+
+def get_cmc_top_n(other_args: List[str]):
+ """
+ Shows top n coins from coinmarketcap.com
+ Parameters
+ ----------
+ other_args: List[str]
+ Arguments to pass to argparse
+
+ """
+ parser = argparse.ArgumentParser(
+ prog="cmc_top_n",
+ add_help=False,
+ description="This gets the top ranked coins from coinmarketcap.com",
+ )
+
+ parser.add_argument(
+ "-n", default=10, dest="n_to_get", type=int, help="number of coins to display"
+ )
+
+ parser.add_argument(
+ "-s",
+ "--sort",
+ dest="sortby",
+ type=str,
+ help="column to sort data by.",
+ default="CMC_Rank",
+ choices=sort_options,
+ )
+
+ parser.add_argument(
+ "--descend",
+ action="store_false",
+ help="Flag to sort in descending order (lowest first)",
+ dest="descend",
+ default=True,
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ cmc = CoinMarketCapAPI(COINMARKETCAP_KEY)
+ ratings = cmc.cryptocurrency_listings_latest().data
+
+ symbol, rank, price, pchange1d, mkt_cap = [], [], [], [], []
+ for coin in ratings:
+ symbol.append(coin["symbol"])
+ rank.append(coin["cmc_rank"])
+ price.append(coin["quote"]["USD"]["price"])
+ pchange1d.append(coin["quote"]["USD"]["percent_change_24h"])
+ mkt_cap.append(coin["quote"]["USD"]["market_cap"] / (10 ** 9))
+
+ df = pd.DataFrame(data=[symbol, rank, price, pchange1d, mkt_cap]).transpose()
+ df.columns = [
+ "Symbol",
+ "CMC_Rank",
+ "Last Price",
+ "1 Day Pct Change",
+ "Market Cap ($B)",
+ ]
+
+ df = df.sort_values(by=sort_map[ns_parser.sortby], ascending=ns_parser.descend)
+
+ print(
+ tabulate(
+ df.iloc[: ns_parser.n_to_get, :],
+ headers=df.columns,
+ showindex=False,
+ tablefmt="fancy_grid",
+ floatfmt=".2f",
+ )
+ )
+ print("")
+
+ except Exception as e:
+ print(e)
+ print("")
diff --git a/gamestonk_terminal/cryptocurrency/crypto_controller.py b/gamestonk_terminal/cryptocurrency/crypto_controller.py
index 4a1508e11f8..e78323b473b 100644
--- a/gamestonk_terminal/cryptocurrency/crypto_controller.py
+++ b/gamestonk_terminal/cryptocurrency/crypto_controller.py
@@ -7,12 +7,13 @@ from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
-from gamestonk_terminal.cryptocurrency import coin_api
+from gamestonk_terminal.cryptocurrency import pycoingecko_view
+from gamestonk_terminal.cryptocurrency import coinmarketcap_view as cmc_view
class CryptoController:
- CHOICES = ["help", "q", "quit", "load", "view"]
+ CHOICES = ["help", "q", "quit", "load", "view", "top"]
def __init__(self):
""" CONSTRUCTOR """
@@ -34,6 +35,8 @@ class CryptoController:
print(" load load cryptocurrency data")
print(" view load and view cryptocurrency data")
print("")
+ print(" top view top coins from coinmarketcap")
+ print("")
def switch(self, an_input: str):
"""Process and dispatch input
@@ -64,16 +67,19 @@ class CryptoController:
return True
def call_load(self, other_args):
- self.current_coin, self.current_df = coin_api.load(other_args)
+ self.current_coin, self.current_df = pycoingecko_view.load(other_args)
def call_view(self, other_args):
if self.current_coin:
- coin_api.view(self.current_coin, self.current_df, other_args)
+ pycoingecko_view.view(self.current_coin, self.current_df, other_args)
else:
print("No coin selected. Use 'load' to load the coin you want to look at.")
print("")
+ def call_top(self, other_args):
+ cmc_view.get_cmc_top_n(other_args)
+
def menu():
crypto_controller = CryptoController()
diff --git a/gamestonk_terminal/cryptocurrency/coin_api.py b/gamestonk_terminal/cryptocurrency/pycoingecko_view.py
similarity index 100%
rename from gamestonk_terminal/cryptocurrency/coin_api.py
rename to gamestonk_terminal/cryptocurrency/pycoingecko_view.py
diff --git a/gamestonk_terminal/discovery/README.md b/gamestonk_terminal/discovery/README.md
index 6b20d1b25f1..1159e591b56 100644
--- a/gamestonk_terminal/discovery/README.md
+++ b/gamestonk_terminal/discovery/README.md
@@ -38,6 +38,8 @@ This menu aims to discover new stocks, and the usage of the following commands a
* trending news [Seeking Alpha]
* [ratings](#ratings)
* top ratings updates [MarketBeat]
+* [darkpool](#darkpool)
+ * dark pool tickers with growing activity [FINRA]
## map
@@ -265,3 +267,18 @@ Top ratings updates. [Source: MarketBeat]
+
+## darkpool
+
+```
+usage: darkpool [-n N_NUM] [-t N_TOP]
+```
+
+Display dark pool (ATS) data of tickers with growing trades activity. [Source: FINRA]
+
+* -n : Number of tickers to filter from entire ATS data based on the sum of the total weekly shares quantity. Default: 1000.
+* -t : List of tickers from most promising with better linear regression slope. Default: 5.
+
+
+
+
diff --git a/gamestonk_terminal/discovery/disc_controller.py b/gamestonk_terminal/discovery/disc_controller.py
index 2362e8f762b..07e00b2e462 100644
--- a/gamestonk_terminal/discovery/disc_controller.py
+++ b/gamestonk_terminal/discovery/disc_controller.py
@@ -21,6 +21,7 @@ from gamestonk_terminal.discovery import (
unusual_whales_view,
yahoo_finance_view,
marketbeat_view,
+ finra_ats_view,
)
@@ -50,6 +51,7 @@ class DiscoveryController:
"ratings",
"latest",
"trending",
+ "darkpool",
]
def __init__(self):
@@ -94,6 +96,7 @@ class DiscoveryController:
print(" latest latest news [Seeking Alpha]")
print(" trending trending news [Seeking Alpha]")
print(" ratings top ratings updates [MarketBeat]")
+ print(" darkpool dark pool tickers with growing activity [FINRA]")
print("")
def switch(self, an_input: str):
@@ -206,6 +209,10 @@ class DiscoveryController:
"""Process ratings command"""
marketbeat_view.ratings_view(other_args)
+ def call_darkpool(self, other_args: List[str]):
+ """Process darkpool command"""
+ finra_ats_view.dark_pool(other_args)
+
def menu():
"""Discovery Menu"""
diff --git a/gamestonk_terminal/discovery/finra_ats_view.py b/gamestonk_terminal/discovery/finra_ats_view.py
new file mode 100644
index 00000000000..7480ba16885
--- /dev/null
+++ b/gamestonk_terminal/discovery/finra_ats_view.py
@@ -0,0 +1,265 @@
+""" FINRA View """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List, Tuple, Dict
+import requests
+from scipy import stats
+import pandas as pd
+from matplotlib import pyplot as plt
+from gamestonk_terminal.config_plot import PLOT_DPI
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import (
+ parse_known_args_and_warn,
+ plot_autoscale,
+ check_positive,
+)
+
+
+def getFINRAweeks(tier, is_ats) -> List:
+ """Get FINRA weeks
+
+ Parameters
+ ----------
+ tier : str
+ Stock tier between T1, T2, or OTCE
+ is_ats : bool
+ ATS data if true, NON-ATS otherwise
+
+ Returns
+ ----------
+ List
+ List of response data
+ """
+ req_hdr = {"Accept": "application/json", "Content-Type": "application/json"}
+
+ req_data = {
+ "compareFilters": [
+ {
+ "compareType": "EQUAL",
+ "fieldName": "summaryTypeCode",
+ "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
+ },
+ {
+ "compareType": "EQUAL",
+ "fieldName": "tierIdentifier",
+ "fieldValue": tier,
+ },
+ ],
+ "delimiter": "|",
+ "fields": ["weekStartDate"],
+ "limit": 27,
+ "quoteValues": False,
+ "sortFields": ["-weekStartDate"],
+ }
+
+ response = requests.post(
+ "https://api.finra.org/data/group/otcMarket/name/weeklyDownloadDetails",
+ headers=req_hdr,
+ json=req_data,
+ )
+
+ return response.json() if response.status_code == 200 else list()
+
+
+def getFINRAdata(weekStartDate, tier, ticker, is_ats, offset):
+ req_hdr = {"Accept": "application/json", "Content-Type": "application/json"}
+
+ l_cmp_filters = [
+ {
+ "compareType": "EQUAL",
+ "fieldName": "weekStartDate",
+ "fieldValue": weekStartDate,
+ },
+ {"compareType": "EQUAL", "fieldName": "tierIdentifier", "fieldValue": tier},
+ {
+ "compareType": "EQUAL",
+ "description": "",
+ "fieldName": "summaryTypeCode",
+ "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
+ },
+ ]
+
+ if ticker:
+ l_cmp_filters.append(
+ {
+ "compareType": "EQUAL",
+ "fieldName": "issueSymbolIdentifier",
+ "fieldValue": ticker,
+ }
+ )
+
+ req_data = {
+ "compareFilters": l_cmp_filters,
+ "delimiter": "|",
+ "fields": [
+ "issueSymbolIdentifier",
+ "totalWeeklyShareQuantity",
+ "totalWeeklyTradeCount",
+ "lastUpdateDate",
+ ],
+ "limit": 5000,
+ "offset": offset,
+ "quoteValues": False,
+ "sortFields": ["totalWeeklyShareQuantity"],
+ }
+
+ return requests.post(
+ "https://api.finra.org/data/group/otcMarket/name/weeklySummary",
+ headers=req_hdr,
+ json=req_data,
+ )
+
+
+def getATSdata(num_tickers_to_filter: int) -> Tuple[pd.DataFrame, Dict]:
+ """Get all FINRA ATS data, and parse most promising tickers based on linear regression
+
+ Parameters
+ ----------
+ num_tickers_to_filter : int
+ Number of tickers to filter from entire ATS data based on the sum of the total weekly shares quantity
+
+ Returns
+ ----------
+ pd.DataFrame
+ Dark Pools (ATS) Data
+ Dict
+ Tickers from Dark Pools with better regression slope
+ """
+ tiers = ["T1", "T2", "OTCE"]
+ df_ats = pd.DataFrame()
+
+ for tier in tiers:
+ print(f"Processing Tier {tier} ...")
+ for d_week in getFINRAweeks(tier, is_ats=True):
+ offset = 0
+ response = getFINRAdata(d_week["weekStartDate"], tier, "", True, offset)
+ l_data = response.json()
+
+ while len(response.json()) == 5000:
+ offset += 5000
+ response = getFINRAdata(d_week["weekStartDate"], tier, "", True, offset)
+ l_data += response.json()
+
+ df_ats_week = pd.DataFrame(l_data)
+ df_ats_week["weekStartDate"] = d_week["weekStartDate"]
+
+ if not df_ats_week.empty:
+ df_ats = df_ats.append(df_ats_week, ignore_index=True)
+
+ df_ats = df_ats.sort_values("weekStartDate")
+ df_ats["weekStartDateInt"] = pd.to_datetime(df_ats["weekStartDate"]).apply(
+ lambda x: x.timestamp()
+ )
+
+ print(f"Processing regression on {num_tickers_to_filter} promising tickers ...")
+
+ d_ats_reg = {}
+ # set(df_ats['issueSymbolIdentifier'].values) this would be iterating through all tickers
+ # but that is extremely time consuming for little reward. A little filtering is done to
+ # speed up search for best ATS tickers
+ for symbol in list(
+ df_ats.groupby("issueSymbolIdentifier")["totalWeeklyShareQuantity"]
+ .sum()
+ .sort_values()[-num_tickers_to_filter:]
+ .index
+ ):
+ slope = stats.linregress(
+ df_ats[df_ats["issueSymbolIdentifier"] == symbol][
+ "weekStartDateInt"
+ ].values,
+ df_ats[df_ats["issueSymbolIdentifier"] == symbol][
+ "totalWeeklyShareQuantity"
+ ].values,
+ )[0]
+ d_ats_reg[symbol] = slope
+
+ return df_ats, d_ats_reg
+
+
+def plot_dark_pools(ats: pd.DataFrame, top_ats_tickers: List):
+ """Plots promising tickers based on growing ATS data
+
+ Parameters
+ ----------
+ ats : pd.DataFrame
+ Dark Pools (ATS) Data
+ top_ats_tickers : List
+ List of tickers from most promising with better linear regression slope
+ """
+ plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
+
+ for symbol in top_ats_tickers:
+ plt.plot(
+ pd.to_datetime(
+ ats[ats["issueSymbolIdentifier"] == symbol]["weekStartDate"]
+ ),
+ ats[ats["issueSymbolIdentifier"] == symbol]["totalWeeklyShareQuantity"]
+ / 1_000_000,
+ )
+
+ plt.legend(top_ats_tickers)
+ plt.ylabel("Total Weekly Shares [Million]")
+ plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2)
+ plt.title("Dark Pool (ATS) growing tickers")
+ plt.gcf().autofmt_xdate()
+ plt.xlabel("Weeks")
+
+ if gtff.USE_ION:
+ plt.ion()
+
+ plt.show()
+
+
+def dark_pool(other_args: List[str]):
+ """Display dark pool (ATS) data of tickers with growing trades activity
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ """
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="darkpool",
+ description="Display dark pool (ATS) data of tickers with growing trades activity",
+ )
+ parser.add_argument(
+ "-n",
+ "--num",
+ action="store",
+ dest="n_num",
+ type=check_positive,
+ default=1000,
+ help="Number of tickers to filter from entire ATS data based on the sum of the total weekly shares quantity.",
+ )
+ parser.add_argument(
+ "-t",
+ "--top",
+ action="store",
+ dest="n_top",
+ type=check_positive,
+ default=5,
+ help="List of tickers from most promising with better linear regression slope.",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ df_ats, d_ats_reg = getATSdata(ns_parser.n_num)
+
+ top_ats_tickers = list(
+ dict(
+ sorted(d_ats_reg.items(), key=lambda item: item[1], reverse=True)
+ ).keys()
+ )[: ns_parser.n_top]
+
+ plot_dark_pools(df_ats, top_ats_tickers)
+ print("")
+
+ except Exception as e:
+ print(e)
+ print("")
+ return
diff --git a/gamestonk_terminal/discovery/finviz_view.py b/gamestonk_terminal/discovery/finviz_view.py
index 3bd3e06e8f6..284779960c4 100644
--- a/gamestonk_terminal/discovery/finviz_view.py
+++ b/gamestonk_terminal/discovery/finviz_view.py
@@ -4,10 +4,11 @@ __docformat__ = "numpy"
import argparse
from typing import List
import webbrowser
-from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
from finvizfinance.group import valuation, performance, spectrum
from PIL import Image
+from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
+
l_GROUPS = [
"Sector",
"Industry",
@@ -97,6 +98,7 @@ def get_valuation_performance_data(group: str, data_type: str):
pd.DataFrame
dataframe with valuation/performance data
"""
+
if data_type == "valuation":
df_group = valuation.Valuation().ScreenerView(group=group)
elif data_type == "performance":
@@ -117,6 +119,7 @@ def get_spectrum_data(group: str):
data_type : str
select data type to see data between valuation or performance
"""
+
spectrum.Spectrum().ScreenerView(group=group)
@@ -130,6 +133,7 @@ def view_group_data(other_args: List[str], data_type: str):
data_type : str
select data type to see data between valuation, performance and spectrum
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="group_data",
@@ -156,12 +160,12 @@ def view_group_data(other_args: List[str], data_type: str):
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return
+ return None
if isinstance(ns_parser.group, List):
ns_parser.group = ns_parser.group[0]
- if data_type == "valuation" or data_type == "performance":
+ if data_type in ("valuation", "performance"):
df_group = get_valuation_performance_data(ns_parser.group, data_type)
print(df_group.to_string())
@@ -172,7 +176,7 @@ def view_group_data(other_args: List[str], data_type: str):
img.show()
print("")
- return ns_parser.group
+ return img
else:
print(
@@ -180,7 +184,8 @@ def view_group_data(other_args: List[str], data_type: str):
)
print("")
- return ""
+ return None
except SystemExit:
print("")
+ return None
diff --git a/gamestonk_terminal/discovery/marketbeat_model.py b/gamestonk_terminal/discovery/marketbeat_model.py
old mode 100755
new mode 100644
diff --git a/gamestonk_terminal/discovery/marketbeat_view.py b/gamestonk_terminal/discovery/marketbeat_view.py
index 13ec048ee5c..c2f3c58007d 100644
--- a/gamestonk_terminal/discovery/marketbeat_view.py
+++ b/gamestonk_terminal/discovery/marketbeat_view.py
@@ -2,14 +2,14 @@
__docformat__ = "numpy"
import argparse
+from typing import List
import numpy as np
import pandas as pd
-from typing import List
+
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
)
-
from gamestonk_terminal.discovery import marketbeat_model
diff --git a/gamestonk_terminal/discovery/seeking_alpha_model.py b/gamestonk_terminal/discovery/seeking_alpha_model.py
old mode 100755
new mode 100644
index 6041eb63f67..1a2df5f03a3
--- a/gamestonk_terminal/discovery/seeking_alpha_model.py
+++ b/gamestonk_terminal/discovery/seeking_alpha_model.py
@@ -2,11 +2,11 @@
__docformat__ = "numpy"
from typing import List
+from datetime import datetime
import requests
from bs4 import BeautifulSoup
import pandas as pd
from pandas.core.frame import DataFrame
-from datetime import datetime
from gamestonk_terminal.helper_funcs import get_user_agent
@@ -180,7 +180,7 @@ def get_trending_list(num: int) -> list:
}
)
- return articles
+ return articles[:num]
def get_article_data(article_id: int) -> dict:
diff --git a/gamestonk_terminal/discovery/seeking_alpha_view.py b/gamestonk_terminal/discovery/seeking_alpha_view.py
index 1670cc3e084..ee65fae29d5 100644
--- a/gamestonk_terminal/discovery/seeking_alpha_view.py
+++ b/gamestonk_terminal/discovery/seeking_alpha_view.py
@@ -3,8 +3,8 @@ __docformat__ = "numpy"
import argparse
from typing import List
-import pandas as pd
from datetime import datetime
+import pandas as pd
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
diff --git a/gamestonk_terminal/due_diligence/README.md b/gamestonk_terminal/due_diligence/README.md
index 70bfb49340b..cb8854b78e5 100644
--- a/gamestonk_terminal/due_diligence/README.md
+++ b/gamestonk_terminal/due_diligence/README.md
@@ -24,6 +24,10 @@ This menu aims to help in due-diligence of a pre-loaded stock, and the usage of
* short interest [Quandl]
* [warnings](#warnings)
* company warnings according to Sean Seah book [Market Watch]
+* [dp](#dp)
+ * dark pools (ATS) vs OTC data [FINRA]
+* [ftd](#ftd)
+ * fails-to-deliver data [SEC]
## news
@@ -157,3 +161,26 @@ Sean Seah warnings. Check: Consistent historical earnings per share; Consistentl
* -d : print insights into warnings calculation. Default False.
+
+## dp
+
+```text
+usage: dp
+```
+
+Display barchart of dark pool (ATS) and OTC (Non ATS) data
+
+
+
+## ftd
+
+```text
+usage: ftd [-n N_NUM]
+```
+
+The fails-to-deliver data collected by SEC. Fails to deliver on a given day are a cumulative number of all fails outstanding until that day, plus new fails that occur that day, less fails that settle that day. See . [Source: SEC]
+
+* -n : number of latest fails-to-deliver being printed. Default 20.
+
+
+
diff --git a/gamestonk_terminal/due_diligence/dd_controller.py b/gamestonk_terminal/due_diligence/dd_controller.py
index 14ecab8fc40..2dbe1379927 100644
--- a/gamestonk_terminal/due_diligence/dd_controller.py
+++ b/gamestonk_terminal/due_diligence/dd_controller.py
@@ -13,6 +13,8 @@ from gamestonk_terminal.due_diligence import market_watch_view as mw_view
from gamestonk_terminal.due_diligence import quandl_view as q_view
from gamestonk_terminal.due_diligence import reddit_view as r_view
from gamestonk_terminal.due_diligence import news_view
+from gamestonk_terminal.due_diligence import finra_view
+from gamestonk_terminal.due_diligence import sec_view
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
@@ -37,6 +39,8 @@ class DueDiligenceController:
"analyst",
"warnings",
"sec",
+ "dp",
+ "ftd",
]
def __init__(self, stock: DataFrame, ticker: str, start: str, interval: str):
@@ -97,6 +101,8 @@ class DueDiligenceController:
print(
" warnings company warnings according to Sean Seah book [Market Watch]"
)
+ print(" dp dark pools (ATS) vs OTC data [FINRA]")
+ print(" ftd fails-to-deliver data [SEC]")
print("")
def switch(self, an_input: str):
@@ -175,6 +181,14 @@ class DueDiligenceController:
""" Process short command """
q_view.short_interest(other_args, self.ticker, self.start)
+ def call_dp(self, other_args: List[str]):
+ """ Process dp command """
+ finra_view.dark_pool(other_args, self.ticker)
+
+ def call_ftd(self, other_args: List[str]):
+ """ Process ftd command """
+ sec_view.fails_to_deliver(other_args, self.ticker)
+
def menu(stock: DataFrame, ticker: str, start: str, interval: str):
"""Due Diligence Menu
diff --git a/gamestonk_terminal/due_diligence/finra_view.py b/gamestonk_terminal/due_diligence/finra_view.py
new file mode 100644
index 00000000000..8182e376cb1
--- /dev/null
+++ b/gamestonk_terminal/due_diligence/finra_view.py
@@ -0,0 +1,305 @@
+""" FINRA View """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List, Tuple
+import requests
+import pandas as pd
+from matplotlib import pyplot as plt
+from gamestonk_terminal.config_plot import PLOT_DPI
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import parse_known_args_and_warn, plot_autoscale
+
+
+def getFINRAweeks(tier, is_ats) -> List:
+ """Get FINRA weeks
+
+ Parameters
+ ----------
+ tier : str
+ Stock tier between T1, T2, or OTCE
+ is_ats : bool
+ ATS data if true, NON-ATS otherwise
+
+ Returns
+ ----------
+ List
+ List of response data
+ """
+ req_hdr = {"Accept": "application/json", "Content-Type": "application/json"}
+
+ req_data = {
+ "compareFilters": [
+ {
+ "compareType": "EQUAL",
+ "fieldName": "summaryTypeCode",
+ "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
+ },
+ {
+ "compareType": "EQUAL",
+ "fieldName": "tierIdentifier",
+ "fieldValue": tier,
+ },
+ ],
+ "delimiter": "|",
+ "fields": ["weekStartDate"],
+ "limit": 27,
+ "quoteValues": False,
+ "sortFields": ["-weekStartDate"],
+ }
+
+ response = requests.post(
+ "https://api.finra.org/data/group/otcMarket/name/weeklyDownloadDetails",
+ headers=req_hdr,
+ json=req_data,
+ )
+
+ return response.json() if response.status_code == 200 else list()
+
+
+def getFINRAdata(weekStartDate, tier, ticker, is_ats) -> Tuple[int, List]:
+ """Get FINRA data
+
+ Parameters
+ ----------
+ weekStartDate : str
+ Weekly data to get FINRA data
+ tier : str
+ Stock tier between T1, T2, or OTCE
+ ticker : str
+ Stock ticker to get data from
+ is_ats : bool
+ ATS data if true, NON-ATS otherwise
+
+ Returns
+ ----------
+ str
+ Status code from request
+ List
+ List of response data
+ """
+ req_hdr = {"Accept": "application/json", "Content-Type": "application/json"}
+
+ l_cmp_filters = [
+ {
+ "compareType": "EQUAL",
+ "fieldName": "weekStartDate",
+ "fieldValue": weekStartDate,
+ },
+ {"compareType": "EQUAL", "fieldName": "tierIdentifier", "fieldValue": tier},
+ {
+ "compareType": "EQUAL",
+ "description": "",
+ "fieldName": "summaryTypeCode",
+ "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
+ },
+ ]
+
+ if ticker:
+ l_cmp_filters.append(
+ {
+ "compareType": "EQUAL",
+ "fieldName": "issueSymbolIdentifier",
+ "fieldValue": ticker,
+ }
+ )
+
+ req_data = {
+ "compareFilters": l_cmp_filters,
+ "delimiter": "|",
+ "fields": [
+ "issueSymbolIdentifier",
+ "totalWeeklyShareQuantity",
+ "totalWeeklyTradeCount",
+ "lastUpdateDate",
+ ],
+ "limit": 5000,
+ "quoteValues": False,
+ "sortFields": ["totalWeeklyShareQuantity"],
+ }
+
+ response = requests.post(
+ "https://api.finra.org/data/group/otcMarket/name/weeklySummary",
+ headers=req_hdr,
+ json=req_data,
+ )
+
+ return (
+ response.status_code,
+ response.json() if response.status_code == 200 else list(),
+ )
+
+
+def getTickerFINRAdata(ticker) -> Tuple[pd.DataFrame, pd.DataFrame]:
+ """Get all FINRA data associated with a ticker
+
+ Parameters
+ ----------
+ ticker : str
+ Stock ticker to get data from
+
+ Returns
+ ----------
+ pd.DataFrame
+ Dark Pools (ATS) Data
+ pd.DataFrame
+ OTC (Non-ATS) Data
+ """
+ tiers = ["T1", "T2", "OTCE"]
+
+ l_data = list()
+ for tier in tiers:
+ for d_week in getFINRAweeks(tier, is_ats=True):
+ status_code, response = getFINRAdata(
+ d_week["weekStartDate"], tier, ticker, True
+ )
+ if status_code == 200:
+ if response:
+ d_data = response[0]
+ d_data.update(d_week)
+ l_data.append(d_data)
+ else:
+ break
+
+ df_ats = pd.DataFrame(l_data)
+ if not df_ats.empty:
+ df_ats = df_ats.sort_values("weekStartDate")
+ df_ats = df_ats.set_index("weekStartDate")
+
+ l_data = list()
+ for tier in tiers:
+ for d_week in getFINRAweeks(tier, is_ats=False):
+ status_code, response = getFINRAdata(
+ d_week["weekStartDate"], tier, ticker, False
+ )
+ if status_code == 200:
+ if response:
+ d_data = response[0]
+ d_data.update(d_week)
+ l_data.append(d_data)
+ else:
+ break
+
+ df_otc = pd.DataFrame(l_data)
+ if not df_otc.empty:
+ df_otc = df_otc.sort_values("weekStartDate")
+ df_otc = df_otc.set_index("weekStartDate")
+
+ return df_ats, df_otc
+
+
+def plot_dark_pools(ticker: str, ats: pd.DataFrame, otc: pd.DataFrame):
+ """Plots ATS and NON-ATS data
+
+ Parameters
+ ----------
+ ticker : str
+ Stock ticker to get data from
+ ats : pd.DataFrame
+ Dark Pools (ATS) Data
+ otc : pd.DataFrame
+ OTC (Non-ATS) Data
+ """
+
+ _, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
+
+ plt.subplot(3, 1, (1, 2))
+ if not ats.empty and not otc.empty:
+ plt.bar(
+ ats.index,
+ (ats["totalWeeklyShareQuantity"] + otc["totalWeeklyShareQuantity"])
+ / 1_000_000,
+ color="tab:orange",
+ )
+ plt.bar(
+ otc.index, otc["totalWeeklyShareQuantity"] / 1_000_000, color="tab:blue"
+ )
+ plt.legend(["ATS", "OTC"])
+
+ elif not ats.empty:
+ plt.bar(
+ ats.index,
+ ats["totalWeeklyShareQuantity"] / 1_000_000,
+ color="tab:orange",
+ )
+ plt.legend(["ATS"])
+
+ elif not otc.empty:
+ plt.bar(
+ otc.index, otc["totalWeeklyShareQuantity"] / 1_000_000, color="tab:blue"
+ )
+ plt.legend(["OTC"])
+
+ plt.ylabel("Total Weekly Shares [Million]")
+ plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2)
+ plt.title(f"Dark Pools (ATS) vs OTC (Non-ATS) Data for {ticker}")
+
+ plt.subplot(313)
+ if not ats.empty:
+ plt.plot(
+ ats.index,
+ ats["totalWeeklyShareQuantity"] / ats["totalWeeklyTradeCount"],
+ color="tab:orange",
+ )
+ plt.legend(["ATS"])
+
+ if not otc.empty:
+ plt.plot(
+ otc.index,
+ otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"],
+ color="tab:blue",
+ )
+ plt.legend(["ATS", "OTC"])
+
+ else:
+ plt.plot(
+ otc.index,
+ otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"],
+ color="tab:blue",
+ )
+ plt.legend(["OTC"])
+
+ plt.ylabel("Shares per Trade")
+ plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2)
+ plt.gcf().autofmt_xdate()
+ plt.xlabel("Weeks")
+
+ if gtff.USE_ION:
+ plt.ion()
+
+ plt.show()
+
+
+def dark_pool(other_args: List[str], ticker: str):
+ """Display barchart of dark pool (ATS) and OTC (Non ATS) data
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Stock ticker
+ """
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="dp",
+ description="Display barchart of dark pool (ATS) and OTC (Non ATS) data [Source: FINRA]",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ df_ats, df_otc = getTickerFINRAdata(ticker)
+
+ if df_ats.empty and df_otc.empty:
+ print("No ticker data found!")
+
+ plot_dark_pools(ticker, df_ats, df_otc)
+ print("")
+
+ except Exception as e:
+ print(e)
+ print("")
+ return
diff --git a/gamestonk_terminal/due_diligence/sec_view.py b/gamestonk_terminal/due_diligence/sec_view.py
new file mode 100644
index 00000000000..9eb3f02e8f8
--- /dev/null
+++ b/gamestonk_terminal/due_diligence/sec_view.py
@@ -0,0 +1,108 @@
+""" SEC View """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+from datetime import datetime
+import requests
+import pandas as pd
+from bs4 import BeautifulSoup
+from matplotlib import pyplot as plt
+import matplotlib.dates as mdates
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import (
+ get_user_agent,
+ check_positive,
+ parse_known_args_and_warn,
+)
+
+
+def fails_to_deliver(other_args: List[str], ticker: str):
+ """Display fails-to-deliver data for a given ticker
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args - ["-n", "10"]
+ ticker : str
+ Stock ticker
+ """
+
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="ftd",
+ description="""Prints latest fails-to-deliver data. [Source: SEC]""",
+ )
+ parser.add_argument(
+ "-n",
+ "--num",
+ action="store",
+ dest="n_num",
+ type=check_positive,
+ default=20,
+ help="number of latest fails-to-deliver being printed",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ url_ftds = "https://www.sec.gov/data/foiadocsfailsdatahtm"
+ text_soup_ftds = BeautifulSoup(
+ requests.get(url_ftds, headers={"User-Agent": get_user_agent()}).text,
+ "lxml",
+ )
+
+ table = text_soup_ftds.find("table", {"class": "list"})
+ links = table.findAll("a")
+ link_idx = 0
+ ftds_data = pd.DataFrame()
+ while len(ftds_data) < ns_parser.n_num:
+ if link_idx > len(links):
+ break
+ link = links[link_idx]
+ url = "https://www.sec.gov" + link["href"]
+ all_ftds = pd.read_csv(
+ url,
+ compression="zip",
+ sep="|",
+ engine="python",
+ skipfooter=2,
+ usecols=[0, 2, 3, 5],
+ dtype={"QUANTITY (FAILS)": "int"},
+ )
+ tmp_ftds = all_ftds[all_ftds["SYMBOL"] == ticker]
+ del tmp_ftds["PRICE"]
+ del tmp_ftds["SYMBOL"]
+ # merge the data from this archive
+ ftds_data = pd.concat([ftds_data, tmp_ftds], ignore_index=True)
+ link_idx += 1
+
+ # clip away extra rows
+ ftds_data = ftds_data.sort_values("SETTLEMENT DATE")[-ns_parser.n_num :]
+ ftds_data["SETTLEMENT DATE"] = ftds_data["SETTLEMENT DATE"].apply(
+ lambda x: datetime.strptime(str(x), "%Y%m%d")
+ )
+
+ plt.bar(
+ ftds_data["SETTLEMENT DATE"],
+ ftds_data["QUANTITY (FAILS)"] / 1000,
+ )
+ plt.ylabel("Shares [K]")
+ plt.title(f"Fails-to-deliver Data for {ticker}")
+ plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2)
+ plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
+ plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=7))
+ plt.gcf().autofmt_xdate()
+ plt.xlabel("Days")
+
+ if gtff.USE_ION:
+ plt.ion()
+
+ plt.show()
+
+ print("")
+
+ except Exception as e:
+ print(e, "\n")
diff --git a/gamestonk_terminal/feature_flags.py b/gamestonk_terminal/feature_flags.py
index 5c4910a1ab2..6cea32c0c28 100644
--- a/gamestonk_terminal/feature_flags.py
+++ b/gamestonk_terminal/feature_flags.py
@@ -24,3 +24,6 @@ USE_PLOT_AUTOSCALING = strtobool(os.getenv("GTFF_USE_PLOT_AUTOSCALING", "False")
# Enable thoughts of the day
ENABLE_THOUGHTS_DAY = strtobool(os.getenv("GTFF_ENABLE_THOUGHTS_DAY", "False"))
+
+# Quick exit for testing
+ENABLE_QUICK_EXIT = strtobool(os.getenv("GTFF_ENABLE_QUICK_EXIT", "False"))
diff --git a/gamestonk_terminal/forex/README.md b/gamestonk_terminal/forex/README.md
index b038fcc3535..e7ed6ef5143 100644
--- a/gamestonk_terminal/forex/README.md
+++ b/gamestonk_terminal/forex/README.md
@@ -115,7 +115,6 @@ Retrieve a candlestick chart for the currently loaded instrument. Not a live cha
* -g : Specify the granularity, which is the timeframe each candle represents. The available granularities are Seconds: S5, S10, S15, S30 Minutes: M1, M2, M4, M5, M10, M15, M30 Hours: H1, H2, H3, H4, H6, H8, H12 Day: D, Week: W Month: M. (default=D)
* -c : Specify the number of candles to retrieve. (default=180)
-
* -a : Adds AD (Accumulation/Distribution Index) to the chart. AD is a cumulative indicator that uses volume and price to assess whether a stock is being accumulated or distributed. This provides insight into how strong a trend is. [Investopedia](#https://www.investopedia.com/terms/a/accumulationdistribution.asp)
* -b : Adds Bollinger Bands to the chart. Bollinger bands are a set of trendlines plotted two standard deviations (positively and negatively) away from a simple moving average of a security's price. [Investopedia](#https://www.investopedia.com/terms/b/bollingerbands.asp)
* -C : Adds CCI (Commodity Channel Index) to the chart. CCI is a momentum-based oscillator used to help determine when an investment vehicle is reaching a condition of being overbought or oversold. [Investopedia](#https://www.investopedia.com/terms/c/commoditychannelindex.asp)
@@ -152,5 +151,4 @@ Plots the current orderbook for loaded instrument if one is provided by Oanda. N
```text
usage: positionbook
```
-Plots the current positionbook for the loaded instrument if one is provided by Oanda. Not a live chart.
-
+Plots the current positionbook for the loaded instrument if one is provided by Oanda. Not a live chart.
\ No newline at end of file
diff --git a/gamestonk_terminal/forex/fx_controller.py b/gamestonk_terminal/forex/fx_controller.py
index 390da986f50..b844f2042d0 100644
--- a/gamestonk_terminal/forex/fx_controller.py
+++ b/gamestonk_terminal/forex/fx_controller.py
@@ -101,6 +101,7 @@ class ForexController:
print(
" edacusum detects abrupt changes using cumulative sum algorithm"
)
+
print("")
def switch(self, an_input: str):
diff --git a/gamestonk_terminal/forex/fx_view.py b/gamestonk_terminal/forex/fx_view.py
index 4128e367cf8..c33f63f83a4 100644
--- a/gamestonk_terminal/forex/fx_view.py
+++ b/gamestonk_terminal/forex/fx_view.py
@@ -51,6 +51,17 @@ def get_fx_price(accountID, instrument, other_args: List[str]):
print(d_error["errorMessage"], "\n")
+def get_account_summary(accountID, other_args: List[str]):
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="summary",
+ description="Print some information about your account.",
+ )
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+<
def get_account_summary(accountID, other_args: List[str]):
parser = argparse.ArgumentParser(
add_help=False,
@@ -270,7 +281,7 @@ def create_order(accountID, instrument, other_args: List[str]):
print(d_error["errorMessage"], "\n")
except Exception as e:
print(e)
-
+
def cancel_pending_order(accountID, other_args: List[str]):
parser = argparse.ArgumentParser(
@@ -337,6 +348,7 @@ def get_pending_orders(accountID, other_args):
else:
print(df.to_string(index=False))
print("")
+
except V20Error as e:
d_error = eval(e.msg)
print(d_error["errorMessage"], "\n")
@@ -381,6 +393,17 @@ def get_open_positions(accountID, other_args):
print(d_error["errorMessage"], "\n")
+def get_open_trades(accountID, other_args):
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="trades",
+ description="Gets information about open trades.",
+ )
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+
def get_open_trades(accountID, other_args):
parser = argparse.ArgumentParser(
add_help=False,
@@ -416,8 +439,10 @@ def get_open_trades(accountID, other_args):
"unrealizedPL": "Unrealized P/L",
}
)
+
print(df.to_string(index=False))
print("")
+
except KeyError:
print("No trades were found")
print("")
@@ -487,6 +512,7 @@ def close_trade(accountID, other_args: List[str]):
print(e, "\n")
+
def show_candles(accountID, instrument, other_args: List[str]):
parser = argparse.ArgumentParser(
add_help=False,
@@ -597,10 +623,12 @@ def show_candles(accountID, instrument, other_args: List[str]):
returnfig=True,
addplot=plots_to_add,
)
+
ax[0].set_title(f"{instrument} {ns_parser.granularity}")
ax[0].legend(legends)
for i in range(0, len(subplot_legends), 2):
ax[subplot_legends[i]].legend(subplot_legends[i + 1])
+
print("")
except V20Error as e:
d_error = eval(e.msg)
@@ -609,6 +637,7 @@ def show_candles(accountID, instrument, other_args: List[str]):
print(e)
+
def add_plots(df, ns_parser):
panel_number = 2
plots_to_add = []
@@ -788,6 +817,7 @@ def get_candles_dataframe(accountID, instrument, parameters):
print(d_error["errorMessage"], "\n")
+
def load(other_args: List[str]):
"""Load a forex instrument to use"""
parser = argparse.ArgumentParser(
@@ -876,3 +906,4 @@ def format_instrument(instrument, char):
except TypeError:
print("Please load an instrument")
print("")
+
diff --git a/gamestonk_terminal/fundamental_analysis/README.md b/gamestonk_terminal/fundamental_analysis/README.md
index 5c2c114b0ce..914675970e5 100644
--- a/gamestonk_terminal/fundamental_analysis/README.md
+++ b/gamestonk_terminal/fundamental_analysis/README.md
@@ -6,7 +6,9 @@ This menu aims to extract all fundamentals of a pre-loaded company, and the usag
* screen info about the company [Finviz]
* [mgmt](#mgmt)
* management team of the company [Business Insider]
-
+* [score](#score)
+ * investing score from Warren Buffett, Joseph Piotroski and Benjamin Graham [FMP]
+
[MARKET WATCH](#MARKET_WATCH)
* [income](#income)
@@ -323,3 +325,12 @@ Prints the growth of several financial statement items and ratios over time. Thi
* n : Number of latest years/quarters. Default 1.
* q : Quarter fundamental data flag. Default False.
+
+
+### score
+
+```text
+usage: score
+```
+
+Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: Financial Modeling Prep]
diff --git a/gamestonk_terminal/fundamental_analysis/alpha_vantage_controller.py b/gamestonk_terminal/fundamental_analysis/alpha_vantage_controller.py
new file mode 100644
index 00000000000..01d029a569c
--- /dev/null
+++ b/gamestonk_terminal/fundamental_analysis/alpha_vantage_controller.py
@@ -0,0 +1,168 @@
+""" Alpha Vantage Controller """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+from prompt_toolkit.completion import NestedCompleter
+
+from gamestonk_terminal.fundamental_analysis import alpha_vantage_view as avv
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import get_flair
+from gamestonk_terminal.menu import session
+
+
+class AlphaVantageController:
+ """ Alpha Vantage Controller """
+
+ # Command choices
+ CHOICES = [
+ "help",
+ "q",
+ "quit",
+ "overview",
+ "key",
+ "income",
+ "balance",
+ "cash",
+ "earnings",
+ ]
+
+ def __init__(self, ticker: str, start: str, interval: str):
+ """Constructor
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Stat date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ self.ticker = ticker
+ self.start = start
+ self.interval = interval
+ self.av_parser = argparse.ArgumentParser(add_help=False, prog="av")
+ self.av_parser.add_argument(
+ "cmd",
+ choices=self.CHOICES,
+ )
+
+ def print_help(self):
+ """ Print help """
+
+ intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
+
+ if self.start:
+ print(
+ f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
+ )
+ else:
+ print(f"\n{intraday} Stock: {self.ticker}")
+
+ print("\nAlpha Vantage:")
+ print(" help show this alpha vantage menu again")
+ print(" q quit this menu, and shows back to main menu")
+ print(" quit quit to abandon program")
+ print("")
+ print(" overview overview of the company")
+ print(" key company key metrics")
+ print(" income income statements of the company")
+ print(" balance balance sheet of the company")
+ print(" cash cash flow of the company")
+ print(" earnings earnings dates and reported EPS")
+ print("")
+
+ def switch(self, an_input: str):
+ """Process and dispatch input
+
+ Returns
+ -------
+ True, False or None
+ False - quit the menu
+ True - quit the program
+ None - continue in the menu
+ """
+ (known_args, other_args) = self.av_parser.parse_known_args(an_input.split())
+
+ return getattr(
+ self, "call_" + known_args.cmd, lambda: "Command not recognized!"
+ )(other_args)
+
+ def call_help(self, _):
+ """Process Help command"""
+ self.print_help()
+
+ def call_q(self, _):
+ """Process Q command - quit the menu"""
+ return False
+
+ def call_quit(self, _):
+ """Process Quit command - quit the program"""
+ return True
+
+ def call_overview(self, other_args: List[str]):
+ """ Process overview command """
+ avv.overview(other_args, self.ticker)
+
+ def call_key(self, other_args: List[str]):
+ """ Process overview command """
+ avv.key(other_args, self.ticker)
+
+ def call_income(self, other_args: List[str]):
+ """ Process income command """
+ avv.income_statement(other_args, self.ticker)
+
+ def call_balance(self, other_args: List[str]):
+ """ Process balance command """
+ avv.balance_sheet(other_args, self.ticker)
+
+ def call_cash(self, other_args: List[str]):
+ """ Process cash command """
+ avv.cash_flow(other_args, self.ticker)
+
+ def call_earnings(self, other_args: List[str]):
+ """ Process earnings command """
+ avv.earnings(other_args, self.ticker)
+
+
+def menu(ticker: str, start: str, interval: str):
+ """Alpha Vantage menu
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Start date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ av_controller = AlphaVantageController(ticker, start, interval)
+ av_controller.call_help(None)
+
+ while True:
+ # Get input command from user
+ if session and gtff.USE_PROMPT_TOOLKIT:
+ completer = NestedCompleter.from_nested_dict(
+ {c: None for c in av_controller.CHOICES}
+ )
+
+ an_input = session.prompt(
+ f"{get_flair()} (fa)>(av)> ",
+ completer=completer,
+ )
+ else:
+ an_input = input(f"{get_flair()} (fa)>(av)> ")
+
+ try:
+ process_input = av_controller.switch(an_input)
+
+ if process_input is not None:
+ return process_input
+
+ except SystemExit:
+ print("The command selected doesn't exist\n")
+ continue
diff --git a/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py b/gamestonk_terminal/fundamental_analysis/alpha_vantage_view.py
similarity index 79%
rename from gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py
rename to gamestonk_terminal/fundamental_analysis/alpha_vantage_view.py
index 36c648b614c..2adb4f8d177 100644
--- a/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py
+++ b/gamestonk_terminal/fundamental_analysis/alpha_vantage_view.py
@@ -1,112 +1,33 @@
+""" Alpha Vantage View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
import requests
+
from alpha_vantage.fundamentaldata import FundamentalData
import pandas as pd
-from pandas.io.json import json_normalize
+
from gamestonk_terminal import config_terminal as cfg
from gamestonk_terminal.dataframe_helpers import clean_df_index
from gamestonk_terminal.helper_funcs import (
check_positive,
long_number_format,
parse_known_args_and_warn,
- get_flair,
)
-from gamestonk_terminal.menu import session
-from prompt_toolkit.completion import NestedCompleter
-def print_menu(s_ticker, s_start, s_interval):
- """ Print help """
+def overview(other_args: List[str], ticker: str):
+ """Alpha Vantage stock ticker overview
- s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
- if s_start:
- print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
- else:
- print(f"\n{s_intraday} Stock: {s_ticker}")
-
- print("\nAlpha Vantage:")
- print(" help show this alpha vantage menu again")
- print(" q quit this menu, and shows back to main menu")
- print(" quit quit to abandon program")
- print("")
- print(" overview overview of the company")
- print(" income income statements of the company")
- print(" balance balance sheet of the company")
- print(" cash cash flow of the company")
- print(" earnings earnings dates and reported EPS")
- print("")
-
-
-def menu(s_ticker, s_start, s_interval):
-
- # Add list of arguments that the fundamental analysis parser accepts
- av_parser = argparse.ArgumentParser(prog="av", add_help=False)
- choices = [
- "help",
- "q",
- "quit",
- "overview",
- "income",
- "balance",
- "cash",
- "earnings",
- ]
- av_parser.add_argument("cmd", choices=choices)
- completer = NestedCompleter.from_nested_dict({c: None for c in choices})
-
- print_menu(s_ticker, s_start, s_interval)
-
- # Loop forever and ever
- while True:
- # Get input command from user
- if session:
- as_input = session.prompt(
- f"{get_flair()} (fa)>(av)> ",
- completer=completer,
- )
- else:
- as_input = input(f"{get_flair()} (fa)>(av)> ")
-
- # Parse alpha vantage command of the list of possible commands
- try:
- (ns_known_args, l_args) = av_parser.parse_known_args(as_input.split())
-
- except SystemExit:
- print("The command selected doesn't exist\n")
- continue
-
- if ns_known_args.cmd == "help":
- print_menu(s_ticker, s_start, s_interval)
-
- elif ns_known_args.cmd == "q":
- # Just leave the menu
- return False
-
- elif ns_known_args.cmd == "quit":
- # Abandon the program
- return True
-
- elif ns_known_args.cmd == "overview":
- overview(l_args, s_ticker)
-
- elif ns_known_args.cmd == "income":
- income_statement(l_args, s_ticker)
-
- elif ns_known_args.cmd == "balance":
- balance_sheet(l_args, s_ticker)
-
- elif ns_known_args.cmd == "cash":
- cash_flow(l_args, s_ticker)
-
- elif ns_known_args.cmd == "earnings":
- earnings(l_args, s_ticker)
-
- else:
- print("Command not recognized!")
-
-
-def overview(l_args, s_ticker):
parser = argparse.ArgumentParser(
add_help=False,
prog="overview",
@@ -128,18 +49,18 @@ def overview(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
# Request OVERVIEW data from Alpha Vantage API
- s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
+ s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
# Parse json data to dataframe
- df_fa = json_normalize(result.json())
+ df_fa = pd.json_normalize(result.json())
# Keep json data sorting in dataframe
df_fa = df_fa[list(result.json().keys())].T
df_fa = df_fa.applymap(lambda x: long_number_format(x))
@@ -182,7 +103,17 @@ def overview(l_args, s_ticker):
return
-def key(l_args, s_ticker):
+def key(other_args: List[str], ticker: str):
+ """Alpha Vantage key metrics
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="key",
@@ -196,17 +127,17 @@ def key(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
# Request OVERVIEW data
- s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
+ s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
- df_fa = json_normalize(result.json())
+ df_fa = pd.json_normalize(result.json())
df_fa = df_fa[list(result.json().keys())].T
df_fa = df_fa.applymap(lambda x: long_number_format(x))
clean_df_index(df_fa)
@@ -248,10 +179,20 @@ def key(l_args, s_ticker):
return
-def income_statement(l_args, s_ticker):
+def income_statement(other_args: List[str], ticker: str):
+ """Alpha Vantage income statement
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
- prog="incom",
+ prog="income",
description="""
Prints a complete income statement over time. This can be either quarterly or annually.
The following fields are expected: Accepted date, Cost and expenses, Cost of revenue,
@@ -283,7 +224,7 @@ def income_statement(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -295,10 +236,10 @@ def income_statement(l_args, s_ticker):
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
if ns_parser.b_quarter:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_income_statement_quarterly(symbol=s_ticker)
+ df_fa, _ = fd.get_income_statement_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_income_statement_annual(symbol=s_ticker)
+ df_fa, _ = fd.get_income_statement_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -310,7 +251,17 @@ def income_statement(l_args, s_ticker):
return
-def balance_sheet(l_args, s_ticker):
+def balance_sheet(other_args: List[str], ticker: str):
+ """Alpha Vantage balance sheet
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="balance",
@@ -351,7 +302,7 @@ def balance_sheet(l_args, s_ticker):
)
try:
- (ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
+ (ns_parser, l_unknown_args) = parser.parse_known_args(other_args)
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}\n")
@@ -365,10 +316,10 @@ def balance_sheet(l_args, s_ticker):
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
if ns_parser.b_quarter:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_balance_sheet_quarterly(symbol=s_ticker)
+ df_fa, _ = fd.get_balance_sheet_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_balance_sheet_annual(symbol=s_ticker)
+ df_fa, _ = fd.get_balance_sheet_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -380,7 +331,17 @@ def balance_sheet(l_args, s_ticker):
return
-def cash_flow(l_args, s_ticker):
+def cash_flow(other_args: List[str], ticker: str):
+ """Alpha Vantage cash flow
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="cash",
@@ -419,7 +380,7 @@ def cash_flow(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -431,10 +392,10 @@ def cash_flow(l_args, s_ticker):
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
if ns_parser.b_quarter:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_cash_flow_quarterly(symbol=s_ticker)
+ df_fa, _ = fd.get_cash_flow_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
- df_fa, _ = fd.get_cash_flow_annual(symbol=s_ticker)
+ df_fa, _ = fd.get_cash_flow_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -446,7 +407,17 @@ def cash_flow(l_args, s_ticker):
return
-def earnings(l_args, s_ticker):
+def earnings(other_args: List[str], ticker: str):
+ """Alpha Vantage earnings
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="earnings",
@@ -475,7 +446,7 @@ def earnings(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -487,13 +458,13 @@ def earnings(l_args, s_ticker):
# Request EARNINGS data from Alpha Vantage API
s_req = (
"https://www.alphavantage.co/query?function=EARNINGS&"
- f"symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
+ f"symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
)
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
- df_fa = json_normalize(result.json())
+ df_fa = pd.json_normalize(result.json())
if ns_parser.b_quarter:
df_fa = pd.DataFrame(df_fa["quarterlyEarnings"][0])
df_fa = df_fa[
diff --git a/gamestonk_terminal/fundamental_analysis/business_insider_api.py b/gamestonk_terminal/fundamental_analysis/business_insider_view.py
similarity index 86%
rename from gamestonk_terminal/fundamental_analysis/business_insider_api.py
rename to gamestonk_terminal/fundamental_analysis/business_insider_view.py
index 4811c2585be..bb0d4db3d6c 100644
--- a/gamestonk_terminal/fundamental_analysis/business_insider_api.py
+++ b/gamestonk_terminal/fundamental_analysis/business_insider_view.py
@@ -1,4 +1,8 @@
+""" Business Insider View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
import requests
from bs4 import BeautifulSoup
import pandas as pd
@@ -6,7 +10,17 @@ from rapidfuzz import fuzz
from gamestonk_terminal.helper_funcs import get_user_agent, parse_known_args_and_warn
-def management(l_args, s_ticker):
+def management(other_args: List[str], ticker: str):
+ """Display company's managers
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Stock ticker
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="mgmt",
@@ -17,12 +31,12 @@ def management(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
url_market_business_insider = (
- f"https://markets.businessinsider.com/stocks/{s_ticker.lower()}-stock"
+ f"https://markets.businessinsider.com/stocks/{ticker.lower()}-stock"
)
text_soup_market_business_insider = BeautifulSoup(
requests.get(
@@ -42,7 +56,7 @@ def management(l_args, s_ticker):
found_h2s[next_h2.text] = next_table
if found_h2s.get("Management") is None:
- print(f"No management information in Business Insider for {s_ticker}")
+ print(f"No management information in Business Insider for {ticker}")
print("")
return
@@ -73,7 +87,7 @@ def management(l_args, s_ticker):
for s_name in df_management.index:
df_management.loc[s_name][
"Info"
- ] = f"http://www.google.com/search?q={s_name} {s_ticker.upper()}".replace(
+ ] = f"http://www.google.com/search?q={s_name} {ticker.upper()}".replace(
" ", "%20"
)
diff --git a/gamestonk_terminal/fundamental_analysis/fa_controller.py b/gamestonk_terminal/fundamental_analysis/fa_controller.py
new file mode 100644
index 00000000000..5de204ab675
--- /dev/null
+++ b/gamestonk_terminal/fundamental_analysis/fa_controller.py
@@ -0,0 +1,262 @@
+""" Fundamental Analysis Controller """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+from prompt_toolkit.completion import NestedCompleter
+
+from gamestonk_terminal.fundamental_analysis import alpha_vantage_controller as avc
+from gamestonk_terminal.fundamental_analysis import business_insider_view as biw
+from gamestonk_terminal.fundamental_analysis import (
+ financial_modeling_prep_controller as fmpc,
+ financial_modeling_prep_view as fmpv,
+)
+from gamestonk_terminal.fundamental_analysis import finviz_view
+from gamestonk_terminal.fundamental_analysis import market_watch_view
+from gamestonk_terminal.fundamental_analysis import yahoo_finance_view
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import get_flair
+from gamestonk_terminal.menu import session
+
+
+class FundamentalAnalysisController:
+ """ Fundamental Analysis Controller """
+
+ # Command choices
+ CHOICES = [
+ "help",
+ "q",
+ "quit",
+ "score",
+ "screener",
+ "income",
+ "balance",
+ "cash",
+ "mgmt",
+ "info",
+ "shrs",
+ "sust",
+ "cal",
+ "av",
+ "fmp",
+ ]
+
+ def __init__(self, ticker: str, start: str, interval: str):
+ """Constructor
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Stat date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ self.ticker = ticker
+ self.start = start
+ self.interval = interval
+
+ self.fa_parser = argparse.ArgumentParser(add_help=False, prog="fa")
+ self.fa_parser.add_argument(
+ "cmd",
+ choices=self.CHOICES,
+ )
+
+ def print_help(self):
+ """ Print help """
+
+ intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
+
+ if self.start:
+ print(
+ f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
+ )
+ else:
+ print(f"\n{intraday} Stock: {self.ticker}")
+
+ print(
+ "\nFundamental Analysis:"
+ ) # https://github.com/JerBouma/FundamentalAnalysis
+ print(" help show this fundamental analysis menu again")
+ print(" q quit this menu, and shows back to main menu")
+ print(" quit quit to abandon program")
+ print("")
+ print(" screener screen info about the company [Finviz]")
+ print(" mgmt management team of the company [Business Insider]")
+ print(
+ " score investing score from Warren Buffett, Joseph Piotroski and Benjamin Graham [FMP]"
+ )
+ print("")
+ print("Market Watch API")
+ print(" income income statement of the company")
+ print(" balance balance sheet of the company")
+ print(" cash cash flow statement of the company")
+ print("")
+ print("Yahoo Finance API")
+ print(" info information scope of the company")
+ print(" shrs shareholders of the company")
+ print(" sust sustainability values of the company")
+ print(" cal calendar earnings and estimates of the company")
+ print("")
+ print("Other Sources:")
+ print("> av Alpha Vantage MENU")
+ print("> fmp Financial Modeling Prep MENU")
+ print("")
+
+ def switch(self, an_input: str):
+ """Process and dispatch input
+
+ Returns
+ -------
+ True, False or None
+ False - quit the menu
+ True - quit the program
+ None - continue in the menu
+ """
+
+ (known_args, other_args) = self.fa_parser.parse_known_args(an_input.split())
+
+ return getattr(
+ self, "call_" + known_args.cmd, lambda: "Command not recognized!"
+ )(other_args)
+
+ def call_help(self, _):
+ """Process Help command"""
+ self.print_help()
+
+ def call_q(self, _):
+ """Process Q command - quit the menu"""
+ return False
+
+ def call_quit(self, _):
+ """Process Quit command - quit the program"""
+ return True
+
+ def call_mgmt(self, other_args: List[str]):
+ """ Process mgmt command """
+ biw.management(other_args, self.ticker)
+
+ def call_screener(self, other_args: List[str]):
+ """ Process screener command """
+ finviz_view.screener(other_args, self.ticker)
+
+ def call_score(self, other_args: List[str]):
+ """ Process score command """
+ fmpv.valinvest_score(other_args, self.ticker)
+
+ def call_income(self, other_args: List[str]):
+ """ Process income command """
+ market_watch_view.income(other_args, self.ticker)
+
+ def call_balance(self, other_args: List[str]):
+ """ Process balance command """
+ market_watch_view.balance(other_args, self.ticker)
+
+ def call_cash(self, other_args: List[str]):
+ """ Process cash command """
+ market_watch_view.cash(other_args, self.ticker)
+
+ def call_info(self, other_args: List[str]):
+ """ Process info command """
+ yahoo_finance_view.info(other_args, self.ticker)
+
+ def call_shrs(self, other_args: List[str]):
+ """ Process shrs command """
+ yahoo_finance_view.shareholders(other_args, self.ticker)
+
+ def call_sust(self, other_args: List[str]):
+ """ Process sust command """
+ yahoo_finance_view.sustainability(other_args, self.ticker)
+
+ def call_cal(self, other_args: List[str]):
+ """ Process cal command """
+ yahoo_finance_view.calendar_earnings(other_args, self.ticker)
+
+ # pylint: disable=unused-argument
+ def call_av(self, other_args: List[str]):
+ """ Process av command """
+ ret = avc.menu(self.ticker, self.start, self.interval)
+
+ if ret is not True:
+ self.print_help()
+
+ # pylint: disable=unused-argument
+ def call_fmp(self, other_args: List[str]):
+ """ Process fmp command """
+ ret = fmpc.menu(self.ticker, self.start, self.interval)
+
+ if ret is not True:
+ self.print_help()
+
+
+def key_metrics_explained(other_args: List[str]):
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="info",
+ description="""
+ Provides information about main key metrics. Namely: EBITDA,
+ EPS, P/E, PEG, FCF, P/B, ROE, DPR, P/S, Dividend Yield Ratio, D/E, and Beta.
+ """,
+ )
+
+ try:
+ (_, l_unknown_args) = parser.parse_known_args(other_args)
+
+ if l_unknown_args:
+ print(f"The following args couldn't be interpreted: {l_unknown_args}")
+
+ filepath = "fundamental_analysis/key_metrics_explained.txt"
+ with open(filepath) as fp:
+ line = fp.readline()
+ while line:
+ print(f"{line.strip()}")
+ line = fp.readline()
+ print("")
+
+ except Exception as e:
+ print(e)
+ print("ERROR!\n")
+ return
+
+
+def menu(ticker: str, start: str, interval: str):
+ """Fundamental Analysis menu
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Start date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ fa_controller = FundamentalAnalysisController(ticker, start, interval)
+ fa_controller.call_help(None)
+
+ while True:
+ # Get input command from user
+ if session and gtff.USE_PROMPT_TOOLKIT:
+ completer = NestedCompleter.from_nested_dict(
+ {c: None for c in fa_controller.CHOICES}
+ )
+
+ an_input = session.prompt(
+ f"{get_flair()} (fa)> ",
+ completer=completer,
+ )
+ else:
+ an_input = input(f"{get_flair()} (fa)> ")
+
+ try:
+ process_input = fa_controller.switch(an_input)
+
+ if process_input is not None:
+ return process_input
+
+ except SystemExit:
+ print("The command selected doesn't exist\n")
+ continue
diff --git a/gamestonk_terminal/fundamental_analysis/fa_menu.py b/gamestonk_terminal/fundamental_analysis/fa_menu.py
deleted file mode 100644
index 426fa418526..00000000000
--- a/gamestonk_terminal/fundamental_analysis/fa_menu.py
+++ /dev/null
@@ -1,193 +0,0 @@
-import argparse
-
-from gamestonk_terminal.fundamental_analysis import alpha_vantage_api as av_api
-from gamestonk_terminal.fundamental_analysis import business_insider_api as bi_api
-from gamestonk_terminal.fundamental_analysis import (
- financial_modeling_prep_api as fmp_api,
-)
-from gamestonk_terminal.fundamental_analysis import finviz_api as fvz_api
-from gamestonk_terminal.fundamental_analysis import market_watch_api as mw_api
-from gamestonk_terminal.fundamental_analysis import yahoo_finance_api as yf_api
-from gamestonk_terminal import feature_flags as gtff
-from gamestonk_terminal.helper_funcs import get_flair
-from gamestonk_terminal.menu import session
-from prompt_toolkit.completion import NestedCompleter
-
-
-def print_fundamental_analysis(s_ticker, s_start, s_interval):
- """ Print help """
-
- s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
-
- if s_start:
- print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
- else:
- print(f"\n{s_intraday} Stock: {s_ticker}")
-
- print("\nFundamental Analysis:") # https://github.com/JerBouma/FundamentalAnalysis
- print(" help show this fundamental analysis menu again")
- print(" q quit this menu, and shows back to main menu")
- print(" quit quit to abandon program")
- print("")
- print(" screener screen info about the company [Finviz]")
- print(" mgmt management team of the company [Business Insider]")
- print("")
- print("Market Watch API")
- print(" income income statement of the company")
- print(" balance balance sheet of the company")
- print(" cash cash flow statement of the company")
- print("")
- print("Yahoo Finance API")
- print(" info information scope of the company")
- print(" shrs shareholders of the company")
- print(" sust sustainability values of the company")
- print(" cal calendar earnings and estimates of the company")
- print("")
- print("Other Sources:")
- print("> av Alpha Vantage MENU")
- print("> fmp Financial Modeling Prep MENU")
- print("")
- return
-
-
-def key_metrics_explained(l_args):
- parser = argparse.ArgumentParser(
- add_help=False,
- prog="info",
- description="""
- Provides information about main key metrics. Namely: EBITDA,
- EPS, P/E, PEG, FCF, P/B, ROE, DPR, P/S, Dividend Yield Ratio, D/E, and Beta.
- """,
- )
-
- try:
- (_, l_unknown_args) = parser.parse_known_args(l_args)
-
- if l_unknown_args:
- print(f"The following args couldn't be interpreted: {l_unknown_args}")
-
- filepath = "fundamental_analysis/key_metrics_explained.txt"
- with open(filepath) as fp:
- line = fp.readline()
- while line:
- print(f"{line.strip()}")
- line = fp.readline()
- print("")
-
- except Exception as e:
- print(e)
- print("ERROR!\n")
- return
-
-
-# pylint: disable=too-many-branches
-def fa_menu(s_ticker, s_start, s_interval):
-
- # Add list of arguments that the fundamental analysis parser accepts
- fa_parser = argparse.ArgumentParser(prog="fa", add_help=False)
- choices = [
- "help",
- "q",
- "quit",
- "screener",
- "income",
- "balance",
- "cash",
- "mgmt",
- "info",
- "shrs",
- "sust",
- "cal",
- "av",
- "fmp",
- ]
- fa_parser.add_argument("cmd", choices=choices)
- completer = NestedCompleter.from_nested_dict({c: None for c in choices})
-
- should_print_help = True
-
- # Loop forever and ever
- while True:
- if should_print_help:
- print_fundamental_analysis(s_ticker, s_start, s_interval)
- should_print_help = False
-
- # Get input command from user
- if session and gtff.USE_PROMPT_TOOLKIT:
- as_input = session.prompt(
- f"{get_flair()} (fa)> ",
- completer=completer,
- )
- else:
- as_input = input(f"{get_flair()} (fa)> ")
-
- # Parse fundamental analysis command of the list of possible commands
- try:
- (ns_known_args, l_args) = fa_parser.parse_known_args(as_input.split())
-
- except SystemExit:
- print("The command selected doesn't exist\n")
- continue
-
- if ns_known_args.cmd == "help":
- should_print_help = True
-
- elif ns_known_args.cmd == "q":
- # Just leave the FA menu
- return False
-
- elif ns_known_args.cmd == "quit":
- # Abandon the program
- return True
-
- # BUSINESS INSIDER API
- elif ns_known_args.cmd == "mgmt":
- bi_api.management(l_args, s_ticker)
-
- # FINVIZ API
- elif ns_known_args.cmd == "screener":
- fvz_api.screener(l_args, s_ticker)
-
- # MARKET WATCH API
- elif ns_known_args.cmd == "income":
- mw_api.income(l_args, s_ticker)
-
- elif ns_known_args.cmd == "balance":
- mw_api.balance(l_args, s_ticker)
-
- elif ns_known_args.cmd == "cash":
- mw_api.cash(l_args, s_ticker)
-
- # YAHOO FINANCE API
- elif ns_known_args.cmd == "info":
- yf_api.info(l_args, s_ticker)
-
- elif ns_known_args.cmd == "shrs":
- yf_api.shareholders(l_args, s_ticker)
-
- elif ns_known_args.cmd == "sust":
- yf_api.sustainability(l_args, s_ticker)
-
- elif ns_known_args.cmd == "cal":
- yf_api.calendar_earnings(l_args, s_ticker)
-
- # ALPHA VANTAGE API
- elif ns_known_args.cmd == "av":
- b_quit = av_api.menu(s_ticker, s_start, s_interval)
-
- if b_quit:
- return True
- else:
- should_print_help = True
-
- # FINANCIAL MODELING PREP API
- elif ns_known_args.cmd == "fmp":
- b_quit = fmp_api.menu(s_ticker, s_start, s_interval)
-
- if b_quit:
- return True
- else:
- should_print_help = True
-
- else:
- print("Command not recognized!")
diff --git a/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_controller.py b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_controller.py
new file mode 100644
index 00000000000..e68077aa0f9
--- /dev/null
+++ b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_controller.py
@@ -0,0 +1,194 @@
+""" Financial Modeling Prep Controller """
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+from prompt_toolkit.completion import NestedCompleter
+
+from gamestonk_terminal.fundamental_analysis import financial_modeling_prep_view as fmpv
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import (
+ get_flair,
+)
+from gamestonk_terminal.menu import session
+
+
+class FinancialModelingPrepController:
+ """ Financial Modeling Prep Controller """
+
+ # Command choices
+ CHOICES = [
+ "help",
+ "q",
+ "quit",
+ "profile",
+ "quote",
+ "enterprise",
+ "dcf",
+ "income",
+ "balance",
+ "cash",
+ "metrics",
+ "ratios",
+ "growth",
+ ]
+
+ def __init__(self, ticker: str, start: str, interval: str):
+ """Constructor
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Stat date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ self.ticker = ticker
+ self.start = start
+ self.interval = interval
+ self.fmp_parser = argparse.ArgumentParser(add_help=False, prog="fmp")
+ self.fmp_parser.add_argument(
+ "cmd",
+ choices=self.CHOICES,
+ )
+
+ def print_help(self):
+ """ Print help """
+
+ intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
+
+ if self.start:
+ print(
+ f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
+ )
+ else:
+ print(f"\n{intraday} Stock: {self.ticker}")
+
+ print("\nFinancial Modeling Prep API")
+ print(" help show this financial modeling prep menu again")
+ print(" q quit this menu, and shows back to main menu")
+ print(" quit quit to abandon program")
+ print("")
+ print(" profile profile of the company")
+ print(" quote quote of the company")
+ print(" enterprise enterprise value of the company over time")
+ print(" dcf discounted cash flow of the company over time")
+ print(" income income statements of the company")
+ print(" balance balance sheet of the company")
+ print(" cash cash flow statement of the company")
+ print(" metrics key metrics of the company")
+ print(" ratios financial ratios of the company")
+ print(" growth financial statement growth of the company")
+ print("")
+
+ def switch(self, an_input: str):
+ """Process and dispatch input
+
+ Returns
+ -------
+ True, False or None
+ False - quit the menu
+ True - quit the program
+ None - continue in the menu
+ """
+ (known_args, other_args) = self.fmp_parser.parse_known_args(an_input.split())
+
+ return getattr(
+ self, "call_" + known_args.cmd, lambda: "Command not recognized!"
+ )(other_args)
+
+ def call_help(self, _):
+ """Process Help command"""
+ self.print_help()
+
+ def call_q(self, _):
+ """Process Q command - quit the menu"""
+ return False
+
+ def call_quit(self, _):
+ """Process Quit command - quit the program"""
+ return True
+
+ def call_profile(self, other_args: List[str]):
+ """ Process profile command """
+ fmpv.profile(other_args, self.ticker)
+
+ def call_quote(self, other_args: List[str]):
+ """ Process quote command """
+ fmpv.quote(other_args, self.ticker)
+
+ def call_enterprise(self, other_args: List[str]):
+ """ Process income command """
+ fmpv.enterprise(other_args, self.ticker)
+
+ def call_dcf(self, other_args: List[str]):
+ """ Process dcf command """
+ fmpv.discounted_cash_flow(other_args, self.ticker)
+
+ def call_income(self, other_args: List[str]):
+ """ Process income command """
+ fmpv.income_statement(other_args, self.ticker)
+
+ def call_balance(self, other_args: List[str]):
+ """ Process balance command """
+ fmpv.balance_sheet(other_args, self.ticker)
+
+ def call_cash(self, other_args: List[str]):
+ """ Process cash command """
+ fmpv.cash_flow(other_args, self.ticker)
+
+ def call_metrics(self, other_args: List[str]):
+ """ Process metrics command """
+ fmpv.key_metrics(other_args, self.ticker)
+
+ def call_ratios(self, other_args: List[str]):
+ """ Process cash command """
+ fmpv.financial_ratios(other_args, self.ticker)
+
+ def call_growth(self, other_args: List[str]):
+ """ Process cash command """
+ fmpv.financial_statement_growth(other_args, self.ticker)
+
+
+def menu(ticker: str, start: str, interval: str):
+ """Financial Modeling Prep menu
+
+ Parameters
+ ----------
+ ticker : str
+ Fundamental analysis ticker symbol
+ start : str
+ Start date of the stock data
+ interval : str
+ Stock data interval
+ """
+
+ fmp_controller = FinancialModelingPrepController(ticker, start, interval)
+ fmp_controller.call_help(None)
+
+ while True:
+ # Get input command from user
+ if session and gtff.USE_PROMPT_TOOLKIT:
+ completer = NestedCompleter.from_nested_dict(
+ {c: None for c in fmp_controller.CHOICES}
+ )
+
+ an_input = session.prompt(
+ f"{get_flair()} (fa)>(fmp)> ",
+ completer=completer,
+ )
+ else:
+ an_input = input(f"{get_flair()} (fa)>(fmp)> ")
+
+ try:
+ process_input = fmp_controller.switch(an_input)
+
+ if process_input is not None:
+ return process_input
+
+ except SystemExit:
+ print("The command selected doesn't exist\n")
+ continue
diff --git a/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_view.py
similarity index 77%
rename from gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py
rename to gamestonk_terminal/fundamental_analysis/financial_modeling_prep_view.py
index 7189fce3fd5..f5bda9f8a17 100644
--- a/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py
+++ b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_view.py
@@ -1,139 +1,66 @@
+""" Financial Modeling Prep View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
from datetime import datetime
import pandas as pd
+import valinvest
import FundamentalAnalysis as fa # Financial Modeling Prep
-from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import config_terminal as cfg
from gamestonk_terminal.dataframe_helpers import clean_df_index
from gamestonk_terminal.helper_funcs import (
long_number_format,
check_positive,
parse_known_args_and_warn,
- get_flair,
)
-from gamestonk_terminal.menu import session
-def print_menu(s_ticker, s_start, s_interval):
- """ Print help """
+def valinvest_score(other_args: List[str], ticker: str):
+ """Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: FMP]
- s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
- if s_start:
- print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
- else:
- print(f"\n{s_intraday} Stock: {s_ticker}")
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ prog="score",
+ description="""
+ Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: FMP]
+ """,
+ )
- print("\nFinancial Modeling Prep API")
- print(" help show this financial modeling prep menu again")
- print(" q quit this menu, and shows back to main menu")
- print(" quit quit to abandon program")
- print("")
- print(" profile profile of the company")
- print(" quote quote of the company")
- print(" enterprise enterprise value of the company over time")
- print(" dcf discounted cash flow of the company over time")
- print(" income income statements of the company")
- print(" balance balance sheet of the company")
- print(" cash cash flow statement of the company")
- print(" metrics key metrics of the company")
- print(" ratios financial ratios of the company")
- print(" growth financial statement growth of the company")
- print("")
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+
+ valstock = valinvest.Fundamental(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ score = 100 * (valstock.fscore() / 9)
+ print(f"Score: {score:.2f}".rstrip("0").rstrip(".") + " %")
+ print("")
+
+ except Exception as e:
+ print(e, "\n")
+ return
-def menu(s_ticker, s_start, s_interval):
+def profile(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker profile
- # Add list of arguments that the fundamental analysis parser accepts
- fmp_parser = argparse.ArgumentParser(prog="fmp", add_help=False)
- choices = [
- "help",
- "q",
- "quit",
- "profile",
- "quote",
- "enterprise",
- "dcf",
- "fmp_income",
- "fmp_balance",
- "fmp_cash",
- "metrics",
- "ratios",
- "growth",
- ]
- fmp_parser.add_argument("cmd", choices=choices)
- completer = NestedCompleter.from_nested_dict({c: None for c in choices})
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
- print_menu(s_ticker, s_start, s_interval)
-
- # Loop forever and ever
- while True:
- # Get input command from user
- if session:
- as_input = session.prompt(
- f"{get_flair()} (fa)>(fmp)> ",
- completer=completer,
- )
- else:
- as_input = input(f"{get_flair()} (fa)>(av)> ")
-
- # Parse alpha vantage command of the list of possible commands
- try:
- (ns_known_args, l_args) = fmp_parser.parse_known_args(as_input.split())
-
- except SystemExit:
- print("The command selected doesn't exist\n")
- continue
-
- if ns_known_args.cmd == "help":
- print_menu(s_ticker, s_start, s_interval)
-
- elif ns_known_args.cmd == "q":
- # Just leave the menu
- return False
-
- elif ns_known_args.cmd == "quit":
- # Abandon the program
- return True
-
- # Details:
- elif ns_known_args.cmd == "profile":
- profile(l_args, s_ticker)
-
- elif ns_known_args.cmd == "quote":
- quote(l_args, s_ticker)
-
- elif ns_known_args.cmd == "enterprise":
- enterprise(l_args, s_ticker)
-
- elif ns_known_args.cmd == "dcf":
- discounted_cash_flow(l_args, s_ticker)
-
- # Financial statement:
- elif ns_known_args.cmd == "income":
- income_statement(l_args, s_ticker)
-
- elif ns_known_args.cmd == "balance":
- balance_sheet(l_args, s_ticker)
-
- elif ns_known_args.cmd == "cash":
- cash_flow(l_args, s_ticker)
-
- # Ratios:
- elif ns_known_args.cmd == "metrics":
- key_metrics(l_args, s_ticker)
-
- elif ns_known_args.cmd == "ratios":
- financial_ratios(l_args, s_ticker)
-
- elif ns_known_args.cmd == "growth":
- financial_statement_growth(l_args, s_ticker)
-
- else:
- print("Command not recognized!")
-
-
-def profile(l_args, s_ticker):
parser = argparse.ArgumentParser(
add_help=False,
prog="profile",
@@ -148,11 +75,11 @@ def profile(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- df_fa = fa.profile(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.profile(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
clean_df_index(df_fa)
print(df_fa.drop(index=["Description", "Image"]).to_string(header=False))
@@ -166,7 +93,17 @@ def profile(l_args, s_ticker):
return
-def quote(l_args, s_ticker):
+def quote(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker quote
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="quote",
@@ -181,11 +118,11 @@ def quote(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- df_fa = fa.quote(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.quote(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
clean_df_index(df_fa)
@@ -211,7 +148,17 @@ def quote(l_args, s_ticker):
return
-def enterprise(l_args, s_ticker):
+def enterprise(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker enterprise
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="enterprise",
@@ -242,7 +189,7 @@ def enterprise(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -253,10 +200,10 @@ def enterprise(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.enterprise(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.enterprise(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.enterprise(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False)
@@ -269,7 +216,17 @@ def enterprise(l_args, s_ticker):
return
-def discounted_cash_flow(l_args, s_ticker):
+def discounted_cash_flow(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker discounted cash flow
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="dcf",
@@ -298,7 +255,7 @@ def discounted_cash_flow(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -309,10 +266,10 @@ def discounted_cash_flow(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.discounted_cash_flow(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.discounted_cash_flow(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.discounted_cash_flow(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False)
@@ -325,7 +282,17 @@ def discounted_cash_flow(l_args, s_ticker):
return
-def income_statement(l_args, s_ticker):
+def income_statement(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker income statement
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="inc",
@@ -361,7 +328,7 @@ def income_statement(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -372,10 +339,10 @@ def income_statement(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.income_statement(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.income_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.income_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -394,7 +361,17 @@ def income_statement(l_args, s_ticker):
return
-def balance_sheet(l_args, s_ticker):
+def balance_sheet(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker balance sheet
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="bal",
@@ -435,7 +412,7 @@ def balance_sheet(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -446,11 +423,11 @@ def balance_sheet(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.balance_sheet_statement(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.balance_sheet_statement(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP
)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -470,7 +447,17 @@ def balance_sheet(l_args, s_ticker):
return
-def cash_flow(l_args, s_ticker):
+def cash_flow(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker cash flow
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="cash",
@@ -509,7 +496,7 @@ def cash_flow(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -520,10 +507,10 @@ def cash_flow(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.cash_flow_statement(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.cash_flow_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.cash_flow_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -542,7 +529,17 @@ def cash_flow(l_args, s_ticker):
return
-def key_metrics(l_args, s_ticker):
+def key_metrics(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker key metrics
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="metrics",
@@ -560,7 +557,7 @@ def key_metrics(l_args, s_ticker):
Inventory turnover, Market cap, Net current asset value, Net debt to EBITDA, Net income
per share, Operating cash flow per share, Payables turnover, Payout ratio, Pb ratio, Pe
ratio, Pfcf ratio, Pocfratio, Price to sales ratio, Ptb ratio, Receivables turnover,
- Research and ddevelopement to revenue, Return on tangible assets, Revenue per share,
+ Research and development to revenue, Return on tangible assets, Revenue per share,
Roe, Roic, Sales general and administrative to revenue, Shareholders equity per
share, Stock based compensation to revenue, Tangible book value per share, and Working
capital. [Source: Financial Modeling Prep]
@@ -586,7 +583,7 @@ def key_metrics(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -597,10 +594,10 @@ def key_metrics(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.key_metrics(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.key_metrics(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.key_metrics(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -613,7 +610,17 @@ def key_metrics(l_args, s_ticker):
return
-def financial_ratios(l_args, s_ticker):
+def financial_ratios(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker ratios
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="ratios",
@@ -658,7 +665,7 @@ def financial_ratios(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -669,10 +676,10 @@ def financial_ratios(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.financial_ratios(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
- df_fa = fa.financial_ratios(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
+ df_fa = fa.financial_ratios(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -685,7 +692,17 @@ def financial_ratios(l_args, s_ticker):
return
-def financial_statement_growth(l_args, s_ticker):
+def financial_statement_growth(other_args: List[str], ticker: str):
+ """Financial Modeling Prep ticker growth
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="growth",
@@ -726,7 +743,7 @@ def financial_statement_growth(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -737,11 +754,11 @@ def financial_statement_growth(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.financial_statement_growth(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.financial_statement_growth(
- s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP
+ ticker, cfg.API_KEY_FINANCIALMODELINGPREP
)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -756,6 +773,23 @@ def financial_statement_growth(l_args, s_ticker):
def clean_metrics_df(df_fa: pd.DataFrame, num: int, mask: bool = True) -> pd.DataFrame:
+ """Clean metrics data frame
+
+ Parameters
+ ----------
+ df_fa : pd.DataFrame
+ Metrics data frame
+ num : int
+ Number of columns to clean
+ mask : bool, optional
+ Apply mask, by default True
+
+ Returns
+ -------
+ pd.DataFrame
+ Cleaned metrics data frame
+ """
+
df_fa = df_fa.iloc[:, 0:num]
if mask:
df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["None"])).dropna()
diff --git a/gamestonk_terminal/fundamental_analysis/finviz_api.py b/gamestonk_terminal/fundamental_analysis/finviz_view.py
similarity index 78%
rename from gamestonk_terminal/fundamental_analysis/finviz_api.py
rename to gamestonk_terminal/fundamental_analysis/finviz_view.py
index 3bdc999ff62..59fa1679498 100644
--- a/gamestonk_terminal/fundamental_analysis/finviz_api.py
+++ b/gamestonk_terminal/fundamental_analysis/finviz_view.py
@@ -1,10 +1,25 @@
+""" FinViz View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
import finviz
import pandas as pd
+
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
-def screener(l_args, s_ticker):
+def screener(other_args: List[str], ticker: str):
+ """FinViz ticker screener
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="screener",
@@ -24,11 +39,11 @@ def screener(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- d_finviz_stock = finviz.get_stock(s_ticker)
+ d_finviz_stock = finviz.get_stock(ticker)
df_fa = pd.DataFrame.from_dict(
d_finviz_stock, orient="index", columns=["Values"]
)
diff --git a/gamestonk_terminal/fundamental_analysis/market_watch_model.py b/gamestonk_terminal/fundamental_analysis/market_watch_model.py
new file mode 100644
index 00000000000..fc1715949da
--- /dev/null
+++ b/gamestonk_terminal/fundamental_analysis/market_watch_model.py
@@ -0,0 +1,111 @@
+""" Fundamental Analysis Market Watch Model """
+__docformat__ = "numpy"
+
+import requests
+import pandas as pd
+from bs4 import BeautifulSoup
+
+from gamestonk_terminal.helper_funcs import (
+ get_user_agent,
+)
+
+
+def prepare_df_financials(
+ ticker: str, statement: str, quarter: bool = False
+) -> pd.DataFrame:
+ """Builds a DataFrame with financial statements for a given company
+
+ Parameters
+ ----------
+ ticker : str
+ Company's stock ticker
+ statement : str
+ Either income, balance or cashflow
+ quarter : bool, optional
+ Return quarterly financial statements instead of annual, by default False
+
+ Returns
+ -------
+ pd.DataFrame
+ A DataFrame with financial info
+
+ Raises
+ ------
+ ValueError
+ If statement is not income, balance or cashflow
+ """
+ financial_urls = {
+ "income": {
+ "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/income/quarter",
+ "annual": "https://www.marketwatch.com/investing/stock/{}/financials/income",
+ },
+ "balance": {
+ "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet/quarter",
+ "annual": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet",
+ },
+ "cashflow": {
+ "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow/quarter",
+ "annual": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow",
+ },
+ }
+
+ if statement not in financial_urls.keys():
+ raise ValueError(f"type {statement} is not in {financial_urls.keys()}")
+
+ if quarter:
+ period = "quarter"
+ else:
+ period = "annual"
+
+ text_soup_financials = BeautifulSoup(
+ requests.get(
+ financial_urls[statement][period].format(ticker),
+ headers={"User-Agent": get_user_agent()},
+ ).text,
+ "lxml",
+ )
+
+ # Define financials columns
+ a_financials_header = list()
+ for financials_header in text_soup_financials.findAll(
+ "th", {"class": "overflow__heading"}
+ ):
+ a_financials_header.append(financials_header.text.strip("\n").split("\n")[0])
+
+ s_header_end_trend = ("5-year trend", "5- qtr trend")[quarter]
+ df_financials = pd.DataFrame(
+ columns=a_financials_header[0 : a_financials_header.index(s_header_end_trend)]
+ )
+
+ find_table = text_soup_financials.findAll(
+ "div", {"class": "element element--table table--fixed financials"}
+ )
+
+ if not find_table:
+ return df_financials
+
+ financials_rows = find_table[0].findAll(
+ "tr", {"class": ["table__row is-highlighted", "table__row"]}
+ )
+
+ for a_row in financials_rows:
+ constructed_row = list()
+ financial_columns = a_row.findAll(
+ "td", {"class": ["overflow__cell", "overflow__cell fixed--column"]}
+ )
+
+ if not financial_columns:
+ continue
+
+ for a_column in financial_columns:
+ column_to_text = a_column.text.strip()
+ if "\n" in column_to_text:
+ column_to_text = column_to_text.split("\n")[0]
+
+ if column_to_text == "":
+ continue
+ constructed_row.append(column_to_text)
+
+ df_financials.loc[len(df_financials)] = constructed_row
+
+ return df_financials
diff --git a/gamestonk_terminal/fundamental_analysis/market_watch_api.py b/gamestonk_terminal/fundamental_analysis/market_watch_view.py
similarity index 70%
rename from gamestonk_terminal/fundamental_analysis/market_watch_api.py
rename to gamestonk_terminal/fundamental_analysis/market_watch_view.py
index db94fcf0fbe..795f88e7b7c 100644
--- a/gamestonk_terminal/fundamental_analysis/market_watch_api.py
+++ b/gamestonk_terminal/fundamental_analysis/market_watch_view.py
@@ -1,12 +1,12 @@
-""" Fundamental Analysis Market Watch API """
+""" Fundamental Analysis Market Watch View """
__docformat__ = "numpy"
import argparse
-import requests
+from typing import List
import pandas as pd
-from bs4 import BeautifulSoup
+
+from gamestonk_terminal.fundamental_analysis import market_watch_model as mwm
from gamestonk_terminal.helper_funcs import (
- get_user_agent,
parse_known_args_and_warn,
patch_pandas_text_adjustment,
financials_colored_values,
@@ -14,7 +14,17 @@ from gamestonk_terminal.helper_funcs import (
from gamestonk_terminal import feature_flags as gtff
-def income(l_args, s_ticker):
+def income(other_args: List[str], ticker: str):
+ """Market Watch ticker income statement
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="income",
@@ -50,11 +60,11 @@ def income(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- df_financials = prepare_df_financials(s_ticker, "income", ns_parser.b_quarter)
+ df_financials = mwm.prepare_df_financials(ticker, "income", ns_parser.b_quarter)
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -72,7 +82,17 @@ def income(l_args, s_ticker):
return
-def balance(l_args, s_ticker):
+def balance(other_args: List[str], ticker: str):
+ """Market Watch ticker balance statement
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="balance",
@@ -120,11 +140,13 @@ def balance(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- df_financials = prepare_df_financials(s_ticker, "balance", ns_parser.b_quarter)
+ df_financials = mwm.prepare_df_financials(
+ ticker, "balance", ns_parser.b_quarter
+ )
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -142,7 +164,17 @@ def balance(l_args, s_ticker):
return
-def cash(l_args, s_ticker):
+def cash(other_args: List[str], ticker: str):
+ """Market Watch ticker cash flow statement
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="cash_flow",
@@ -186,11 +218,13 @@ def cash(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- df_financials = prepare_df_financials(s_ticker, "cashflow", ns_parser.b_quarter)
+ df_financials = mwm.prepare_df_financials(
+ ticker, "cashflow", ns_parser.b_quarter
+ )
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -206,104 +240,3 @@ def cash(l_args, s_ticker):
print(e)
print("")
return
-
-
-def prepare_df_financials(
- ticker: str, statement: str, quarter: bool = False
-) -> pd.DataFrame:
- """Builds a DataFrame with financial statements for a given company
-
- Parameters
- ----------
- ticker : str
- Company's stock ticker
- statement : str
- Either income, balance or cashflow
- quarter : bool, optional
- Return quarterly financial statements instead of annual, by default False
-
- Returns
- -------
- pd.DataFrame
- A DataFrame with financial info
-
- Raises
- ------
- ValueError
- If statement is not income, balance or cashflow
- """
- financial_urls = {
- "income": {
- "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/income/quarter",
- "annual": "https://www.marketwatch.com/investing/stock/{}/financials/income",
- },
- "balance": {
- "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet/quarter",
- "annual": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet",
- },
- "cashflow": {
- "quarter": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow/quarter",
- "annual": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow",
- },
- }
-
- if statement not in financial_urls.keys():
- raise ValueError(f"type {statement} is not in {financial_urls.keys()}")
-
- if quarter:
- period = "quarter"
- else:
- period = "annual"
-
- text_soup_financials = BeautifulSoup(
- requests.get(
- financial_urls[statement][period].format(ticker),
- headers={"User-Agent": get_user_agent()},
- ).text,
- "lxml",
- )
-
- # Define financials columns
- a_financials_header = list()
- for financials_header in text_soup_financials.findAll(
- "th", {"class": "overflow__heading"}
- ):
- a_financials_header.append(financials_header.text.strip("\n").split("\n")[0])
-
- s_header_end_trend = ("5-year trend", "5- qtr trend")[quarter]
- df_financials = pd.DataFrame(
- columns=a_financials_header[0 : a_financials_header.index(s_header_end_trend)]
- )
-
- find_table = text_soup_financials.findAll(
- "div", {"class": "element element--table table--fixed financials"}
- )
-
- if not find_table:
- return df_financials
-
- financials_rows = find_table[0].findAll(
- "tr", {"class": ["table__row is-highlighted", "table__row"]}
- )
-
- for a_row in financials_rows:
- constructed_row = list()
- financial_columns = a_row.findAll(
- "td", {"class": ["overflow__cell", "overflow__cell fixed--column"]}
- )
-
- if not financial_columns:
- continue
-
- for a_column in financial_columns:
- column_to_text = a_column.text.strip()
- if "\n" in column_to_text:
- column_to_text = column_to_text.split("\n")[0]
-
- if column_to_text == "":
- continue
- constructed_row.append(column_to_text)
-
- df_financials.loc[len(df_financials)] = constructed_row
-
- return df_financials
diff --git a/gamestonk_terminal/fundamental_analysis/yahoo_finance_api.py b/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py
similarity index 85%
rename from gamestonk_terminal/fundamental_analysis/yahoo_finance_api.py
rename to gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py
index f7eef62eb8a..d2192875f17 100644
--- a/gamestonk_terminal/fundamental_analysis/yahoo_finance_api.py
+++ b/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py
@@ -1,7 +1,12 @@
+""" Yahoo Finance View """
+__docformat__ = "numpy"
+
import argparse
+from typing import List
from datetime import datetime
import yfinance as yf
import pandas as pd
+
from gamestonk_terminal.dataframe_helpers import clean_df_index
from gamestonk_terminal.helper_funcs import (
long_number_format,
@@ -9,7 +14,17 @@ from gamestonk_terminal.helper_funcs import (
)
-def info(l_args, s_ticker):
+def info(other_args: List[str], ticker: str):
+ """Yahoo Finance ticker info
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="info",
@@ -36,11 +51,11 @@ def info(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- stock = yf.Ticker(s_ticker)
+ stock = yf.Ticker(ticker)
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
df_info = df_info.set_index("Metric")
@@ -86,7 +101,17 @@ def info(l_args, s_ticker):
return
-def shareholders(l_args, s_ticker):
+def shareholders(other_args: List[str], ticker: str):
+ """Yahoo Finance ticker shareholders
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="shrs",
@@ -95,11 +120,11 @@ def shareholders(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- stock = yf.Ticker(s_ticker)
+ stock = yf.Ticker(ticker)
pd.set_option("display.max_colwidth", None)
# Major holders
@@ -154,7 +179,17 @@ def shareholders(l_args, s_ticker):
return
-def sustainability(l_args, s_ticker):
+def sustainability(other_args: List[str], ticker: str):
+ """Yahoo Finance ticker sustainability
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="sust",
@@ -169,17 +204,17 @@ def sustainability(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- stock = yf.Ticker(s_ticker)
+ stock = yf.Ticker(ticker)
pd.set_option("display.max_colwidth", None)
df_sustainability = stock.sustainability
if not df_sustainability:
- print(f"No sustainability information in Yahoo for {s_ticker}")
+ print(f"No sustainability information in Yahoo for {ticker}")
print("")
return
@@ -209,7 +244,17 @@ def sustainability(l_args, s_ticker):
return
-def calendar_earnings(l_args, s_ticker):
+def calendar_earnings(other_args: List[str], ticker: str):
+ """Yahoo Finance ticker calendar earnings
+
+ Parameters
+ ----------
+ other_args : List[str]
+ argparse other args
+ ticker : str
+ Fundamental analysis ticker symbol
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="cal",
@@ -220,15 +265,15 @@ def calendar_earnings(l_args, s_ticker):
)
try:
- ns_parser = parse_known_args_and_warn(parser, l_args)
+ ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
- stock = yf.Ticker(s_ticker)
+ stock = yf.Ticker(ticker)
df_calendar = stock.calendar
if df_calendar.empty:
- print(f"No earnings calendar information in Yahoo for {s_ticker}")
+ print(f"No earnings calendar information in Yahoo for {ticker}")
print("")
return
diff --git a/gamestonk_terminal/options/README.md b/gamestonk_terminal/options/README.md
index 980be7495c4..7413f9a88aa 100644
--- a/gamestonk_terminal/options/README.md
+++ b/gamestonk_terminal/options/README.md
@@ -1,50 +1,109 @@
-# OPTIONS DATA
+# OPTIONS
-This menu aims to give insight on options. options can cause significant share price movement, and option pricing gives
-info about market sentiment for a ticker.
+This menu aims to give insight on options.
-* [volume](#volume)
- * Show traded options for a given expiry [Yahoo Finance]
+This menu aims to give insight on options. Options can cause significant share price movement, and option pricing gives info about market sentiment for a ticker. The usage of the following commands along with an example will be exploited below:
+* [exp](#exp)
+ * See/set expiry date [Yahoo Finance]
+* [voi](#voi)
+ * Volume + open interest options trading plot [Yahoo Finance]
+* [vcalls](#vcalls)
+ * Calls volume + open interest plot [Yahoo Finance]
+* [vputs](#vputs)
+ * Puts volume + open interest plot [Yahoo Finance]
* [chains](#chains)
- * Display option chains for
+ * Display option chains [Source: Tradier]
+* [info](#info)
+ * _**This requires selenium webdriver installed**_
+ * Display option information [Source: Barchart.com]
-## volume
+
+## exp
```text
-usage: volume -e yyyy-mm-dd
+usage: exp [-d {0,1,2,3,4,5,6,7,8,9,10,11}]
```
-or
+See/set expiry dates. [Source: Yahoo Finance]
+
+* -d : Expiry date index to set.
+
+
+
+
+## voi
```text
-usage: volume --expiry yyyy-mm-dd
+usage: voi [-v MIN_VOL] [-m MIN_SP] [-M MAX_SP]
```
+Plots Volume + Open Interest of calls vs puts. [Source: Yahoo Finance]
-Display volume graph for a date. [Source: Yahoo Finance]
+* -v : Minimum volume (considering open interest) threshold of the plot.
+* -m : Minimum strike price to consider in the plot.
+* -M : Maximum strike price to consider in the plot.
+
+
+
+
+## vcalls
+
+```text
+usage: vcalls [-m MIN_SP] [-M MAX_SP]
+```
+
+Plots Calls Volume + Open Interest. [Source: Yahoo Finance]
+
+* -m : Minimum strike price to consider in the plot.
+* -M : Maximum strike price to consider in the plot.
+
+
+
+
+## vputs
+
+```text
+usage: vputs [-m MIN_SP] [-M MAX_SP]
+```
+
+Plots Puts Volume + Open Interest. [Source: Yahoo Finance]
+
+* -m : Minimum strike price to consider in the plot.
+* -M : Maximum strike price to consider in the plot.
+
+
-* -e, --expiry : expiration date.
## chains
-Display a table of options chains.
-
-This data requires a Tradier sandbox developer account, which can be made [here](#https://tradier.com/products/market-data-api)
````
-usage: chains [--calls] [--puts] [-m MIN] [-M MAX]
+usage: chains [--calls] [--puts] [-m MIN_SP] [-M MAX_SP]
````
-* --calls : Flag to only display call options
-* --puts : Flag to display only put options
-* -m : Minimum strike price to show
-* -M : Maximum strike price to show
-For combines tables, call options are on the left and put options are on the right of the strike
+Display options chains. [Source: Tradier]
-As an example, if I load my ticker and select an expiry, to view the options chain for strikes between $129 and $135, one would use:
+* --calls : Flag to show calls only
+* --puts : Flag to show puts only
+* -m : Minimum strike price to consider.
+* -M : Maximum strike price to consider.
+* -d : Columns to display. Should be comma separated. Must be in * -d : Columns to display from the following selection: bid, ask, strike, bidsize, asksize, volume, open_interest, delta, gamma, theta, vega, ask_iv, bid_iv, mid_iv. Default: mid_iv,vega_theta_gamma,delta,volume,open_interest,bid,ask. Note that they are separated by comma.
+
+
+
+
+
+## info
+This scrapes the options information from barchart.com/stocks overview. This includes information such as Historical Volatility and IV Rank.
+
+In order to run, the selenium webdriver must be installed.
+Currently, this runs on either Chrome or Firefox. The path to the driver should be defined in [config_terminal.py](#config_terminal.py).
+
+Note this may take more time than other commands to process.
````
-chains -m 129 -M 135
+usage: info [-d DRIVER]
````
-Which outputs:
-
+* -d/--driver : One of {chrome, firefox}. This indicates which driver you have installed.
+
+
diff --git a/gamestonk_terminal/options/chains_view.py b/gamestonk_terminal/options/chains_view.py
index c05552a909e..b87b57460b6 100644
--- a/gamestonk_terminal/options/chains_view.py
+++ b/gamestonk_terminal/options/chains_view.py
@@ -27,6 +27,28 @@ greek_columns = ["delta", "gamma", "theta", "vega", "ask_iv", "bid_iv", "mid_iv"
df_columns = option_columns + greek_columns
column_map = {"mid_iv": "iv", "open_interest": "oi", "volume": "vol"}
+default_columns = [
+ "mid_iv",
+ "vega",
+ "delta",
+ "gamma",
+ "theta",
+ "volume",
+ "open_interest",
+ "bid",
+ "ask",
+]
+
+
+def check_valid_option_chains_headers(headers: str) -> List[str]:
+ columns = [str(item) for item in headers.split(",")]
+
+ for header in columns:
+ if header not in df_columns:
+ raise argparse.ArgumentTypeError("Invalid option chains header selected!")
+
+ return columns
+
def process_chains(response: requests.models.Response) -> pd.DataFrame:
"""
@@ -88,7 +110,9 @@ def get_option_chains(symbol: str, expiry: str) -> pd.DataFrame:
def display_chains(symbol: str, expiry: str, other_args: List[str]):
parser = argparse.ArgumentParser(
- prog="chains", add_help=False, description="Display options chains"
+ prog="chains",
+ add_help=False,
+ description="Display option chains [Source: Tradier]",
)
parser.add_argument(
@@ -122,25 +146,24 @@ def display_chains(symbol: str, expiry: str, other_args: List[str]):
default=-1,
help="maximum strike price to consider.",
)
+ parser.add_argument(
+ "-d",
+ "--display",
+ dest="to_display",
+ default=default_columns,
+ type=check_valid_option_chains_headers,
+ help="columns to look at. Columns can be: {bid, ask, strike, bidsize, asksize, volume, open_interest, delta, "
+ "gamma, theta, vega, ask_iv, bid_iv, mid_iv} ",
+ )
chains_df = get_option_chains(symbol, expiry)
- default_columns = [
- "mid_iv",
- "delta",
- "volume",
- "open_interest",
- "bid",
- "ask",
- "strike",
- "option_type",
- ]
- chains_df = chains_df[default_columns].rename(columns=column_map)
-
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
+ columns = ns_parser.to_display + ["strike", "option_type"]
+ chains_df = chains_df[columns].rename(columns=column_map)
if ns_parser.max_sp == -1 and ns_parser.min_sp == -1:
min_strike = np.percentile(chains_df["strike"], 25)
max_strike = np.percentile(chains_df["strike"], 75)
@@ -201,6 +224,7 @@ def display_chains(symbol: str, expiry: str, other_args: List[str]):
floatfmt=".2f",
)
)
+ print("")
except Exception as e:
print(e)
diff --git a/gamestonk_terminal/options/op_controller.py b/gamestonk_terminal/options/op_controller.py
index 4caa51dbd63..5ba3ad04dc8 100644
--- a/gamestonk_terminal/options/op_controller.py
+++ b/gamestonk_terminal/options/op_controller.py
@@ -9,7 +9,7 @@ import yfinance as yf
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
from gamestonk_terminal import feature_flags as gtff
-from gamestonk_terminal.options import volume_view, chains_view
+from gamestonk_terminal.options import volume_view, chains_view, op_scrape_view
from gamestonk_terminal.menu import session
@@ -17,7 +17,7 @@ class OptionsController:
"""Options Controller class."""
# Command choices
- CHOICES = ["help", "q", "quit", "exp", "voi", "vcalls", "vputs", "chains"]
+ CHOICES = ["help", "q", "quit", "exp", "voi", "vcalls", "vputs", "chains", "info"]
def __init__(self, ticker: str, last_adj_close_price: float):
"""Construct data."""
@@ -38,7 +38,7 @@ class OptionsController:
parser = argparse.ArgumentParser(
add_help=False,
prog="exp",
- description="""See expiry dates.""",
+ description="""See/set expiry dates. [Source: Yahoo Finance]""",
)
parser.add_argument(
"-d",
@@ -94,6 +94,7 @@ class OptionsController:
print(" vputs puts volume + open interest plot")
print("")
print(" chains display option chains")
+ print(" info display option information (volatility, IV rank etc)")
print("")
return
@@ -163,6 +164,9 @@ class OptionsController:
def call_chains(self, other_args):
chains_view.display_chains(self.ticker, self.expiry_date, other_args)
+ def call_info(self, other_args):
+ op_scrape_view.print_options_data(self.ticker, other_args)
+
def menu(ticker: str, last_adj_close_price: float):
""" Options Menu. """
diff --git a/gamestonk_terminal/options/op_scrape_view.py b/gamestonk_terminal/options/op_scrape_view.py
new file mode 100644
index 00000000000..dbf5459181f
--- /dev/null
+++ b/gamestonk_terminal/options/op_scrape_view.py
@@ -0,0 +1,104 @@
+"""Helper functions for scraping options data"""
+__docformat__ = "numpy"
+
+import argparse
+from typing import List
+from selenium import webdriver
+from bs4 import BeautifulSoup
+
+# from selenium.webdriver.chrome.options import Options as cOpts
+# from selenium.webdriver.firefox.options import Options as fOpts
+import pandas as pd
+from tabulate import tabulate
+from gamestonk_terminal.config_terminal import (
+ PATH_TO_SELENIUM_DRIVER as path_to_driver,
+ WEBDRIVER_TO_USE as web,
+)
+from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
+
+browsers = ["chrome", "firefox"]
+
+
+def print_options_data(stock: str, other_args: List[str]):
+ """
+ Scrapes Barchart.com for the options information
+ Parameters
+ ----------
+ stock: str
+ Ticker to get options info for
+ other_args: List[str]
+ Other arguments. Currently just accepts a browser flag for selenium
+
+ """
+
+ if path_to_driver is None:
+ print("Please specify your selenium driver path in config_terminal.py")
+ print("")
+ return
+
+ parser = argparse.ArgumentParser(
+ prog="info",
+ add_help=False,
+ description="Display option data [Source: Barchart.com]",
+ )
+
+ parser.add_argument(
+ "-b",
+ "--browser",
+ dest="browser",
+ help="selenium webdriver to use",
+ choices=browsers,
+ default=web,
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+
+ if ns_parser.browser:
+ browser = ns_parser.browser
+
+ except Exception as e:
+ print(e)
+ print("")
+ return
+
+ try:
+ if browser == "chrome":
+ # commenting this because it breaks when in usage
+ # the downside is that the browser will pop up to get the data
+ # options = cOpts()
+ # options.headless = True
+ driver = webdriver.Chrome(executable_path=path_to_driver)
+
+ elif browser == "firefox":
+ # commenting this because it breaks when in usage
+ # the downside is that the browser will pop up to get the data
+ # options = fOpts()
+ # options.headless = True
+ driver = webdriver.Firefox(executable_path=path_to_driver)
+
+ page = f"https://www.barchart.com/stocks/quotes/{stock}/overview"
+ driver.get(page)
+
+ soup = BeautifulSoup(driver.page_source, "html.parser")
+ tags = soup.find(
+ "div",
+ attrs={
+ "class": "barchart-content-block symbol-fundamentals bc-cot-table-wrapper"
+ },
+ )
+ data = tags.find_all("li")
+ labels = []
+ values = []
+ print("")
+ for row in data:
+ labels.append(row.find_all("span")[0].getText())
+ values.append(row.find_all("span")[1].getText())
+
+ df = pd.DataFrame(data=[labels, values]).T
+ print(tabulate(df, tablefmt="fancy_grid", showindex=False))
+ print("")
+
+ except Exception as e:
+ print(e)
+ print("")
diff --git a/gamestonk_terminal/options/volume_view.py b/gamestonk_terminal/options/volume_view.py
index a4f3062a960..4d32126c682 100644
--- a/gamestonk_terminal/options/volume_view.py
+++ b/gamestonk_terminal/options/volume_view.py
@@ -351,8 +351,9 @@ def plot_calls_volume_open_interest(
df_calls["strike"],
df_calls["volume"] + df_calls["openInterest"],
color="lightgreen",
+ width=0.45,
)
- plt.bar(df_calls["strike"], df_calls["volume"], color="green")
+ plt.bar(df_calls["strike"], df_calls["volume"], color="green", width=0.45)
plt.title(f"{ticker} calls volumes for {exp_date} ")
plt.legend(["Stock Price", "Open Interest", "Volume"])
@@ -443,8 +444,9 @@ def plot_puts_volume_open_interest(
df_puts["strike"],
-df_puts["volume"] - df_puts["openInterest"],
color="pink",
+ width=0.45,
)
- plt.bar(df_puts["strike"], -df_puts["volume"], color="red")
+ plt.bar(df_puts["strike"], -df_puts["volume"], color="red", width=0.45)
plt.title(f"{ticker} puts volumes for {exp_date} ")
plt.legend(["Stock Price", "Open Interest", "Volume"])
diff --git a/gamestonk_terminal/portfolio/port_controller.py b/gamestonk_terminal/portfolio/port_controller.py
index d6d5265789e..e9d6b0c1fea 100644
--- a/gamestonk_terminal/portfolio/port_controller.py
+++ b/gamestonk_terminal/portfolio/port_controller.py
@@ -4,6 +4,7 @@ import argparse
from typing import List
import pandas as pd
from prompt_toolkit.completion import NestedCompleter
+
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
@@ -15,6 +16,7 @@ from gamestonk_terminal.portfolio.portfolio_helpers import (
class PortfolioController:
+ """ Portfolio Controller """
CHOICES = [
"help",
@@ -129,6 +131,7 @@ class PortfolioController:
if broker in self.BROKERS:
api = broker + "_api"
try:
+ # pylint: disable=eval-used
eval(api + ".login()")
self.broker_list.add(broker)
logged_in = True
@@ -179,7 +182,9 @@ class PortfolioController:
print("Login to desired brokers\n")
for broker in self.broker_list:
holdings = pd.concat(
- [holdings, eval(broker + "_api.return_holdings()")], axis=0
+ # pylint: disable=eval-used
+ [holdings, eval(broker + "_api.return_holdings()")],
+ axis=0,
)
self.merged_holdings = merge_portfolios(holdings)
print_portfolio(self.merged_holdings)
diff --git a/gamestonk_terminal/portfolio_optimization/optimizer_helper.py b/gamestonk_terminal/portfolio_optimization/optimizer_helper.py
index f88ad80463c..8236d01b789 100644
--- a/gamestonk_terminal/portfolio_optimization/optimizer_helper.py
+++ b/gamestonk_terminal/portfolio_optimization/optimizer_helper.py
@@ -1,4 +1,4 @@
-""" Portfolio Optimization Helper Functions"""
+""" Portfolio Optimization Helper Functions """
__docformat__ = "numpy"
import argparse
@@ -110,12 +110,12 @@ l_valid_property_infos = [
]
-def check_valid_property_type(property: str) -> str:
+def check_valid_property_type(aproperty: str) -> str:
""" Check that the property selected is valid """
- if property in l_valid_property_infos:
- return property
- else:
- raise argparse.ArgumentTypeError(f"{property} is not a valid info")
+ if aproperty in l_valid_property_infos:
+ return aproperty
+
+ raise argparse.ArgumentTypeError(f"{aproperty} is not a valid info")
def process_stocks(list_of_stocks: List[str], period: str = "3mo") -> pd.DataFrame:
@@ -133,6 +133,7 @@ def process_stocks(list_of_stocks: List[str], period: str = "3mo") -> pd.DataFra
stock_closes: DataFrame
DataFrame containing daily (adjusted) close prices for each stock in list
"""
+
stock_prices = yf.download(
list_of_stocks, period=period, progress=False, group_by="ticker"
)
@@ -155,6 +156,7 @@ def prepare_efficient_frontier(stock_prices: pd.DataFrame):
ef: EfficientFrontier
EfficientFrontier object
"""
+
mu = expected_returns.mean_historical_return(stock_prices)
S = risk_models.sample_cov(stock_prices)
ef = EfficientFrontier(mu, S)
@@ -162,13 +164,14 @@ def prepare_efficient_frontier(stock_prices: pd.DataFrame):
def display_weights(weights: dict):
- """
- Print weights in a nice format
+ """Print weights in a nice format
+
Parameters
----------
weights: dict
weights to display. Keys are stocks. Values are either weights or values if -v specified
"""
+
if not weights:
return
weight_df = pd.DataFrame.from_dict(data=weights, orient="index", columns=["value"])
@@ -185,8 +188,8 @@ def my_autopct(x):
"""Function for autopct of plt.pie. This results in values not being printed in the pie if they are 'too small'"""
if x > 4:
return f"{x:.2f} %"
- else:
- return ""
+
+ return ""
def pie_chart_weights(weights: dict, title_opt: str):
diff --git a/gamestonk_terminal/portfolio_optimization/optimizer_view.py b/gamestonk_terminal/portfolio_optimization/optimizer_view.py
index 6c61666d5bf..884bea7c578 100644
--- a/gamestonk_terminal/portfolio_optimization/optimizer_view.py
+++ b/gamestonk_terminal/portfolio_optimization/optimizer_view.py
@@ -122,12 +122,8 @@ def property_weighting(stocks: List[str], other_args: List[str]):
List of tickers to be included in optimization
other_args : List[str]
Command line arguments to be processed with argparse
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="property",
@@ -136,7 +132,7 @@ def property_weighting(stocks: List[str], other_args: List[str]):
parser.add_argument(
"-p",
"--property",
- required=True if "-h" not in other_args else False,
+ required=bool("-h" not in other_args),
type=check_valid_property_type,
dest="property",
help="""Property info to weigh. Use one of:
@@ -217,19 +213,16 @@ def property_weighting(stocks: List[str], other_args: List[str]):
def max_sharpe(stocks: List[str], other_args: List[str]):
- """
- Return a portfolio that maximises the Sharpe Ratio
+ """Return a portfolio that maximises the Sharpe Ratio
Parameters
----------
- stocks: List[str]
+ stocks : List[str]
List of the stocks to be included in the weights
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers.
+ other_args : List[str]
+ argparse other args
"""
+
parser = argparse.ArgumentParser(
add_help=False, prog="maxsharpe", description="Maximise the Sharpe Ratio"
)
@@ -273,7 +266,7 @@ def max_sharpe(stocks: List[str], other_args: List[str]):
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return None
+ return
if len(stocks) < 2:
print("Please have at least 2 loaded tickers to calculate weights.\n")
@@ -309,19 +302,16 @@ def max_sharpe(stocks: List[str], other_args: List[str]):
def min_volatility(stocks: List[str], other_args: List[str]):
- """
- Return a portfolio that optimizes for minimum volatility
+ """Return a portfolio that optimizes for minimum volatility
Parameters
----------
- stocks: List[str]
+ stocks : List[str]
List of the stocks to be included in the weights
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers.
+ other_args : List[str]
+ argparse other args
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="min_volatility",
@@ -354,7 +344,7 @@ def min_volatility(stocks: List[str], other_args: List[str]):
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return None
+ return
if len(stocks) < 2:
print("Please have at least 2 loaded tickers to calculate weights.\n")
@@ -390,19 +380,16 @@ def min_volatility(stocks: List[str], other_args: List[str]):
def max_quadratic_utility(stocks: List[str], other_args: List[str]):
- """
- Return a portfolio that maximises the quadratic utility, given some risk aversion
+ """Return a portfolio that maximises the quadratic utility, given some risk aversion
Parameters
----------
- stocks: List[str]
+ stocks : List[str]
List of the stocks to be included in the weights
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers.
+ other_args : List[str]
+ argparse other args
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="max_quadratic_utility",
@@ -458,7 +445,7 @@ def max_quadratic_utility(stocks: List[str], other_args: List[str]):
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return None
+ return
if len(stocks) < 2:
print("Please have at least 2 loaded tickers to calculate weights.\n")
@@ -499,20 +486,15 @@ def max_quadratic_utility(stocks: List[str], other_args: List[str]):
def efficient_risk(stocks: List[str], other_args: List[str]):
- """
- Return a portfolio that maximises return for a target risk. The resulting portfolio will have
- a volatility less than the target (but not guaranteed to be equal)
+ """Return a portfolio that maximises return for a target risk. The resulting portfolio will have
+ a volatility less than the target (but not guaranteed to be equal)
- Parameters
- ----------
- stocks: List[str]
+ stocks : List[str]
List of the stocks to be included in the weights
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers.
+ other_args : List[str]
+ argparse other args
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="effrisk",
@@ -568,7 +550,7 @@ def efficient_risk(stocks: List[str], other_args: List[str]):
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return None
+ return
if len(stocks) < 2:
print("Please have at least 2 loaded tickers to calculate weights.\n")
@@ -609,19 +591,16 @@ def efficient_risk(stocks: List[str], other_args: List[str]):
def efficient_return(stocks: List[str], other_args: List[str]):
- """
- Return a portfolio that minimises volatility for a given target return ('Markowitz portfolio')
+ """Displays a portfolio that minimises volatility for a given target return ('Markowitz portfolio')
Parameters
----------
- stocks: List[str]
+ stocks : List[str]
List of the stocks to be included in the weights
-
- Returns
- -------
- weights: dict
- Dictionary of weights where keys are the tickers.
+ other_args : List[str]
+ argparse other args
"""
+
parser = argparse.ArgumentParser(
add_help=False,
prog="effret",
@@ -676,7 +655,7 @@ def efficient_return(stocks: List[str], other_args: List[str]):
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
- return None
+ return
if len(stocks) < 2:
print("Please have at least 2 loaded tickers to calculate weights.\n")
@@ -717,6 +696,16 @@ def efficient_return(stocks: List[str], other_args: List[str]):
def show_ef(stocks: List[str], other_args: List[str]):
+ """Display efficient frontier
+
+ Parameters
+ ----------
+ stocks : List[str]
+ List of the stocks to be included in the weights
+ other_args : List[str]
+ argparse other args
+ """
+
parser = argparse.ArgumentParser(
add_help=False,
prog="ef",
@@ -756,7 +745,7 @@ def show_ef(stocks: List[str], other_args: List[str]):
mu = expected_returns.mean_historical_return(stock_prices)
S = risk_models.sample_cov(stock_prices)
ef = EfficientFrontier(mu, S)
- fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
+ _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
# Generate random portfolios
n_samples = ns_parser.n_port
diff --git a/gamestonk_terminal/portfolio_optimization/po_controller.py b/gamestonk_terminal/portfolio_optimization/po_controller.py
index c66ca63e846..c4345e8b386 100644
--- a/gamestonk_terminal/portfolio_optimization/po_controller.py
+++ b/gamestonk_terminal/portfolio_optimization/po_controller.py
@@ -1,7 +1,6 @@
-"""Portfolio Optimization Controller Module"""
+""" Portfolio Optimization Controller Module """
__docformat__ = "numpy"
-
import argparse
from typing import List
import matplotlib.pyplot as plt
@@ -34,6 +33,7 @@ class PortfolioOptimization:
"yolo",
]
+ # pylint: disable=dangerous-default-value
def __init__(self, tickers: List[str] = []):
"""
Construct Portfolio Optimization
@@ -113,12 +113,12 @@ class PortfolioOptimization:
def call_add(self, other_args: List[str]):
"""Process add command"""
- self.add_stocks(self, other_args)
+ self.add_stocks(other_args)
def call_select(self, other_args: List[str]):
"""Process select command"""
self.tickers = []
- self.add_stocks(self, other_args)
+ self.add_stocks(other_args)
def call_equal(self, other_args: List[str]):
"""Process equal command"""
@@ -168,7 +168,6 @@ class PortfolioOptimization:
print({"GME": 200})
print("")
- @staticmethod
def add_stocks(self, other_args: List[str]):
""" Add ticker or Select tickes for portfolio to be optimized """
parser = argparse.ArgumentParser(
diff --git a/gamestonk_terminal/prediction_techniques/ets.py b/gamestonk_terminal/prediction_techniques/ets.py
index 96e17306d78..c26e6f28a5a 100644
--- a/gamestonk_terminal/prediction_techniques/ets.py
+++ b/gamestonk_terminal/prediction_techniques/ets.py
@@ -5,6 +5,7 @@ import numpy as np
import pandas as pd
from pandas.plotting import register_matplotlib_converters
from statsmodels.tsa.holtwinters import ExponentialSmoothing
+
from gamestonk_terminal.helper_funcs import (
check_positive,
parse_known_args_and_warn,
@@ -18,19 +19,18 @@ from gamestonk_terminal.prediction_techniques.pred_helper import (
price_prediction_backtesting_color,
print_prediction_kpis,
)
-
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal import feature_flags as gtff
register_matplotlib_converters()
-trend = "Ad" # Additive damped, A Additive, N None
-seasonal = "N" # None, A Additive, M Multiplicative
-seasonal_periods = 5
+# trend = "Ad" # Additive damped, A Additive, N None
+# seasonal = "N" # None, A Additive, M Multiplicative
+# seasonal_periods = 5
def check_valid_trend(trend: str) -> str:
- if trend == "N" or trend == "A" or trend == "Ad":
+ if trend in ("N", "A", "Ad"):
return trend
raise argparse.ArgumentTypeError(
"Invalid trend selected. Choose between 'N', 'A', and 'Ad'"
@@ -38,7 +38,7 @@ def check_valid_trend(trend: str) -> str:
def check_valid_seasonal(seasonal: str) -> str:
- if seasonal == "N" or seasonal == "A" or seasonal == "M":
+ if seasonal in ("N", "A", "M"):
return seasonal
raise argparse.ArgumentTypeError(
"Invalid seasonal selected. Choose between 'N', 'A', and 'M'"
diff --git a/gamestonk_terminal/prediction_techniques/neural_networks.py b/gamestonk_terminal/prediction_techniques/neural_networks.py
index 2e7d63e5db6..d0489619576 100644
--- a/gamestonk_terminal/prediction_techniques/neural_networks.py
+++ b/gamestonk_terminal/prediction_techniques/neural_networks.py
@@ -408,27 +408,6 @@ def _plot_and_print_results(
)
plt.plot(df_pred.index, df_pred[df_pred.columns[0]], lw=2, c="tab:green")
else:
- """
- # Looks too noisy to output all loops predictions
- for idx_loop in range(ns_parser.n_loops):
- plt.plot(
- [df_stock.index[-1], df_pred.index[0]],
- [
- df_stock["5. adjusted close"].values[-1],
- df_pred[df_pred.columns[idx_loop]].values[0],
- ],
- lw=0.5,
- c="tab:green",
- linestyle="--",
- )
- plt.plot(
- df_pred.index,
- df_pred[df_pred.columns[idx_loop]],
- lw=1,
- ls="--",
- c="tab:green",
- )
- """
df_quantiles = pd.DataFrame()
df_quantiles["Quantile 10%"] = df_pred.quantile(0.1, axis=1)
df_quantiles["Median"] = df_pred.quantile(0.5, axis=1)
diff --git a/gamestonk_terminal/prediction_techniques/pred_controller.py b/gamestonk_terminal/prediction_techniques/pred_controller.py
index 8d2bdb4b2be..2ca6c8e6443 100644
--- a/gamestonk_terminal/prediction_techniques/pred_controller.py
+++ b/gamestonk_terminal/prediction_techniques/pred_controller.py
@@ -1,8 +1,10 @@
import argparse
from typing import List
-import pandas as pd
from datetime import datetime
+import pandas as pd
import matplotlib.pyplot as plt
+from prompt_toolkit.completion import NestedCompleter
+
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
@@ -14,7 +16,6 @@ from gamestonk_terminal.prediction_techniques import (
regression,
sma,
)
-from prompt_toolkit.completion import NestedCompleter
class PredictionTechniquesController:
@@ -59,7 +60,6 @@ class PredictionTechniquesController:
choices=self.CHOICES,
)
- @staticmethod
def print_help(self):
""" Print help """
@@ -110,7 +110,7 @@ class PredictionTechniquesController:
def call_help(self, _):
"""Process Help command"""
- self.print_help(self)
+ self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
@@ -170,6 +170,7 @@ class PredictionTechniquesController:
def call_prophet(self, other_args: List[str]):
"""Process prophet command"""
+ # pylint: disable=import-outside-toplevel
from gamestonk_terminal.prediction_techniques import fbprophet
fbprophet.fbprophet(other_args, self.ticker, self.stock)
diff --git a/gamestonk_terminal/prediction_techniques/pred_helper.py b/gamestonk_terminal/prediction_techniques/pred_helper.py
index 43aba435f39..c69ac5f0616 100644
--- a/gamestonk_terminal/prediction_techniques/pred_helper.py
+++ b/gamestonk_terminal/prediction_techniques/pred_helper.py
@@ -1,13 +1,14 @@
import numpy as np
import pandas as pd
from colorama import Fore, Style
-from gamestonk_terminal import feature_flags as gtff
from sklearn.metrics import (
mean_absolute_error,
r2_score,
mean_squared_error,
)
+from gamestonk_terminal import feature_flags as gtff
+
def price_prediction_color(val: float, last_val: float) -> str:
if float(val) > last_val:
diff --git a/gamestonk_terminal/technical_analysis/finviz_view.py b/gamestonk_terminal/technical_analysis/finviz_view.py
index 0fc3f794356..1e74144ca48 100644
--- a/gamestonk_terminal/technical_analysis/finviz_view.py
+++ b/gamestonk_terminal/technical_analysis/finviz_view.py
@@ -3,10 +3,11 @@ __docformat__ = "numpy"
import argparse
from typing import List
-from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
from finvizfinance.quote import finvizfinance
from PIL import Image
+from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
+
def view(other_args: List[str], ticker: str):
"""View historical price with trendlines. [Source: Finviz]
diff --git a/gamestonk_terminal/technical_analysis/overlap.py b/gamestonk_terminal/technical_analysis/overlap.py
index 7509c0ce2f3..a6c4b5d971a 100644
--- a/gamestonk_terminal/technical_analysis/overlap.py
+++ b/gamestonk_terminal/technical_analysis/overlap.py
@@ -69,7 +69,7 @@ def ema(l_args, s_ticker, s_interval, df_stock):
offset=ns_parser.n_offset,
).dropna()
- _, axPrice = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
+ _, _ = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
plt.title(f"{ns_parser.n_length} EMA on {s_ticker}")
if s_interval == "1440min":
plt.plot(
diff --git a/gamestonk_terminal/technical_analysis/ta_controller.py b/gamestonk_terminal/technical_analysis/ta_controller.py
index 7362b2edb26..620e13ab55f 100644
--- a/gamestonk_terminal/technical_analysis/ta_controller.py
+++ b/gamestonk_terminal/technical_analysis/ta_controller.py
@@ -3,10 +3,12 @@ __docformat__ = "numpy"
import argparse
import os
-import pandas as pd
from typing import List
from datetime import datetime
+import pandas as pd
import matplotlib.pyplot as plt
+from prompt_toolkit.completion import NestedCompleter
+
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
@@ -18,7 +20,6 @@ from gamestonk_terminal.technical_analysis import volume as ta_volume
from gamestonk_terminal.technical_analysis import finbrain_view
from gamestonk_terminal.technical_analysis import tradingview_view
from gamestonk_terminal.technical_analysis import finviz_view
-from prompt_toolkit.completion import NestedCompleter
class TechnicalAnalysisController:
@@ -65,7 +66,6 @@ class TechnicalAnalysisController:
choices=self.CHOICES,
)
- @staticmethod
def print_help(self):
"""Print help"""
@@ -106,7 +106,6 @@ class TechnicalAnalysisController:
print(" ad chaikin accumulation/distribution line values")
print(" obv on balance volume")
print("")
- return
def switch(self, an_input: str):
"""Process and dispatch input
@@ -118,6 +117,7 @@ class TechnicalAnalysisController:
True - quit the program
None - continue in the menu
"""
+
(known_args, other_args) = self.ta_parser.parse_known_args(an_input.split())
# Due to Finviz implementation of Spectrum, we delete the generated spectrum figure
@@ -134,7 +134,7 @@ class TechnicalAnalysisController:
def call_help(self, _):
"""Process Help command"""
- self.print_help(self)
+ self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
diff --git a/gamestonk_terminal/technical_analysis/tradingview_view.py b/gamestonk_terminal/technical_analysis/tradingview_view.py
index 61d2faf0723..b2f1668dfb4 100644
--- a/gamestonk_terminal/technical_analysis/tradingview_view.py
+++ b/gamestonk_terminal/technical_analysis/tradingview_view.py
@@ -2,8 +2,9 @@ import argparse
from typing import List
import requests
import pandas as pd
-from gamestonk_terminal import config_terminal as cfg
from tradingview_ta import TA_Handler
+
+from gamestonk_terminal import config_terminal as cfg
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
)
diff --git a/notebooks/templates/due_diligence.ipynb b/notebooks/templates/due_diligence.ipynb
old mode 100644
new mode 100755
index 09f4d95510f..8b3672abe76
--- a/notebooks/templates/due_diligence.ipynb
+++ b/notebooks/templates/due_diligence.ipynb
@@ -150,7 +150,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from gamestonk_terminal.fundamental_analysis import market_watch_api as mw"
+ "from gamestonk_terminal.fundamental_analysis import market_watch_model as mw"
]
},
{
@@ -215,4 +215,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
-}
\ No newline at end of file
+}
diff --git a/notebooks/templates/econ_data.ipynb b/notebooks/templates/econ_data.ipynb
old mode 100644
new mode 100755
index 4eea6cc29a7..fa4f80f2693
--- a/notebooks/templates/econ_data.ipynb
+++ b/notebooks/templates/econ_data.ipynb
@@ -319,7 +319,7 @@
},
"outputs": [],
"source": [
- "edh.draw_graph(\"HCL=F\", cache_dir, line_type=\"line\", draw_mas=(20,50,200), draw_volume=True, time_delta=720, low_trend=False)"
+ "edh.draw_graph(\"CL=F\", cache_dir, line_type=\"line\", draw_mas=(20,50,200), draw_volume=True, time_delta=720, low_trend=False)"
]
},
{
diff --git a/poetry.lock b/poetry.lock
index 0a01734d46e..d232c41a1fd 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -31,7 +31,7 @@ speedups = ["aiodns", "brotlipy", "cchardet"]
[[package]]
name = "alpaca-trade-api"
-version = "1.1.0"
+version = "1.2.0"
description = "Alpaca API python client"
category = "main"
optional = false
@@ -104,7 +104,7 @@ tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"]
[[package]]
name = "astroid"
-version = "2.5.1"
+version = "2.5.3"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
optional = false
@@ -225,7 +225,7 @@ webencodings = "*"
[[package]]
name = "bpemb"
-version = "0.3.2"
+version = "0.3.3"
description = "Byte-pair embeddings in 275 languages"
category = "main"
optional = true
@@ -354,7 +354,7 @@ test = ["coverage"]
[[package]]
name = "cryptography"
-version = "3.4.6"
+version = "3.4.7"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main"
optional = false
@@ -530,23 +530,26 @@ python-versions = "*"
[[package]]
name = "finviz"
-version = "1.3.4"
-description = "Unofficial API for finviz.com"
+version = "1.4.1"
+description = "Unofficial API for FinViz.com"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
aiohttp = "*"
+beautifulsoup4 = "*"
cssselect = "*"
lxml = "*"
requests = "*"
+tenacity = "*"
+tqdm = "*"
urllib3 = "*"
user_agent = "*"
[[package]]
name = "finvizfinance"
-version = "0.9.3"
+version = "0.9.6"
description = "Finviz Finance. Information downloader."
category = "main"
optional = false
@@ -593,7 +596,7 @@ transformers = ">=3.5.0,<=3.5.1"
[[package]]
name = "flake8"
-version = "3.9.0"
+version = "3.9.1"
description = "the modular source code checker: pep8 pyflakes and co"
category = "dev"
optional = false
@@ -626,18 +629,21 @@ pandas = "*"
[[package]]
name = "ftfy"
-version = "5.9"
+version = "6.0.1"
description = "Fixes some problems with Unicode text after the fact"
category = "main"
optional = true
-python-versions = ">=3.5"
+python-versions = ">=3.6"
[package.dependencies]
wcwidth = "*"
+[package.extras]
+docs = ["furo", "sphinx"]
+
[[package]]
name = "fundamentalanalysis"
-version = "0.2.6"
+version = "0.2.7"
description = "Fully-fledged Fundamental Analysis package capable of collecting 20 years of Company Profiles, Financial Statements, Ratios and Stock Data of 13.000+ companies."
category = "main"
optional = false
@@ -695,7 +701,7 @@ test-win = ["pytest", "pytest-rerunfailures", "mock", "cython", "testfixtures",
[[package]]
name = "google-auth"
-version = "1.28.0"
+version = "1.29.0"
description = "Google Authentication Library"
category = "main"
optional = true
@@ -710,10 +716,11 @@ six = ">=1.9.0"
[package.extras]
aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"]
pyopenssl = ["pyopenssl (>=20.0.0)"]
+reauth = ["pyu2f (>=0.1.5)"]
[[package]]
name = "google-auth-oauthlib"
-version = "0.4.3"
+version = "0.4.4"
description = "Google Authentication Library"
category = "main"
optional = true
@@ -830,7 +837,7 @@ idna = ">=2.0"
[[package]]
name = "importlib-metadata"
-version = "3.7.3"
+version = "4.0.1"
description = "Read metadata from Python packages"
category = "main"
optional = false
@@ -842,7 +849,7 @@ zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
[[package]]
name = "inflection"
@@ -862,7 +869,7 @@ python-versions = "*"
[[package]]
name = "ipykernel"
-version = "5.5.0"
+version = "5.5.3"
description = "IPython Kernel for Jupyter"
category = "main"
optional = false
@@ -946,7 +953,7 @@ python-versions = "*"
[[package]]
name = "isort"
-version = "5.7.0"
+version = "5.8.0"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
@@ -999,7 +1006,7 @@ name = "joblib"
version = "1.0.1"
description = "Lightweight pipelining with Python functions"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.6"
[[package]]
@@ -1038,14 +1045,15 @@ qtconsole = "*"
[[package]]
name = "jupyter-client"
-version = "6.1.12"
+version = "6.2.0"
description = "Jupyter protocol implementation and client libraries"
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6.1"
[package.dependencies]
jupyter-core = ">=4.6.0"
+nest-asyncio = ">=1.5"
python-dateutil = ">=2.1"
pyzmq = ">=13"
tornado = ">=4.1"
@@ -1053,11 +1061,11 @@ traitlets = "*"
[package.extras]
doc = ["sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
-test = ["async-generator", "ipykernel", "ipython", "mock", "pytest-asyncio", "pytest-timeout", "pytest", "jedi (<0.18)"]
+test = ["async-generator", "ipykernel", "ipython", "mock", "pytest-asyncio", "pytest-timeout", "pytest", "mypy", "pre-commit", "jedi (<0.18)"]
[[package]]
name = "jupyter-console"
-version = "6.3.0"
+version = "6.4.0"
description = "Jupyter terminal console"
category = "main"
optional = false
@@ -1131,16 +1139,14 @@ python-versions = ">=3.6"
[[package]]
name = "konoha"
-version = "4.6.4"
+version = "4.6.3"
description = "A tiny sentence/word tokenizer for Japanese text written in Python"
category = "main"
optional = true
python-versions = ">=3.6.1,<4.0.0"
[package.dependencies]
-importlib-metadata = ">=3.7.0,<4.0.0"
overrides = ">=3.0.0,<4.0.0"
-requests = ">=2.25.1,<3.0.0"
[package.extras]
janome = ["janome (>=0.3.10,<0.4.0)"]
@@ -1177,11 +1183,11 @@ six = "*"
[[package]]
name = "lazy-object-proxy"
-version = "1.5.2"
+version = "1.6.0"
description = "A fast and thorough lazy object proxy."
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[[package]]
name = "lunarcalendar"
@@ -1198,7 +1204,7 @@ pytz = "*"
[[package]]
name = "lxml"
-version = "4.6.2"
+version = "4.6.3"
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
category = "main"
optional = false
@@ -1295,7 +1301,7 @@ python-versions = "*"
[[package]]
name = "mplfinance"
-version = "0.12.7a10"
+version = "0.12.7a12"
description = "Utilities for the visualization, and visual analysis, of financial data"
category = "main"
optional = false
@@ -1405,7 +1411,7 @@ webpdf = ["pyppeteer (==0.2.2)"]
[[package]]
name = "nbformat"
-version = "5.1.2"
+version = "5.1.3"
description = "The Jupyter Notebook format"
category = "main"
optional = false
@@ -1431,14 +1437,14 @@ python-versions = ">=3.5"
[[package]]
name = "networkx"
-version = "2.5"
+version = "2.5.1"
description = "Python package for creating and manipulating graphs and networks"
category = "main"
optional = true
python-versions = ">=3.6"
[package.dependencies]
-decorator = ">=4.3.0"
+decorator = ">=4.3,<5"
[package.extras]
all = ["numpy", "scipy", "pandas", "matplotlib", "pygraphviz", "pydot", "pyyaml", "lxml", "pytest"]
@@ -1455,11 +1461,11 @@ scipy = ["scipy"]
[[package]]
name = "notebook"
-version = "6.2.0"
+version = "6.3.0"
description = "A web-based notebook environment for interactive computing"
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
[package.dependencies]
argon2-cffi = "*"
@@ -1490,6 +1496,14 @@ category = "main"
optional = false
python-versions = ">=3.6"
+[[package]]
+name = "oandapyv20"
+version = "0.6.3"
+description = "Python wrapper for the OANDA REST-V20 API"
+category = "main"
+optional = false
+python-versions = "*"
+
[[package]]
name = "oauthlib"
version = "3.1.0"
@@ -1620,7 +1634,7 @@ test = ["boto3", "botocore", "codecov", "coverage", "google-compute-engine", "ip
[[package]]
name = "parso"
-version = "0.8.1"
+version = "0.8.2"
description = "A Python Parser"
category = "main"
optional = false
@@ -1775,18 +1789,18 @@ tests = ["pytest", "pytest-cov"]
[[package]]
name = "prometheus-client"
-version = "0.9.0"
+version = "0.10.1"
description = "Python client for the Prometheus monitoring system."
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
twisted = ["twisted"]
[[package]]
name = "prompt-toolkit"
-version = "3.0.17"
+version = "3.0.18"
description = "Library for building powerful interactive command lines in Python"
category = "main"
optional = false
@@ -1797,7 +1811,7 @@ wcwidth = "*"
[[package]]
name = "protobuf"
-version = "3.15.6"
+version = "3.15.8"
description = "Protocol Buffers"
category = "main"
optional = true
@@ -1876,7 +1890,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pycoingecko"
-version = "1.4.0"
+version = "1.4.1"
description = "Python wrapper around the CoinGecko API"
category = "main"
optional = false
@@ -1895,7 +1909,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyflakes"
-version = "2.3.0"
+version = "2.3.1"
description = "passive checker of Python programs"
category = "dev"
optional = false
@@ -1911,14 +1925,14 @@ python-versions = ">=3.5"
[[package]]
name = "pylint"
-version = "2.7.2"
+version = "2.7.4"
description = "python code static checker"
category = "dev"
optional = false
python-versions = "~=3.6"
[package.dependencies]
-astroid = ">=2.5.1,<2.6"
+astroid = ">=2.5.2,<2.7"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.7"
@@ -2020,7 +2034,7 @@ numpy = ">=1.7"
[[package]]
name = "pytest"
-version = "6.2.2"
+version = "6.2.3"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
@@ -2040,6 +2054,14 @@ toml = "*"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+[[package]]
+name = "python-coinmarketcap"
+version = "0.2"
+description = "CoinMarketCap Python API Wrapper"
+category = "main"
+optional = false
+python-versions = "*"
+
[[package]]
name = "python-dateutil"
version = "2.8.1"
@@ -2053,8 +2075,8 @@ six = ">=1.5"
[[package]]
name = "python-dotenv"
-version = "0.15.0"
-description = "Add .env support to your django/flask apps in development and deployments"
+version = "0.17.0"
+description = "Read key-value pairs from a .env file and set them as environment variables"
category = "main"
optional = false
python-versions = "*"
@@ -2085,7 +2107,7 @@ python-versions = "*"
[[package]]
name = "pyupgrade"
-version = "2.11.0"
+version = "2.13.0"
description = "A tool to automatically upgrade syntax for newer versions."
category = "dev"
optional = false
@@ -2191,7 +2213,7 @@ six = "*"
[[package]]
name = "rapidfuzz"
-version = "1.3.0"
+version = "1.4.1"
description = "rapid fuzzy string matching"
category = "main"
optional = false
@@ -2277,7 +2299,7 @@ pyasn1 = ">=0.1.3"
[[package]]
name = "sacremoses"
-version = "0.0.43"
+version = "0.0.45"
description = "SacreMoses"
category = "main"
optional = true
@@ -2295,7 +2317,7 @@ name = "scikit-learn"
version = "0.24.1"
description = "A set of python modules for machine learning and data mining"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.6"
[package.dependencies]
@@ -2336,7 +2358,7 @@ pyobjc-framework-Cocoa = {version = "*", markers = "sys_platform == \"darwin\""}
[[package]]
name = "scs"
-version = "2.1.2"
+version = "2.1.3"
description = "scs: splitting conic solver"
category = "main"
optional = false
@@ -2371,6 +2393,17 @@ python-versions = "*"
[package.dependencies]
regex = "*"
+[[package]]
+name = "selenium"
+version = "3.141.0"
+description = "Python bindings for Selenium"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+urllib3 = "*"
+
[[package]]
name = "send2trash"
version = "1.5.0"
@@ -2405,7 +2438,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "smart-open"
-version = "4.2.0"
+version = "5.0.0"
description = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)"
category = "main"
optional = true
@@ -2414,10 +2447,10 @@ python-versions = ">=3.6.*"
[package.extras]
all = ["boto3", "google-cloud-storage", "azure-storage-blob", "azure-common", "azure-core", "requests"]
azure = ["azure-storage-blob", "azure-common", "azure-core"]
-gcp = ["google-cloud-storage"]
+gcs = ["google-cloud-storage"]
http = ["requests"]
s3 = ["boto3"]
-test = ["boto3", "google-cloud-storage", "azure-storage-blob", "azure-common", "azure-core", "requests", "mock", "moto[server] (==1.3.14)", "pathlib2", "responses", "boto3", "paramiko", "parameterizedtestcase", "pytest", "pytest-rerunfailures"]
+test = ["boto3", "google-cloud-storage", "azure-storage-blob", "azure-common", "azure-core", "requests", "mock", "moto[server] (==1.3.14)", "pathlib2", "responses", "paramiko", "parameterizedtestcase", "pytest", "pytest-rerunfailures"]
webhdfs = ["requests"]
[[package]]
@@ -2482,7 +2515,7 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"]
[[package]]
name = "tensorboard"
-version = "2.4.1"
+version = "2.5.0"
description = "TensorBoard lets you watch Tensors Flow"
category = "main"
optional = true
@@ -2497,10 +2530,18 @@ markdown = ">=2.6.8"
numpy = ">=1.12.0"
protobuf = ">=3.6.0"
requests = ">=2.21.0,<3"
-six = ">=1.10.0"
+tensorboard-data-server = ">=0.6.0,<0.7.0"
tensorboard-plugin-wit = ">=1.6.0"
werkzeug = ">=0.11.15"
+[[package]]
+name = "tensorboard-data-server"
+version = "0.6.0"
+description = "Fast data loading for TensorBoard"
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
[[package]]
name = "tensorboard-plugin-wit"
version = "1.8.0"
@@ -2554,7 +2595,7 @@ python-versions = "*"
[[package]]
name = "terminado"
-version = "0.9.3"
+version = "0.9.4"
description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library."
category = "main"
optional = false
@@ -2565,6 +2606,9 @@ ptyprocess = {version = "*", markers = "os_name != \"nt\""}
pywinpty = {version = ">=0.5", markers = "os_name == \"nt\""}
tornado = ">=4"
+[package.extras]
+test = ["pytest"]
+
[[package]]
name = "testpath"
version = "0.4.4"
@@ -2589,7 +2633,7 @@ name = "threadpoolctl"
version = "2.1.0"
description = "threadpoolctl"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.5"
[[package]]
@@ -2660,7 +2704,7 @@ python-versions = ">= 3.5"
[[package]]
name = "tqdm"
-version = "4.59.0"
+version = "4.60.0"
description = "Fast, Extensible Progress Meter"
category = "main"
optional = false
@@ -2739,7 +2783,7 @@ torch = ["torch (>=1.0)"]
[[package]]
name = "typed-ast"
-version = "1.4.2"
+version = "1.4.3"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "main"
optional = false
@@ -2793,6 +2837,14 @@ python-versions = "*"
[package.dependencies]
six = "*"
+[[package]]
+name = "valinvest"
+version = "0.0.2"
+description = "A value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
[[package]]
name = "wcwidth"
version = "0.2.5"
@@ -2874,7 +2926,7 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
[[package]]
name = "yfinance"
-version = "0.1.55"
+version = "0.1.59"
description = "Yahoo! Finance market data downloader"
category = "main"
optional = false
@@ -2901,7 +2953,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
[[package]]
name = "zope.interface"
-version = "5.3.0"
+version = "5.4.0"
description = "Interfaces for Python"
category = "main"
optional = false
@@ -2918,7 +2970,7 @@ prediction = ["fbprophet", "tensorflow", "pmdarima", "transformers", "flair", "t
[metadata]
lock-version = "1.1"
python-versions = "^3.6.8"
-content-hash = "623e5809320b1fb71c692bdd6cdcb9ea3419f3a5b3592e6c755816bd493769bc"
+content-hash = "2088d5cb7d1789cabe8d0f0f211ec599f56e630b4997527b9838d3ecf517f04c"
[metadata.files]
absl-py = [
@@ -2965,8 +3017,8 @@ aiohttp = [
{file = "aiohttp-3.7.4.post0.tar.gz", hash = "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf"},
]
alpaca-trade-api = [
- {file = "alpaca-trade-api-1.1.0.tar.gz", hash = "sha256:751e06db061cf69aeaf6e21e7cce1baee652cc222a4c00c9f3c2074f7711f757"},
- {file = "alpaca_trade_api-1.1.0-py3-none-any.whl", hash = "sha256:098cde3d3ce70a000c643131e6750f372184db79998e91bf9c5ed787a0da3b13"},
+ {file = "alpaca-trade-api-1.2.0.tar.gz", hash = "sha256:9f383c361bc5076ffbe4366b0887289399dfa6ac36799580ffa480cf589037ef"},
+ {file = "alpaca_trade_api-1.2.0-py3-none-any.whl", hash = "sha256:9184895e74bd59b9f7014ad0b54e6504878b2d54e9f4293db6860767e4462210"},
]
alpha-vantage = [
{file = "alpha_vantage-2.3.1-py3-none-any.whl", hash = "sha256:5d05355febe6f0fafc4bd11dc6ce3504a02d9d3c105d60202539855c0f608661"},
@@ -3005,8 +3057,8 @@ argon2-cffi = [
{file = "argon2_cffi-20.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a84934bd818e14a17943de8099d41160da4a336bcc699bb4c394bbb9b94bd32"},
]
astroid = [
- {file = "astroid-2.5.1-py3-none-any.whl", hash = "sha256:21d735aab248253531bb0f1e1e6d068f0ee23533e18ae8a6171ff892b98297cf"},
- {file = "astroid-2.5.1.tar.gz", hash = "sha256:cfc35498ee64017be059ceffab0a25bedf7548ab76f2bea691c5565896e7128d"},
+ {file = "astroid-2.5.3-py3-none-any.whl", hash = "sha256:bea3f32799fbb8581f58431c12591bc20ce11cbc90ad82e2ea5717d94f2080d5"},
+ {file = "astroid-2.5.3.tar.gz", hash = "sha256:ad63b8552c70939568966811a088ef0bc880f99a24a00834abd0e3681b514f91"},
]
astunparse = [
{file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"},
@@ -3045,8 +3097,8 @@ bleach = [
{file = "bleach-3.3.0.tar.gz", hash = "sha256:98b3170739e5e83dd9dc19633f074727ad848cbedb6026708c8ac2d3b697a433"},
]
bpemb = [
- {file = "bpemb-0.3.2-py3-none-any.whl", hash = "sha256:2a84d0ef963221d01a41b2a4c5d26ef2978992d6558e7289bbe58f7fd03a6446"},
- {file = "bpemb-0.3.2.tar.gz", hash = "sha256:7ef2564f656ec48c4621f555c4431c4ec71900f3c45c8d2203f9c78446e8391c"},
+ {file = "bpemb-0.3.3-py3-none-any.whl", hash = "sha256:061d033d28d7aea7d4a6eb6c91b282805ad216b61dfaf1517dc87f8a02a3ef2f"},
+ {file = "bpemb-0.3.3.tar.gz", hash = "sha256:ad86ba9b1623ecc3be6fcc5ba4408e23a30e118b7e1d683d292f4be788798ffe"},
]
bs4 = [
{file = "bs4-0.0.1.tar.gz", hash = "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"},
@@ -3127,18 +3179,18 @@ convertdate = [
{file = "convertdate-2.3.2.tar.gz", hash = "sha256:57df962a6047534f1452c390ad48e3dc5c83052ad83ad6dd78d60ae22f99214c"},
]
cryptography = [
- {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"},
- {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"},
- {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"},
- {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"},
- {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"},
- {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b"},
- {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df"},
- {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336"},
- {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724"},
- {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"},
+ {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"},
+ {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"},
+ {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"},
+ {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"},
+ {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"},
+ {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"},
+ {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"},
+ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"},
+ {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"},
+ {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"},
]
cssselect = [
{file = "cssselect-1.1.0-py2.py3-none-any.whl", hash = "sha256:f612ee47b749c877ebae5bb77035d8f4202c6ad0f0fc1271b3c18ad6c4468ecf"},
@@ -3285,19 +3337,19 @@ filelock = [
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
finviz = [
- {file = "finviz-1.3.4.tar.gz", hash = "sha256:3e850019c1b239dbaa6a75e982b513805182c205f6e957db48425a5f41fbd788"},
+ {file = "finviz-1.4.1.tar.gz", hash = "sha256:7b1a2a730ce8e09dfe64aad30b499a3adaf0fdf2d52cba6dd3ef9813248182be"},
]
finvizfinance = [
- {file = "finvizfinance-0.9.3-py3-none-any.whl", hash = "sha256:7a342012b9d97e3390d9942c3a87c615628ed5733eeb1ccf1083328a7c486a43"},
- {file = "finvizfinance-0.9.3.tar.gz", hash = "sha256:45dfaf8f6d0df214d5dd86a37c11b1a67ccaa524066d93299236d21bad8a3bd8"},
+ {file = "finvizfinance-0.9.6-py3-none-any.whl", hash = "sha256:18db3403bac6c3e6dae9d2c8d555df10d228e34daf02e4d50bb69c46e578cb7d"},
+ {file = "finvizfinance-0.9.6.tar.gz", hash = "sha256:9a5f5a1a1e67e810e4f6819cda0e3966f95313ff27d06466ae8a91e5a0e0cdbe"},
]
flair = [
{file = "flair-0.7-py3-none-any.whl", hash = "sha256:42c7e8074f67eeac722d68f4d5a9ad602377a76f5c4a2a190b916645b9be6ff2"},
{file = "flair-0.7.tar.gz", hash = "sha256:50cfe5382b41ba88d9cd7096fb82d21d7f938b167fc7de2c8365bf53f3576ef4"},
]
flake8 = [
- {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"},
- {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"},
+ {file = "flake8-3.9.1-py2.py3-none-any.whl", hash = "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"},
+ {file = "flake8-3.9.1.tar.gz", hash = "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378"},
]
flatbuffers = [
{file = "flatbuffers-1.12-py2.py3-none-any.whl", hash = "sha256:9e9ef47fa92625c4721036e7c4124182668dc6021d9e7c73704edd395648deb9"},
@@ -3308,10 +3360,11 @@ fredapi = [
{file = "fredapi-0.4.3.tar.gz", hash = "sha256:d9b3194fb60541991bd33f019c710d4a9580ecfb5e47efbf2d2571888a2aac02"},
]
ftfy = [
- {file = "ftfy-5.9.tar.gz", hash = "sha256:8c4fb2863c0b82eae2ab3cf353d9ade268dfbde863d322f78d6a9fd5cefb31e9"},
+ {file = "ftfy-6.0.1.tar.gz", hash = "sha256:9eb68533eb2a6124e96ed7f63049e6c519194fda3fae92629b5e0b5753cb2c8f"},
]
fundamentalanalysis = [
- {file = "FundamentalAnalysis-0.2.6.tar.gz", hash = "sha256:0033d51784ae6c75a7347942ec3114bfb9d5db494e5fbd67eb693c6ed6fee4fa"},
+ {file = "FundamentalAnalysis-0.2.7-py3-none-any.whl", hash = "sha256:dff63a9c8792a6f4cadbffc9c5ce7b5c7636a890ffac1cdd9d265beedd2f1090"},
+ {file = "FundamentalAnalysis-0.2.7.tar.gz", hash = "sha256:9ef0fbf52b7d0be3038103739db9d6a789adc98d2fde5335f427d1bba5291944"},
]
future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
@@ -3348,12 +3401,12 @@ gensim = [
{file = "gensim-3.8.2.win32-py3.7.exe", hash = "sha256:3234cbd52c0a4d548f385393040277fab03593358fee5673533e7ee6ed2f406c"},
]
google-auth = [
- {file = "google-auth-1.28.0.tar.gz", hash = "sha256:9bd436d19ab047001a1340720d2b629eb96dd503258c524921ec2af3ee88a80e"},
- {file = "google_auth-1.28.0-py2.py3-none-any.whl", hash = "sha256:dcaba3aa9d4e0e96fd945bf25a86b6f878fcb05770b67adbeb50a63ca4d28a5e"},
+ {file = "google-auth-1.29.0.tar.gz", hash = "sha256:010f011c4e27d3d5eb01106fba6aac39d164842dfcd8709955c4638f5b11ccf8"},
+ {file = "google_auth-1.29.0-py2.py3-none-any.whl", hash = "sha256:f30a672a64d91cc2e3137765d088c5deec26416246f7a9e956eaf69a8d7ed49c"},
]
google-auth-oauthlib = [
- {file = "google-auth-oauthlib-0.4.3.tar.gz", hash = "sha256:54431535309cfab50897d9c181e8c2226268825aa6e42e930b05b99c5041a18c"},
- {file = "google_auth_oauthlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:dabffbf594a6be2fd6d054060846d1201569252efb10dfb749b504a7591f8af0"},
+ {file = "google-auth-oauthlib-0.4.4.tar.gz", hash = "sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee"},
+ {file = "google_auth_oauthlib-0.4.4-py2.py3-none-any.whl", hash = "sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317"},
]
google-pasta = [
{file = "google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e"},
@@ -3454,8 +3507,8 @@ idna-ssl = [
{file = "idna-ssl-1.1.0.tar.gz", hash = "sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c"},
]
importlib-metadata = [
- {file = "importlib_metadata-3.7.3-py3-none-any.whl", hash = "sha256:b74159469b464a99cb8cc3e21973e4d96e05d3024d337313fedb618a6e86e6f4"},
- {file = "importlib_metadata-3.7.3.tar.gz", hash = "sha256:742add720a20d0467df2f444ae41704000f50e1234f46174b51f9c6031a1bd71"},
+ {file = "importlib_metadata-4.0.1-py3-none-any.whl", hash = "sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d"},
+ {file = "importlib_metadata-4.0.1.tar.gz", hash = "sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581"},
]
inflection = [
{file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"},
@@ -3466,8 +3519,8 @@ iniconfig = [
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
ipykernel = [
- {file = "ipykernel-5.5.0-py3-none-any.whl", hash = "sha256:efd07253b54d84d26e0878d268c8c3a41582a18750da633c2febfd2ece0d467d"},
- {file = "ipykernel-5.5.0.tar.gz", hash = "sha256:98321abefdf0505fb3dc7601f60fc4087364d394bd8fad53107eb1adee9ff475"},
+ {file = "ipykernel-5.5.3-py3-none-any.whl", hash = "sha256:21abd584543759e49010975a4621603b3cf871b1039cb3879a14094717692614"},
+ {file = "ipykernel-5.5.3.tar.gz", hash = "sha256:a682e4f7affd86d9ce9b699d21bcab6d5ec9fbb2bfcb194f2706973b252bc509"},
]
ipython = [
{file = "ipython-7.16.1-py3-none-any.whl", hash = "sha256:2dbcc8c27ca7d3cfe4fcdff7f45b27f9a8d3edfa70ff8024a71c7a8eb5f09d64"},
@@ -3486,8 +3539,8 @@ iso8601 = [
{file = "iso8601-0.1.14.tar.gz", hash = "sha256:8aafd56fa0290496c5edbb13c311f78fa3a241f0853540da09d9363eae3ebd79"},
]
isort = [
- {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"},
- {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"},
+ {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
+ {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
]
janome = [
{file = "Janome-0.4.1-py2.py3-none-any.whl", hash = "sha256:a650e2684e80af72f869eff17566f31dd4444f5443c4771dca1ada60cea5c251"},
@@ -3515,12 +3568,12 @@ jupyter = [
{file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"},
]
jupyter-client = [
- {file = "jupyter_client-6.1.12-py3-none-any.whl", hash = "sha256:e053a2c44b6fa597feebe2b3ecb5eea3e03d1d91cc94351a52931ee1426aecfc"},
- {file = "jupyter_client-6.1.12.tar.gz", hash = "sha256:c4bca1d0846186ca8be97f4d2fa6d2bae889cce4892a167ffa1ba6bd1f73e782"},
+ {file = "jupyter_client-6.2.0-py3-none-any.whl", hash = "sha256:9715152067e3f7ea3b56f341c9a0f9715c8c7cc316ee0eb13c3c84f5ca0065f5"},
+ {file = "jupyter_client-6.2.0.tar.gz", hash = "sha256:e2ab61d79fbf8b56734a4c2499f19830fbd7f6fefb3e87868ef0545cb3c17eb9"},
]
jupyter-console = [
- {file = "jupyter_console-6.3.0-py3-none-any.whl", hash = "sha256:092283ba2c9b5ceb53f32d95891ecc59ed4bfeb69e36fe017db176213daa5b0e"},
- {file = "jupyter_console-6.3.0.tar.gz", hash = "sha256:947f66bbdeee2221b4fb3a6b78225d337b8f10832f14cecf7932183635abe1d9"},
+ {file = "jupyter_console-6.4.0-py3-none-any.whl", hash = "sha256:7799c4ea951e0e96ba8260575423cb323ea5a03fcf5503560fa3e15748869e27"},
+ {file = "jupyter_console-6.4.0.tar.gz", hash = "sha256:242248e1685039cd8bff2c2ecb7ce6c1546eb50ee3b08519729e6e881aec19c7"},
]
jupyter-core = [
{file = "jupyter_core-4.7.1-py3-none-any.whl", hash = "sha256:8c6c0cac5c1b563622ad49321d5ec47017bd18b94facb381c6973a0486395f8e"},
@@ -3573,8 +3626,8 @@ kiwisolver = [
{file = "kiwisolver-1.3.1.tar.gz", hash = "sha256:950a199911a8d94683a6b10321f9345d5a3a8433ec58b217ace979e18f16e248"},
]
konoha = [
- {file = "konoha-4.6.4-py3-none-any.whl", hash = "sha256:4d6fd63f4977dda9a55bb5fdc3c626d03d6be0d491fa7e098ac971a346290515"},
- {file = "konoha-4.6.4.tar.gz", hash = "sha256:7c6f24b3bd37d3ac5a27db68fcf59d9a71c1cd0471431639459c3d6fb1eec2be"},
+ {file = "konoha-4.6.3-py3-none-any.whl", hash = "sha256:b5c79c6c3ccbe03ed19ed0a562e1a924256e416c8b9e5812a0cce095351b6689"},
+ {file = "konoha-4.6.3.tar.gz", hash = "sha256:24a93d27bd428b846dcfacc53bcec9a1b94154062feabf67f3d4ea41c6428c14"},
]
korean-lunar-calendar = [
{file = "korean_lunar_calendar-0.2.1-py3-none-any.whl", hash = "sha256:a619ea88610129019267467b85cc9faf0fab6e1694b2e782d1aeb610cdd382d5"},
@@ -3585,73 +3638,70 @@ langdetect = [
{file = "langdetect-1.0.8.tar.gz", hash = "sha256:363795ea005f1243c958e953245dac5d814fabdc025c9afa91588c5fa6b2fa83"},
]
lazy-object-proxy = [
- {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"},
- {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"},
- {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"},
- {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"},
- {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"},
- {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"},
- {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"},
- {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"},
+ {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"},
+ {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"},
+ {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"},
+ {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"},
+ {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"},
+ {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"},
]
lunarcalendar = [
{file = "LunarCalendar-0.0.9-py2.py3-none-any.whl", hash = "sha256:5ef25883d73898b37edb54da9e0f04215aaa68b897fd12e9d4b79756ff91c8cb"},
{file = "LunarCalendar-0.0.9.tar.gz", hash = "sha256:681142f22fc353c3abca4b25699e3d1aa7083ad1c268dce36ba297eca04bed5a"},
]
lxml = [
- {file = "lxml-4.6.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f"},
- {file = "lxml-4.6.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d"},
- {file = "lxml-4.6.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2"},
- {file = "lxml-4.6.2-cp27-cp27m-win32.whl", hash = "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e"},
- {file = "lxml-4.6.2-cp27-cp27m-win_amd64.whl", hash = "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e"},
- {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2"},
- {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe"},
- {file = "lxml-4.6.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388"},
- {file = "lxml-4.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80"},
- {file = "lxml-4.6.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b"},
- {file = "lxml-4.6.2-cp35-cp35m-win32.whl", hash = "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8"},
- {file = "lxml-4.6.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780"},
- {file = "lxml-4.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af"},
- {file = "lxml-4.6.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37"},
- {file = "lxml-4.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98"},
- {file = "lxml-4.6.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d"},
- {file = "lxml-4.6.2-cp36-cp36m-win32.whl", hash = "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf"},
- {file = "lxml-4.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939"},
- {file = "lxml-4.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e"},
- {file = "lxml-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711"},
- {file = "lxml-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089"},
- {file = "lxml-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01"},
- {file = "lxml-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2"},
- {file = "lxml-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc"},
- {file = "lxml-4.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d"},
- {file = "lxml-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3"},
- {file = "lxml-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644"},
- {file = "lxml-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308"},
- {file = "lxml-4.6.2-cp38-cp38-win32.whl", hash = "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505"},
- {file = "lxml-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a"},
- {file = "lxml-4.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931"},
- {file = "lxml-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03"},
- {file = "lxml-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5"},
- {file = "lxml-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a"},
- {file = "lxml-4.6.2-cp39-cp39-win32.whl", hash = "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75"},
- {file = "lxml-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf"},
- {file = "lxml-4.6.2.tar.gz", hash = "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc"},
+ {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"},
+ {file = "lxml-4.6.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f"},
+ {file = "lxml-4.6.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d"},
+ {file = "lxml-4.6.3-cp27-cp27m-win32.whl", hash = "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106"},
+ {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"},
+ {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"},
+ {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-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-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"},
+ {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-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"},
+ {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-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"},
+ {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-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"},
+ {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"},
]
markdown = [
{file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"},
@@ -3758,8 +3808,8 @@ mpld3 = [
{file = "mpld3-0.3.tar.gz", hash = "sha256:4d455884a211bf99b37ecc760759435c7bb6a5955de47d8daf4967e301878ab7"},
]
mplfinance = [
- {file = "mplfinance-0.12.7a10-py3-none-any.whl", hash = "sha256:aa4d9759a1befadfed190f9fc72ac8389d80fb61bc6f8ce6693d9c2627e88021"},
- {file = "mplfinance-0.12.7a10.tar.gz", hash = "sha256:f3745ad29ec834cd5505aa510f401f2c44b44328f92c781d093b3bb597641545"},
+ {file = "mplfinance-0.12.7a12-py3-none-any.whl", hash = "sha256:e1ae6e763b9ea5c7b74037c04f5e85af42272053d938592b5b54a610fc16ab6c"},
+ {file = "mplfinance-0.12.7a12.tar.gz", hash = "sha256:5e48d4eab079457c025cfae37ae95a8693b5f3a2ba64e7a08104fbaf1462a400"},
]
msgpack = [
{file = "msgpack-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b6d9e2dae081aa35c44af9c4298de4ee72991305503442a5c74656d82b581fe9"},
@@ -3870,20 +3920,20 @@ nbconvert = [
{file = "nbconvert-6.0.7.tar.gz", hash = "sha256:cbbc13a86dfbd4d1b5dee106539de0795b4db156c894c2c5dc382062bbc29002"},
]
nbformat = [
- {file = "nbformat-5.1.2-py3-none-any.whl", hash = "sha256:3949fdc8f5fa0b1afca16fb307546e78494fa7a7bceff880df8168eafda0e7ac"},
- {file = "nbformat-5.1.2.tar.gz", hash = "sha256:1d223e64a18bfa7cdf2db2e9ba8a818312fc2a0701d2e910b58df66809385a56"},
+ {file = "nbformat-5.1.3-py3-none-any.whl", hash = "sha256:eb8447edd7127d043361bc17f2f5a807626bc8e878c7709a1c647abda28a9171"},
+ {file = "nbformat-5.1.3.tar.gz", hash = "sha256:b516788ad70771c6250977c1374fcca6edebe6126fd2adb5a69aa5c2356fd1c8"},
]
nest-asyncio = [
{file = "nest_asyncio-1.5.1-py3-none-any.whl", hash = "sha256:76d6e972265063fe92a90b9cc4fb82616e07d586b346ed9d2c89a4187acea39c"},
{file = "nest_asyncio-1.5.1.tar.gz", hash = "sha256:afc5a1c515210a23c461932765691ad39e8eba6551c055ac8d5546e69250d0aa"},
]
networkx = [
- {file = "networkx-2.5-py3-none-any.whl", hash = "sha256:8c5812e9f798d37c50570d15c4a69d5710a18d77bafc903ee9c5fba7454c616c"},
- {file = "networkx-2.5.tar.gz", hash = "sha256:7978955423fbc9639c10498878be59caf99b44dc304c2286162fd24b458c1602"},
+ {file = "networkx-2.5.1-py3-none-any.whl", hash = "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06"},
+ {file = "networkx-2.5.1.tar.gz", hash = "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a"},
]
notebook = [
- {file = "notebook-6.2.0-py3-none-any.whl", hash = "sha256:25ad93c982b623441b491e693ef400598d1a46cdf11b8c9c0b3be6c61ebbb6cd"},
- {file = "notebook-6.2.0.tar.gz", hash = "sha256:0464b28e18e7a06cec37e6177546c2322739be07962dd13bf712bcb88361f013"},
+ {file = "notebook-6.3.0-py3-none-any.whl", hash = "sha256:cb271af1e8134e3d6fc6d458bdc79c40cbfc84c1eb036a493f216d58f0880e92"},
+ {file = "notebook-6.3.0.tar.gz", hash = "sha256:cbc9398d6c81473e9cdb891d2cae9c0d3718fca289dda6d26df5cb660fcadc7d"},
]
numpy = [
{file = "numpy-1.19.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc6bd4fd593cb261332568485e20a0712883cf631f6f5e8e86a52caa8b2b50ff"},
@@ -3921,6 +3971,9 @@ numpy = [
{file = "numpy-1.19.5-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:a0d53e51a6cb6f0d9082decb7a4cb6dfb33055308c4c44f53103c073f649af73"},
{file = "numpy-1.19.5.zip", hash = "sha256:a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4"},
]
+oandapyv20 = [
+ {file = "oandapyV20-0.6.3.tar.gz", hash = "sha256:173a56b41ab3a19315c2fbea6f9aa3f0c17f64ba84acff014d072c64c1844b28"},
+]
oauthlib = [
{file = "oauthlib-3.1.0-py2.py3-none-any.whl", hash = "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"},
{file = "oauthlib-3.1.0.tar.gz", hash = "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889"},
@@ -3996,8 +4049,8 @@ papermill = [
{file = "papermill-2.3.3.tar.gz", hash = "sha256:349aecd526c15c39f73a08df836467e2fead877c474d82c7df349f27ad272525"},
]
parso = [
- {file = "parso-0.8.1-py2.py3-none-any.whl", hash = "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410"},
- {file = "parso-0.8.1.tar.gz", hash = "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e"},
+ {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"},
+ {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"},
]
pathspec = [
{file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
@@ -4086,34 +4139,34 @@ prettytable = [
{file = "prettytable-2.1.0.tar.gz", hash = "sha256:5882ed9092b391bb8f6e91f59bcdbd748924ff556bb7c634089d5519be87baa0"},
]
prometheus-client = [
- {file = "prometheus_client-0.9.0-py2.py3-none-any.whl", hash = "sha256:b08c34c328e1bf5961f0b4352668e6c8f145b4a087e09b7296ef62cbe4693d35"},
- {file = "prometheus_client-0.9.0.tar.gz", hash = "sha256:9da7b32f02439d8c04f7777021c304ed51d9ec180604700c1ba72a4d44dceb03"},
+ {file = "prometheus_client-0.10.1-py2.py3-none-any.whl", hash = "sha256:030e4f9df5f53db2292eec37c6255957eb76168c6f974e4176c711cf91ed34aa"},
+ {file = "prometheus_client-0.10.1.tar.gz", hash = "sha256:b6c5a9643e3545bcbfd9451766cbaa5d9c67e7303c7bc32c750b6fa70ecb107d"},
]
prompt-toolkit = [
- {file = "prompt_toolkit-3.0.17-py3-none-any.whl", hash = "sha256:4cea7d09e46723885cb8bc54678175453e5071e9449821dce6f017b1d1fbfc1a"},
- {file = "prompt_toolkit-3.0.17.tar.gz", hash = "sha256:9397a7162cf45449147ad6042fa37983a081b8a73363a5253dd4072666333137"},
+ {file = "prompt_toolkit-3.0.18-py3-none-any.whl", hash = "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04"},
+ {file = "prompt_toolkit-3.0.18.tar.gz", hash = "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"},
]
protobuf = [
- {file = "protobuf-3.15.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1771ef20e88759c4d81db213e89b7a1fc53937968e12af6603c658ee4bcbfa38"},
- {file = "protobuf-3.15.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1a66261a402d05c8ad8c1fde8631837307bf8d7e7740a4f3941fc3277c2e1528"},
- {file = "protobuf-3.15.6-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:eac23a3e56175b710f3da9a9e8e2aa571891fbec60e0c5a06db1c7b1613b5cfd"},
- {file = "protobuf-3.15.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ec220d90eda8bb7a7a1434a8aed4fe26d7e648c1a051c2885f3f5725b6aa71a"},
- {file = "protobuf-3.15.6-cp35-cp35m-win32.whl", hash = "sha256:88d8f21d1ac205eedb6dea943f8204ed08201b081dba2a966ab5612788b9bb1e"},
- {file = "protobuf-3.15.6-cp35-cp35m-win_amd64.whl", hash = "sha256:eaada29bbf087dea7d8bce4d1d604fc768749e8809e9c295922accd7c8fce4d5"},
- {file = "protobuf-3.15.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:256c0b2e338c1f3228d3280707606fe5531fde85ab9d704cde6fdeb55112531f"},
- {file = "protobuf-3.15.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b9069e45b6e78412fba4a314ea38b4a478686060acf470d2b131b3a2c50484ec"},
- {file = "protobuf-3.15.6-cp36-cp36m-win32.whl", hash = "sha256:24f4697f57b8520c897a401b7f9a5ae45c369e22c572e305dfaf8053ecb49687"},
- {file = "protobuf-3.15.6-cp36-cp36m-win_amd64.whl", hash = "sha256:d9ed0955b794f1e5f367e27f8a8ff25501eabe34573f003f06639c366ca75f73"},
- {file = "protobuf-3.15.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:822ac7f87fc2fb9b24edd2db390538b60ef50256e421ca30d65250fad5a3d477"},
- {file = "protobuf-3.15.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:74ac159989e2b02d761188a2b6f4601ff5e494d9b9d863f5ad6e98e5e0c54328"},
- {file = "protobuf-3.15.6-cp37-cp37m-win32.whl", hash = "sha256:30fe4249a364576f9594180589c3f9c4771952014b5f77f0372923fc7bafbbe2"},
- {file = "protobuf-3.15.6-cp37-cp37m-win_amd64.whl", hash = "sha256:45a91fc6f9aa86d3effdeda6751882b02de628519ba06d7160daffde0c889ff8"},
- {file = "protobuf-3.15.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83c7c7534f050cb25383bb817159416601d1cc46c40bc5e851ec8bbddfc34a2f"},
- {file = "protobuf-3.15.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9ec20a6ded7d0888e767ad029dbb126e604e18db744ac0a428cf746e040ccecd"},
- {file = "protobuf-3.15.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0f2da2fcc4102b6c3b57f03c9d8d5e37c63f8bc74deaa6cb54e0cc4524a77247"},
- {file = "protobuf-3.15.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:70054ae1ce5dea7dec7357db931fcf487f40ea45b02cb719ee6af07eb1e906fb"},
- {file = "protobuf-3.15.6-py2.py3-none-any.whl", hash = "sha256:1655fc0ba7402560d749de13edbfca1ac45d1753d8f4e5292989f18f5a00c215"},
- {file = "protobuf-3.15.6.tar.gz", hash = "sha256:2b974519a2ae83aa1e31cff9018c70bbe0e303a46a598f982943c49ae1d4fcd3"},
+ {file = "protobuf-3.15.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fad4f971ec38d8df7f4b632c819bf9bbf4f57cfd7312cf526c69ce17ef32436a"},
+ {file = "protobuf-3.15.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f17b352d7ce33c81773cf81d536ca70849de6f73c96413f17309f4b43ae7040b"},
+ {file = "protobuf-3.15.8-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:4a054b0b5900b7ea7014099e783fb8c4618e4209fffcd6050857517b3f156e18"},
+ {file = "protobuf-3.15.8-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:efa4c4d4fc9ba734e5e85eaced70e1b63fb3c8d08482d839eb838566346f1737"},
+ {file = "protobuf-3.15.8-cp35-cp35m-win32.whl", hash = "sha256:07eec4e2ccbc74e95bb9b3afe7da67957947ee95bdac2b2e91b038b832dd71f0"},
+ {file = "protobuf-3.15.8-cp35-cp35m-win_amd64.whl", hash = "sha256:f9cadaaa4065d5dd4d15245c3b68b967b3652a3108e77f292b58b8c35114b56c"},
+ {file = "protobuf-3.15.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2dc0e8a9e4962207bdc46a365b63a3f1aca6f9681a5082a326c5837ef8f4b745"},
+ {file = "protobuf-3.15.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f80afc0a0ba13339bbab25ca0409e9e2836b12bb012364c06e97c2df250c3343"},
+ {file = "protobuf-3.15.8-cp36-cp36m-win32.whl", hash = "sha256:c5566f956a26cda3abdfacc0ca2e21db6c9f3d18f47d8d4751f2209d6c1a5297"},
+ {file = "protobuf-3.15.8-cp36-cp36m-win_amd64.whl", hash = "sha256:dab75b56a12b1ceb3e40808b5bd9dfdaef3a1330251956e6744e5b6ed8f8830b"},
+ {file = "protobuf-3.15.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3053f13207e7f13dc7be5e9071b59b02020172f09f648e85dc77e3fcb50d1044"},
+ {file = "protobuf-3.15.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1f0b5d156c3df08cc54bc2c8b8b875648ea4cd7ebb2a9a130669f7547ec3488c"},
+ {file = "protobuf-3.15.8-cp37-cp37m-win32.whl", hash = "sha256:90270fe5732c1f1ff664a3bd7123a16456d69b4e66a09a139a00443a32f210b8"},
+ {file = "protobuf-3.15.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f42c2f5fb67da5905bfc03733a311f72fa309252bcd77c32d1462a1ad519521e"},
+ {file = "protobuf-3.15.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6077db37bfa16494dca58a4a02bfdacd87662247ad6bc1f7f8d13ff3f0013e1"},
+ {file = "protobuf-3.15.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:510e66491f1a5ac5953c908aa8300ec47f793130097e4557482803b187a8ee05"},
+ {file = "protobuf-3.15.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5ff9fa0e67fcab442af9bc8d4ec3f82cb2ff3be0af62dba047ed4187f0088b7d"},
+ {file = "protobuf-3.15.8-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1c0e9e56202b9dccbc094353285a252e2b7940b74fdf75f1b4e1b137833fabd7"},
+ {file = "protobuf-3.15.8-py2.py3-none-any.whl", hash = "sha256:a0a08c6b2e6d6c74a6eb5bf6184968eefb1569279e78714e239d33126e753403"},
+ {file = "protobuf-3.15.8.tar.gz", hash = "sha256:0277f62b1e42210cafe79a71628c1d553348da81cbd553402a7f7549c50b11d0"},
]
psaw = [
{file = "psaw-0.0.12-py3-none-any.whl", hash = "sha256:cfbfdf1953ee5f31ca9d4ec6d471873ace960da9fbc7234b9d19a059d5cfa2d6"},
@@ -4165,24 +4218,24 @@ pycodestyle = [
{file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
]
pycoingecko = [
- {file = "pycoingecko-1.4.0-py3-none-any.whl", hash = "sha256:bc6e2d87a59bda88bd01a241b37d49c30104842534fdf65ba96616c90419d756"},
- {file = "pycoingecko-1.4.0.tar.gz", hash = "sha256:082949e83b49ab89090d19b88b6177c9458679dc4a98323db950bd4cef7afa2e"},
+ {file = "pycoingecko-1.4.1-py3-none-any.whl", hash = "sha256:289e5d129872439c7d76cb60037078e72a84f6d24b6034dde12bb5dc87fccb82"},
+ {file = "pycoingecko-1.4.1.tar.gz", hash = "sha256:de754cccc398feaf9230f710f93a15500af7457e86192fbceedf96ddfe8cabd4"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
]
pyflakes = [
- {file = "pyflakes-2.3.0-py2.py3-none-any.whl", hash = "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d"},
- {file = "pyflakes-2.3.0.tar.gz", hash = "sha256:e59fd8e750e588358f1b8885e5a4751203a0516e0ee6d34811089ac294c8806f"},
+ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
]
pygments = [
{file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"},
{file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"},
]
pylint = [
- {file = "pylint-2.7.2-py3-none-any.whl", hash = "sha256:d09b0b07ba06bcdff463958f53f23df25e740ecd81895f7d2699ec04bbd8dc3b"},
- {file = "pylint-2.7.2.tar.gz", hash = "sha256:0e21d3b80b96740909d77206d741aa3ce0b06b41be375d92e1f3244a274c1f8a"},
+ {file = "pylint-2.7.4-py3-none-any.whl", hash = "sha256:209d712ec870a0182df034ae19f347e725c1e615b2269519ab58a35b3fcbbe7a"},
+ {file = "pylint-2.7.4.tar.gz", hash = "sha256:bd38914c7731cdc518634a8d3c5585951302b6e2b6de60fbb3f7a0220e21eeee"},
]
pymeeus = [
{file = "PyMeeus-0.5.11.tar.gz", hash = "sha256:bb9d670818d8b0594317b48a7dadea02a0594e5344263bf2054e1a011c8fed55"},
@@ -4246,16 +4299,21 @@ pystan = [
{file = "pystan-2.19.1.1.tar.gz", hash = "sha256:fa8bad8dbc0da22bbe6f36af56c9abbfcf10f92df8ce627d59a36bd8d25eb038"},
]
pytest = [
- {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"},
- {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"},
+ {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"},
+ {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"},
+]
+python-coinmarketcap = [
+ {file = "python-coinmarketcap-0.2.tar.gz", hash = "sha256:b1e0e8b098fc910a5ec943a06774d5ee3b190e915123366e2f16238ef0a8a433"},
+ {file = "python_coinmarketcap-0.2-py2-none-any.whl", hash = "sha256:54c278154ee11ca78837fb73eae8c322a60af93dc0ce75b515fecf895d181cf5"},
+ {file = "python_coinmarketcap-0.2-py3-none-any.whl", hash = "sha256:3b69a7a92cd4f2b4726a2982d166c0b587fa4911cf366286f798e1e6f9d94933"},
]
python-dateutil = [
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
]
python-dotenv = [
- {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"},
- {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"},
+ {file = "python-dotenv-0.17.0.tar.gz", hash = "sha256:471b782da0af10da1a80341e8438fca5fadeba2881c54360d5fd8d03d03a4f4a"},
+ {file = "python_dotenv-0.17.0-py2.py3-none-any.whl", hash = "sha256:49782a97c9d641e8a09ae1d9af0856cc587c8d2474919342d5104d85be9890b2"},
]
pytrends = [
{file = "pytrends-4.7.3-py3-none-any.whl", hash = "sha256:88d92e398b9408c79fd92946ddc2b03fa622301233bc49f16804042eb2897328"},
@@ -4266,8 +4324,8 @@ pytz = [
{file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
]
pyupgrade = [
- {file = "pyupgrade-2.11.0-py2.py3-none-any.whl", hash = "sha256:47cd92db1675a9043bebbe0b67a103b66527883b35e22634060a6bcb99138baa"},
- {file = "pyupgrade-2.11.0.tar.gz", hash = "sha256:5dcae14b1c9b7ecce5ec42210528eb30a1a2408613da744f2ba4a9b54b344cf6"},
+ {file = "pyupgrade-2.13.0-py2.py3-none-any.whl", hash = "sha256:1cb5a15573fc63824b952bf7dde5b96f9672a1179ec779ac2d159a845da743c8"},
+ {file = "pyupgrade-2.13.0.tar.gz", hash = "sha256:dc6b580b7bc82f357acb354bbba03d8d69da51425ecd5993a2651059bca80518"},
]
pywin32 = [
{file = "pywin32-300-cp35-cp35m-win32.whl", hash = "sha256:1c204a81daed2089e55d11eefa4826c05e604d27fe2be40b6bf8db7b6a39da63"},
@@ -4389,67 +4447,67 @@ quandl = [
{file = "Quandl-3.6.1.tar.gz", hash = "sha256:84414e5f8e870a9c8a9392e9dc639d50e839c5f5e07737a09bb57dd8b14b264b"},
]
rapidfuzz = [
- {file = "rapidfuzz-1.3.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d49956421daad639040e44dc12b301eb3f105f2ca4a5e9b32ed6c9650f02789a"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d5a8f133fb85ea2ed882ab7053d69d0a60cc0c0a7e8bc30bb5e306066279508"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9059004a081a86f3fbdb44e3d36897264196883a339f740476d1869dd41e4068"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:c524cb3267a48ff826f54b70a396e0bc6eb5ba997f2900bc6eff242e43aaafb4"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:ec74086dd1e00f8beeeda14aab80657c7dd84a8c4a7ab67bddce1f2ad41dbe1f"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:b08e8f3dbfd718832dfc77ea87484a8b8942c4f3fafacfd92b1204679d97d8fd"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:3f07c9e13457620e32caa8192aa04e8bf8b99dab2d93a9679ef829c86e98fede"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:e61d8870134c3f419634387c9baa3997f4e5c4294fe620de39662562089212cf"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-win32.whl", hash = "sha256:aa19c9c1b53f6019de4d2451a62b2cba1dee49e53f58905c84215e17a4ba3fed"},
- {file = "rapidfuzz-1.3.0-cp35-cp35m-win_amd64.whl", hash = "sha256:3d2d91358994e2b8379dc529399521c2a3ec727bfdcea7552b0877be1ec54117"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:03d4fefc4a4ca0512040d0753d0be79d920d22e56cd2bc25f2ee6bdcd4176dc9"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:525634b52c0d9544b19105230fe0e09d2dce43901fa5f019a547d8667299f2b8"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c3679dad6789183219dea5ddb927bf62211dc1fdf5b6d17ad49971d2895f9518"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:6f18c4d9fc65caf6068e306acc40192ade6d9af88939eeda3617864b4d2e8abf"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:9aa106d30859a57a1447346cdeddeb7015748281f43f2054e3276551406c39c5"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:3efb9f3c0d1ea0ec82d38075306f7e721dd88fb9ec0684dd350d73d83df6ba53"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:ed0387466970882468535a4a49bc14336783c55035a7e5d0edb36d05e253b8fe"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:78b4e66dec10f9f3d7cc35e6924442b8c121bdaa8a0dbd70311561fd9ff87170"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-win32.whl", hash = "sha256:1cb927ea0904caad8f2923dfdfa0975c93fdc8528b882feda78cbfc373ffa229"},
- {file = "rapidfuzz-1.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2ba61d15d0ac83800f7a283b4c188ab54ac8595b1181714cc06b5f04ef33542a"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:076943f5b318483c263584cec59763d1aac70ea0dab5f5653fde495cd1e6395f"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d25d6f7d94b17a962526c2261cc8fc2e292c5a071db810aeb9d48771ae9ec3e6"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d282448a4121a947daa540fdf0e9a8808adcf81168cfca0da9786768f6209fbb"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:bdb9942565fb10bca30e707b8c96e6e5544bd4c604394fc92596355c34fef258"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:324f6b13274abdbed51d709d6a930cf1408c26a8013e279283f0131b5fc29ac0"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:aae04e463205b363f95ca6971d7f9e3ed39f65a5ef7fee35b01775bba1dde374"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:67a0af6e486bc706f9f64cbd024a0d8d8b63726df95bb7c7a155791391f19567"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:9931dad05f4d51cc4a610db3f33cc3631c4547412b4925380cca7f6f07041cb0"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:eeb6e1c0d63dc4909dfb7daa105c035ff6713189b5ea1c312f7e760f986296c0"},
- {file = "rapidfuzz-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f22193795ef02f9a6bf90e3898a81b927dfdb80c62c6cd3e59d87330a6d4bcf1"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a73a69108cc96fad0f57f374315107eef9e80f997da7483799a262616cc0ef31"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9d97ae27902ffc2efa87b272a79a7376ddea1639b969bf995f2b521c88c2d99e"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a2122c78ffcae47f562450928be439a5b94ddb5b0e0d8e365ee1d08e8fe6874f"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:b4e16aacf5969f0a24dc530d0aa610df105d8fa7dd2aa282a7db98a8039c1719"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1b52b7139b98d559bbd977bd28b7e68a8d75dc2345122ca8fcf938e7ff72b295"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:25edcf5a805479dd434155ea88e9e76e9b3677b670800d5e95e04556e1a4a0e0"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:92ee666f0cfa47e74e745e2bb794b43c6eeba2931c873a91b45b3439018cae77"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:4ab4513fbe47618dab0ffbdea7beb73695d730a424b8df719aee80e48f8d00ff"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-win32.whl", hash = "sha256:3db9d3ea27f0926a137f0e0169f5b29dd49b88fb0171ed7dfce224b890a86f11"},
- {file = "rapidfuzz-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:41b28235f68475a865a94b4c0bee3259f525aac523d182432b68f5cafa35d9a1"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7891ecf01052b69c0e0cc94695a506dd1374636292eca26e061a0c1dc3165f02"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:096b445dca7972161cdd1f856969414dde7cc9b09ff420005092d7b31139d41c"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:66c5579effe2a846117b4f499ab6910d164804c8fe31846a80981992d1b78e6e"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2997f73a0cb5abc3a31e8c740a908be426d71db38827486881728470cc60b2c5"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4fbbe7129df9ecd818f259136f598241206a6ac10b09763eafcf6fd1ca0fe83f"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:24a8af40f7fc41795892be937cf3480d5cd8ae1f62ef6a845e7258d05c9ab35c"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f02b615ad69279e6ed61a7ba072494cd05cfddde210472956139d3361f8f20d1"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:45d20908601158d06c65d9ed4a54585dc32bd49cadefc385374f77b9a4696368"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:0e3570ea068e0704f7b43d5228e97c45954dec370114071139fdd9cf731a1750"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:f027a7df163f5f1d13d9ea60bf06d8bc0730194a2d584c3185c3a77c1a145916"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-win32.whl", hash = "sha256:460bacd89c129cf1aefc56ae465f642c712aa9b620e74305040a1cf6975cc510"},
- {file = "rapidfuzz-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:5afa7539fb45b3c97fed67ca75a99ad7affce14561a3bd11e1c8d665b20ea8ab"},
- {file = "rapidfuzz-1.3.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5cadbd3f5df7e02dc11b819af860cb1a5365a49de515b76bf5dad62a3724ebaf"},
- {file = "rapidfuzz-1.3.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:7e2196346ae5a1a2ac79c780d63983df93c1dbbea8aed910c43ad13c67bddc35"},
- {file = "rapidfuzz-1.3.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:ac3bc9341d8f265eb65a66ec88f351851e89a0f22be916ed4e74590e347f159e"},
- {file = "rapidfuzz-1.3.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:3438c6db485dd5a3716a7f2e92a262b05db959f03712c4423b68a32453a5957d"},
- {file = "rapidfuzz-1.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ac6016f99dc36d490251c8b0910d7445921ca950ac204a4d299c0a298db8f0c"},
- {file = "rapidfuzz-1.3.0-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:9573c989a78866269ced934a5a345ea44d05f4b69576d91c7e5b21771d19e030"},
- {file = "rapidfuzz-1.3.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:6f97fdca7a43ddb4258ddc2d6a8e960b0f5b369346d8bac02cc20b7b51721eb1"},
- {file = "rapidfuzz-1.3.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:c92b7e3148a90ac9f8740e4235c64cf5a02d15a4cfbd3aa580e62327e22d4d6a"},
- {file = "rapidfuzz-1.3.0.tar.gz", hash = "sha256:f6a95ed17d7750ca75f11751ab46365c58f37a5d846e2b21d072d7a0e77ffa72"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:72878878d6744883605b5453c382361716887e9e552f677922f76d93d622d8cb"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:56a67a5b3f783e9af73940f6945366408b3a2060fc6ab18466e5a2894fd85617"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f5d396b64f8ae3a793633911a1fb5d634ac25bf8f13d440139fa729131be42d8"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4990698233e7eda7face7c09f5874a09760c7524686045cbb10317e3a7f3225f"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a87e212855b18a951e79ec71d71dbd856d98cd2019d0c2bd46ec30688a8aa68a"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1897d2ef03f5b51bc19bdb2d0398ae968766750fa319843733f0a8f12ddde986"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:e1fc4fd219057f5f1fa40bb9bc5e880f8ef45bf19350d4f5f15ca2ce7f61c99b"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:21300c4d048798985c271a8bf1ed1611902ebd4479fcacda1a3eaaebbad2f744"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:d2659967c6ac74211a87a1109e79253e4bc179641057c64800ef4e2dc0534fdb"},
+ {file = "rapidfuzz-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:26ac4bfe564c516e053fc055f1543d2b2433338806738c7582e1f75ed0485f7e"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3b485c98ad1ce3c04556f65aaab5d6d6d72121cde656d43505169c71ae956476"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:59db06356eaf22c83f44b0dded964736cbb137291cdf2cf7b4974c0983b94932"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fef95249af9a535854b617a68788c38cd96308d97ee14d44bc598cc73e986167"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:7d8c186e8270e103d339b26ef498581cf3178470ccf238dfd5fd0e47d80e4c7d"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:9246b9c5c8992a83a08ac7813c8bbff2e674ad0b681f9b3fb1ec7641eff6c21f"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f58c17f7a82b1bcc2ce304942cae14287223e6b6eead7071241273da7d9b9770"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:ed708620b23a09ac52eaaec0761943c1bbc9a62d19ecd2feb4da8c3f79ef9d37"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:bdec9ae5fd8a8d4d8813b4aac3505c027b922b4033a32a7aab66a9b2f03a7b47"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:fc668fd706ad1162ce14f26ca2957b4690d47770d23609756536c918a855ced0"},
+ {file = "rapidfuzz-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f9f35df5dd9b02669ff6b1d4a386607ff56982c86a7e57d95eb08c6afbab4ddd"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8427310ea29ce2968e1c6f6779ae5a458b3a4984f9150fc4d16f92b96456f848"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1430dc745476e3798742ad835f61f6e6bf5d3e9a22cf9cd0288b28b7440a9872"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d20311da611c8f4638a09e2bc5e04b327bae010cb265ef9628d9c13c6d5da7b"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7881965e428cf6fe248d6e702e6d5857da02278ab9b21313bee717c080e443e"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f76c965f15861ec4d39e904bd65b84a39121334439ac17bfb8b900d1e6779a93"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:61167f989415e701ac379de247e6b0a21ea62afc86c54d8a79f485b4f0173c02"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:645cfb9456229f0bd5752b3eda69f221d825fbb8cbb8855433516bc185111506"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:c28be57c9bc47b3d7f484340fab1bec8ed4393dee1090892c2774a4584435eb8"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:3c94b6d3513c693f253ff762112cc4580d3bd377e4abacb96af31a3d606fbe14"},
+ {file = "rapidfuzz-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:506d50a066451502ee2f8bf016bc3ba3e3b04eede7a4059d7956248e2dd96179"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:80b375098658bb3db14215a975d354f6573d3943ac2ae0c4627c7760d57ce075"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ba8f7cbd8fdbd3ae115f4484888f3cb94bc2ac7cbd4eb1ca95a3d4f874261ff8"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5fa8570720b0fdfc52f24f5663d66c52ea88ba19cb8b1ff6a39a8bc0b925b33b"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:f35c8a4c690447fd335bfd77df4da42dfea37cfa06a8ecbf22543d86dc720e12"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:27f9eef48e212d73e78f0f5ceedc62180b68f6a25fa0752d2ccfaedc3a840bec"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:31e99216e2a04aec4f281d472b28a683921f1f669a429cf605d11526623eaeed"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:f22bf7ba6eddd59764457f74c637ab5c3ed976c5fcfaf827e1d320cc0478e12b"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:c43ddb354abd00e56f024ce80affb3023fa23206239bb81916d5877cba7f2d1e"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-win32.whl", hash = "sha256:62c1f4ac20c8019ce8d481fb27235306ef3912a8d0b9a60b17905699f43ff072"},
+ {file = "rapidfuzz-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:2963f356c70b710dc6337b012ec976ce2fc2b81c2a9918a686838fead6eb4e1d"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c07f301fd549b266410654850c6918318d7dcde8201350e9ac0819f0542cf147"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa4c8b6fc7e93e3a3fb9be9566f1fe7ef920735eadcee248a0d70f3ca8941341"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c200bd813bbd3b146ba0fd284a9ad314bbad9d95ed542813273bdb9d0ee4e796"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2cccc84e1f0c6217747c09cafe93164e57d3644e18a334845a2dfbdd2073cd2c"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f2033e3d61d1e498f618123b54dc7436d50510b0d18fd678d867720e8d7b2f23"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:26b7f48b3ddd9d97cf8482a88f0f6cba47ac13ff16e63386ea7ce06178174770"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bf18614f87fe3bfff783f0a3d0fad0eb59c92391e52555976e55570a651d2330"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8cb5c2502ff06028a1468bdf61323b53cc3a37f54b5d62d62c5371795b81086a"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:f37f80c1541d6e0a30547261900086b8c0bac519ebc12c9cd6b61a9a43a7e195"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:c13cd1e840aa93639ac1d131fbfa740a609fd20dfc2a462d5cd7bce747a2398d"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-win32.whl", hash = "sha256:0ec346f271e96c485716c091c8b0b78ba52da33f7c6ebb52a349d64094566c2d"},
+ {file = "rapidfuzz-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:5208ce1b1989a10e6fc5b5ef5d0bb7d1ffe5408838f3106abde241aff4dab08c"},
+ {file = "rapidfuzz-1.4.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4fa195ea9ca35bacfa2a4319c6d4ab03aa6a283ad2089b70d2dfa0f6a7d9c1bc"},
+ {file = "rapidfuzz-1.4.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:6e336cfd8103b0b38e107e01502e9d6bf7c7f04e49b970fb11a4bf6c7a932b94"},
+ {file = "rapidfuzz-1.4.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c798c5b87efe8a7e63f408e07ff3bc03ba8b94f4498a89b48eaab3a9f439d52c"},
+ {file = "rapidfuzz-1.4.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:bb16a10b40f5bd3c645f7748fbd36f49699a03f550c010a2c665905cc8937de8"},
+ {file = "rapidfuzz-1.4.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2278001924031d9d75f821bff2c5fef565c8376f252562e04d8eec8857475c36"},
+ {file = "rapidfuzz-1.4.1-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:a89d11f3b5da35fdf3e839186203b9367d56e2be792e8dccb098f47634ec6eb9"},
+ {file = "rapidfuzz-1.4.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:f8c79cd11b4778d387366a59aa747f5268433f9d68be37b00d16f4fb08fdf850"},
+ {file = "rapidfuzz-1.4.1-pp37-pypy37_pp73-win32.whl", hash = "sha256:4364db793ed4b439f9dd28a335bee14e2a828283d3b93c2d2686cc645eeafdd5"},
+ {file = "rapidfuzz-1.4.1.tar.gz", hash = "sha256:de20550178376d21bfe1b34a7dc42ab107bb282ef82069cf6dfe2805a0029e26"},
]
regex = [
{file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"},
@@ -4514,7 +4572,8 @@ rsa = [
{file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"},
]
sacremoses = [
- {file = "sacremoses-0.0.43.tar.gz", hash = "sha256:123c1bf2664351fb05e16f87d3786dbe44a050cfd7b85161c09ad9a63a8e2948"},
+ {file = "sacremoses-0.0.45-py3-none-any.whl", hash = "sha256:fa93db44bc04542553ba6090818b892f603d02aa0d681e6c5c3023baf17e8564"},
+ {file = "sacremoses-0.0.45.tar.gz", hash = "sha256:58176cc28391830789b763641d0f458819bebe88681dac72b41a19c0aedc07e9"},
]
scikit-learn = [
{file = "scikit-learn-0.24.1.tar.gz", hash = "sha256:a0334a1802e64d656022c3bfab56a73fbd6bf4b1298343f3688af2151810bbdf"},
@@ -4582,7 +4641,7 @@ screeninfo = [
{file = "screeninfo-0.6.7.tar.gz", hash = "sha256:1c4bac1ca329da3f68cbc4d2fbc92256aa9bb8ff8583ee3e14f91f0a7baa69cb"},
]
scs = [
- {file = "scs-2.1.2.tar.gz", hash = "sha256:667ed6019bb4e2f925bd9291161d2c61cc0077443094437b703ea905333fd585"},
+ {file = "scs-2.1.3.tar.gz", hash = "sha256:7c9ca6730638abcbd004909e7f4816b9e2c1486d3e864b1a26261ca84002cbf0"},
]
seaborn = [
{file = "seaborn-0.11.1-py3-none-any.whl", hash = "sha256:4e1cce9489449a1c6ff3c567f2113cdb41122f727e27a984950d004a88ef3c5c"},
@@ -4591,6 +4650,10 @@ seaborn = [
segtok = [
{file = "segtok-1.5.10.tar.gz", hash = "sha256:2ed6525e840a669ec7ba3be61353a4f660264aecfc726834dbe4b01eb4ef7804"},
]
+selenium = [
+ {file = "selenium-3.141.0-py2.py3-none-any.whl", hash = "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c"},
+ {file = "selenium-3.141.0.tar.gz", hash = "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"},
+]
send2trash = [
{file = "Send2Trash-1.5.0-py3-none-any.whl", hash = "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"},
{file = "Send2Trash-1.5.0.tar.gz", hash = "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2"},
@@ -4630,7 +4693,8 @@ six = [
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
smart-open = [
- {file = "smart_open-4.2.0.tar.gz", hash = "sha256:d9f5a0f173ccb9bbae528db5a3804f57145815774f77ef755b9b0f3b4b2a9dcb"},
+ {file = "smart_open-5.0.0-py3-none-any.whl", hash = "sha256:ed310ac51a797051b42f9437a566ac8149a3abf8c80ab994a8bd92d96fb7cf44"},
+ {file = "smart_open-5.0.0.tar.gz", hash = "sha256:02e5e02207d955a1f9fd924c37900ac272536bd24393ae731b6945d4f766015f"},
]
soupsieve = [
{file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"},
@@ -4671,7 +4735,12 @@ tenacity = [
{file = "tenacity-7.0.0.tar.gz", hash = "sha256:5bd16ef5d3b985647fe28dfa6f695d343aa26479a04e8792b9d3c8f49e361ae1"},
]
tensorboard = [
- {file = "tensorboard-2.4.1-py3-none-any.whl", hash = "sha256:7b8c53c396069b618f6f276ec94fc45d17e3282d668979216e5d30be472115e4"},
+ {file = "tensorboard-2.5.0-py3-none-any.whl", hash = "sha256:e167460085b6528956b33bab1c970c989cdce47a6616273880733f5e7bde452e"},
+]
+tensorboard-data-server = [
+ {file = "tensorboard_data_server-0.6.0-py3-none-any.whl", hash = "sha256:a4b8e1c3fc85237b3afeef450db06c9a9b25f5854ad27c21667a90808acd1822"},
+ {file = "tensorboard_data_server-0.6.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:2d723d73e3a3b0a4498f56c64c39e2e26ac192414891df22c9f152b7058fd6bc"},
+ {file = "tensorboard_data_server-0.6.0-py3-none-manylinux2010_x86_64.whl", hash = "sha256:b620e520d3d535ceb896557acca0029fd7fd2f9f408af35abc2d2dad91f0345d"},
]
tensorboard-plugin-wit = [
{file = "tensorboard_plugin_wit-1.8.0-py3-none-any.whl", hash = "sha256:2a80d1c551d741e99b2f197bb915d8a133e24adb8da1732b840041860f91183a"},
@@ -4694,8 +4763,8 @@ termcolor = [
{file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"},
]
terminado = [
- {file = "terminado-0.9.3-py3-none-any.whl", hash = "sha256:430e876ec9d4d93a4fd8a49e82dcfae0c25f846540d0c5ca774b397533e237e8"},
- {file = "terminado-0.9.3.tar.gz", hash = "sha256:261c0b7825fecf629666e1820b484a5380f7e54d6b8bd889fa482e99dcf9bde4"},
+ {file = "terminado-0.9.4-py3-none-any.whl", hash = "sha256:daed77f9fad7b32558fa84b226a76f45a02242c20813502f36c4e1ade6d8f1ad"},
+ {file = "terminado-0.9.4.tar.gz", hash = "sha256:9a7dbcfbc2778830eeb70261bf7aa9d98a3eac8631a3afe3febeb57c12f798be"},
]
testpath = [
{file = "testpath-0.4.4-py2.py3-none-any.whl", hash = "sha256:bfcf9411ef4bf3db7579063e0546938b1edda3d69f4e1fb8756991f5951f85d4"},
@@ -4795,8 +4864,8 @@ tornado = [
{file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"},
]
tqdm = [
- {file = "tqdm-4.59.0-py2.py3-none-any.whl", hash = "sha256:9fdf349068d047d4cfbe24862c425883af1db29bcddf4b0eeb2524f6fbdb23c7"},
- {file = "tqdm-4.59.0.tar.gz", hash = "sha256:d666ae29164da3e517fcf125e41d4fe96e5bb375cd87ff9763f6b38b5592fe33"},
+ {file = "tqdm-4.60.0-py2.py3-none-any.whl", hash = "sha256:daec693491c52e9498632dfbe9ccfc4882a557f5fa08982db1b4d3adbe0887c3"},
+ {file = "tqdm-4.60.0.tar.gz", hash = "sha256:ebdebdb95e3477ceea267decfc0784859aa3df3e27e22d23b83e9b272bf157ae"},
]
tradingview-ta = [
{file = "tradingview_ta-3.2.3-py3-none-any.whl", hash = "sha256:5f6101239f452044d8c9421e80c7591befd717f159a562fb0fe66a306d63807e"},
@@ -4811,36 +4880,36 @@ transformers = [
{file = "transformers-3.5.1.tar.gz", hash = "sha256:0d637c6cecc13b12f33f9e79bf5757c85f433c851e3ae7845ff20b6c49f41441"},
]
typed-ast = [
- {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"},
- {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"},
- {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"},
- {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"},
- {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"},
- {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"},
- {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"},
- {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"},
- {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"},
- {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"},
- {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"},
- {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"},
- {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"},
- {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"},
- {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"},
- {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"},
- {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"},
- {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"},
- {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"},
- {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"},
- {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"},
- {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"},
- {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"},
- {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"},
- {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"},
- {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"},
- {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"},
- {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"},
- {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"},
- {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"},
+ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
+ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
+ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
+ {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
+ {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
+ {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
+ {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
+ {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
+ {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
+ {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
+ {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
+ {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
+ {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
+ {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
+ {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
+ {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
+ {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
+ {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
+ {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
+ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
]
typing-extensions = [
{file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
@@ -4858,6 +4927,10 @@ urllib3 = [
user-agent = [
{file = "user_agent-0.1.9.tar.gz", hash = "sha256:8f1ad46cc4aef9f99515ea1c74bb8cacc43e23074c335b2ba2db7735ebe9c0d5"},
]
+valinvest = [
+ {file = "valinvest-0.0.2-py3-none-any.whl", hash = "sha256:37fadaf30c69e0487fed8d9cc93bb792ca8cf36fed0839e0e755a84738166ab9"},
+ {file = "valinvest-0.0.2.tar.gz", hash = "sha256:9614aaf8019e015c20ea48867ede8a6ea10e1c6410e787314066d7b2e5aeb7dc"},
+]
wcwidth = [
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
@@ -4945,62 +5018,62 @@ yarl = [
{file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"},
]
yfinance = [
- {file = "yfinance-0.1.55.tar.gz", hash = "sha256:65d39bccf16bef35f6a08bf0df33650c0515b5ce8ea3c53924601f5fe00590cb"},
+ {file = "yfinance-0.1.59.tar.gz", hash = "sha256:fe4dc46807eceadc6604bf51ece7297b752dc5402a38a87385094fbfc7565fa0"},
]
zipp = [
{file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"},
{file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"},
]
"zope.interface" = [
- {file = "zope.interface-5.3.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:2ec58e1e1691dde4fbbd97f8610de0f8f1b1a38593653f7d3b8e931b9cd6d67f"},
- {file = "zope.interface-5.3.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d3cd9bad547a8e5fbe712a1dc1413aff1b917e8d39a2cd1389a6f933b7a21460"},
- {file = "zope.interface-5.3.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:672668729edcba0f2ee522ab177fcad91c81cfce991c24d8767765e2637d3515"},
- {file = "zope.interface-5.3.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:79b6db1a18253db86e9bf1e99fa829d60fd3fc7ac04f4451c44e4bdcf6756a42"},
- {file = "zope.interface-5.3.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:74b331c5d5efdddf5bbd9e1f7d8cb91a0d6b9c4ba45ca3e9003047a84dca1a3b"},
- {file = "zope.interface-5.3.0-cp27-cp27m-win32.whl", hash = "sha256:9c7044dbbf8c58420a9ef4ed6901f5a8b7698d90cd984d7f57a18c78474686f6"},
- {file = "zope.interface-5.3.0-cp27-cp27m-win_amd64.whl", hash = "sha256:96c2e68385f3848d58f19b2975a675532abdb65c8fa5f04d94b95b27b6b1ffa7"},
- {file = "zope.interface-5.3.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c7b6032dc4490b0dcaf078f09f5b382dc35493cb7f473840368bf0de3196c2b6"},
- {file = "zope.interface-5.3.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0378a42ec284b65706d9ef867600a4a31701a0d6773434e6537cfc744e3343f4"},
- {file = "zope.interface-5.3.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:823d1b4a6a028b8327e64865e2c81a8959ae9f4e7c9c8e0eec814f4f9b36b362"},
- {file = "zope.interface-5.3.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:67aa26097e194947d29f2b5a123830e03da1519bcce10cac034a51fcdb99c34f"},
- {file = "zope.interface-5.3.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b4d59ab3608538e550a72cea13d3c209dd72b6e19e832688da7884081c01594e"},
- {file = "zope.interface-5.3.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28d8157f8c77662a1e0796a7d3cfa8910289131d4b4dd4e10b2686ab1309b67b"},
- {file = "zope.interface-5.3.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:26109c50ccbcc10f651f76277cfc05fba8418a907daccc300c9247f24b3158a2"},
- {file = "zope.interface-5.3.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:416feb6500f7b6fc00d32271f6b8495e67188cb5eb51fc8e289b81fdf465a9cb"},
- {file = "zope.interface-5.3.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:b51d3f1cd87f488455f43046d72003689024b0fa9b2d53635db7523033b19996"},
- {file = "zope.interface-5.3.0-cp35-cp35m-win32.whl", hash = "sha256:0e6cdbdd94ae94d1433ab51f46a76df0f2cd041747c31baec1c1ffa4e76bd0c1"},
- {file = "zope.interface-5.3.0-cp35-cp35m-win_amd64.whl", hash = "sha256:2c51689b7b40c7d9c7e8a678350e73dc647945a13b4e416e7a02bbf0c37bdb01"},
- {file = "zope.interface-5.3.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:f966765f54b536e791541458de84a737a6adba8467190f17a8fe7f85354ba908"},
- {file = "zope.interface-5.3.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:61b8454190b9cc87279232b6de28dee0bad040df879064bb2f0e505cda907918"},
- {file = "zope.interface-5.3.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8af4b3116e4a37059bc8c7fe36d4a73d7c1d8802a1d8b6e549f1380d13a40160"},
- {file = "zope.interface-5.3.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:7d79cd354ae0a033ac7b86a2889c9e8bb0bb48243a6ed27fc5064ce49b842ada"},
- {file = "zope.interface-5.3.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:54243053316b5eec92affe43bbace7c8cd946bc0974a4aa39ff1371df0677b22"},
- {file = "zope.interface-5.3.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7426bea25bdf92f00fa52c7b30fcd2a2f71c21cf007178971b1f248b6c2d3145"},
- {file = "zope.interface-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:92195df3913c1de80062635bf64cd7bd0d0934a7fa1689b6d287d1cbbd16922c"},
- {file = "zope.interface-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c95b355dba2aaf5177dff943b25ded0529a7feb80021d5fdb114a99f0a1ef508"},
- {file = "zope.interface-5.3.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f3c37b0dc1898e305aad4f7a1d75f6da83036588c28a9ce0afc681ff5245a601"},
- {file = "zope.interface-5.3.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:527415b5ca201b4add44026f70278fbc0b942cf0801a26ca5527cb0389b6151e"},
- {file = "zope.interface-5.3.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c980ae87863d76b1ea9a073d6d95554b4135032d34bc541be50c07d4a085821b"},
- {file = "zope.interface-5.3.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:8b4b0034e6c7f30133fa64a1cc276f8f1a155ef9529e7eb93a3c1728b40c0f5c"},
- {file = "zope.interface-5.3.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c02105deda867d09cdd5088d08708f06d75759df6f83d8f7007b06f422908a30"},
- {file = "zope.interface-5.3.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e8809b01f27f679e3023b9e2013051e0a3f17abff4228cb5197663afd8a0f2c7"},
- {file = "zope.interface-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:221b41442cf4428fcda7fc958c9721c916709e2a3a9f584edd70f1493a09a762"},
- {file = "zope.interface-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:07d289358a8c565ea09e426590dd1179f93cf5ac3dd17d43fcc4fc63c1a9d275"},
- {file = "zope.interface-5.3.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:89a6091f2d07936c8a96ce56f2000ecbef20fb420a94845e7d53913c558a6378"},
- {file = "zope.interface-5.3.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a413c424199bcbab71bf5fa7538246f27177fbd6dd74b2d9c5f34878658807f8"},
- {file = "zope.interface-5.3.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:12588a46ae0a99f172c4524cbbc3bb870f32e0f8405e9fa11a5ef3fa3a808ad7"},
- {file = "zope.interface-5.3.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:11354fb8b8bdc5cdd66358ed4f1f0ce739d78ff6d215d33b8f3ae282258c0f11"},
- {file = "zope.interface-5.3.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:6e7305e42b5f54e5ccf51820de46f0a7c951ba7cb9e3f519e908545b0f5628d0"},
- {file = "zope.interface-5.3.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:520352b18adea5478bbf387e9c77910a914985671fe36bc5ef19fdcb67a854bc"},
- {file = "zope.interface-5.3.0-cp38-cp38-win32.whl", hash = "sha256:d12895cd083e35e9e032eb4b57645b91116f8979527381a8d864d1f6b8cb4a2e"},
- {file = "zope.interface-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:18c478b89b6505756f007dcf76a67224a23dcf0f365427742ed0c0473099caa4"},
- {file = "zope.interface-5.3.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:fa939c2e2468142c9773443d4038e7c915b0cc1b670d3c9192bdc503f7ea73e9"},
- {file = "zope.interface-5.3.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:02d3535aa18e34ce97c58d241120b7554f7d1cf4f8002fc9675cc7e7745d20e8"},
- {file = "zope.interface-5.3.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fcc5c1f95102989d2e116ffc8467963554ce89f30a65a3ea86a4d06849c498d8"},
- {file = "zope.interface-5.3.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:16caa44a06f6b0b2f7626ced4b193c1ae5d09c1b49c9b4962c93ae8aa2134f55"},
- {file = "zope.interface-5.3.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:8715717a5861932b7fe7f3cbd498c82ff4132763e2fea182cc95e53850394ec1"},
- {file = "zope.interface-5.3.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a1937efed7e3fe0ee74630e1960df887d8aa83c571e1cf4db9d15b9c181d457d"},
- {file = "zope.interface-5.3.0-cp39-cp39-win32.whl", hash = "sha256:7234ac6782ca43617de803735949f79b894f0c5d353fbc001d745503c69e6d1d"},
- {file = "zope.interface-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:a38c10423a475a1658e2cb8f52cf84ec20a4c0adff724dd43a6b45183f499bc1"},
- {file = "zope.interface-5.3.0.tar.gz", hash = "sha256:b18a855f8504743e0a2d8b75d008c7720d44e4c76687e13f959e35d9a13eb397"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-win32.whl", hash = "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325"},
+ {file = "zope.interface-5.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155"},
+ {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"},
+ {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959"},
+ {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e"},
+ {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-win32.whl", hash = "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8"},
+ {file = "zope.interface-5.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78"},
+ {file = "zope.interface-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7"},
+ {file = "zope.interface-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94"},
+ {file = "zope.interface-5.4.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3"},
+ {file = "zope.interface-5.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e"},
+ {file = "zope.interface-5.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7"},
+ {file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120"},
+ {file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48"},
+ {file = "zope.interface-5.4.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4"},
+ {file = "zope.interface-5.4.0-cp38-cp38-win32.whl", hash = "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb"},
+ {file = "zope.interface-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54"},
+ {file = "zope.interface-5.4.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4"},
+ {file = "zope.interface-5.4.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d"},
+ {file = "zope.interface-5.4.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83"},
+ {file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25"},
+ {file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1"},
+ {file = "zope.interface-5.4.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c"},
+ {file = "zope.interface-5.4.0-cp39-cp39-win32.whl", hash = "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e"},
+ {file = "zope.interface-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09"},
+ {file = "zope.interface-5.4.0.tar.gz", hash = "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e"},
]
diff --git a/pyproject.toml b/pyproject.toml
index 12ccd7ebcc8..d0f9c731ebc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -54,9 +54,13 @@ detecta = "^0.0.5"
tradingview-ta = "^3.2.3"
finvizfinance = "^0.9.3"
Pillow = "^8.2.0"
-pyportfolioopt = "^1.4.1"
statsmodels = "^0.12.2"
tabulate = "^0.8.9"
+pyportfolioopt = "^1.4.1"
+selenium = "^3.141.0"
+python-coinmarketcap = "^0.2"
+oandapyV20 = "^0.6.3"
+valinvest = "^0.0.2"
[tool.poetry.dev-dependencies]
pytest = "^6.2.2"
diff --git a/requirements-full.txt b/requirements-full.txt
index 29b46fbad43..654cd4398b4 100644
--- a/requirements-full.txt
+++ b/requirements-full.txt
@@ -1,10 +1,10 @@
aiohttp==3.7.4.post0; python_version >= "3.6"
-alpaca-trade-api==1.1.0
+alpaca-trade-api==1.2.0
alpha-vantage==2.3.1
ansiwrap==0.8.4; python_version >= "3.6"
appdirs==1.4.4; python_version >= "3.6"
appnope==0.1.2; platform_system == "Darwin" and python_version >= "3.6" and sys_platform == "darwin"
-argon2-cffi==20.1.0; python_version >= "3.5"
+argon2-cffi==20.1.0; python_version >= "3.6"
async-generator==1.10; python_full_version >= "3.6.1" and python_version >= "3.6"
async-timeout==3.0.1; python_full_version >= "3.5.3" and python_version >= "3.6"
attrs==20.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
@@ -19,11 +19,11 @@ chardet==4.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or pyt
click==7.1.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
colorama==0.4.4; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
convertdate==2.3.2; python_version >= "3.5"
-cryptography==3.4.6; python_version >= "3.6"
+cryptography==3.4.7; python_version >= "3.6"
cssselect==1.1.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
cvxpy==1.1.12; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
cycler==0.10.0; python_version >= "3.6"
-cython==0.29.17; python_version >= "2.6" and python_full_version < "3.0.0" and sys_platform == "darwin" or python_full_version >= "3.3.0" and sys_platform == "darwin"
+cython==0.29.17; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "darwin" or python_full_version >= "3.3.0" and python_version >= "3.6" and sys_platform == "darwin"
dataclasses==0.8; python_version >= "3.6" and python_version < "3.7"
datetime==4.3; python_version >= "3.5"
decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6")
@@ -31,49 +31,51 @@ defusedxml==0.7.1; python_version >= "3.6" and python_full_version < "3.0.0" or
detecta==0.0.5; python_version >= "3.6"
ecos==2.0.7.post1; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
entrypoints==0.3; python_version >= "3.6"
-finviz==1.3.4
-finvizfinance==0.9.3; python_version >= "3.5"
+finviz==1.4.1
+finvizfinance==0.9.6; python_version >= "3.5"
fredapi==0.4.3
-fundamentalanalysis==0.2.6
+fundamentalanalysis==0.2.7
h5py==2.10.0
hijri-converter==2.1.1; python_version >= "3.6"
holidays==0.10.5.2
idna-ssl==1.1.0; python_version < "3.7" and python_version >= "3.6"
idna==2.10; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version < "3.7" and python_version >= "3.6" and python_full_version >= "3.5.0"
-importlib-metadata==3.7.3; python_version < "3.8" and python_version >= "3.6"
+importlib-metadata==4.0.1; python_version < "3.8" and python_version >= "3.6"
inflection==0.5.1; python_version >= "3.5"
-ipykernel==5.5.0; python_version >= "3.6"
+ipykernel==5.5.3; python_version >= "3.6"
ipython-genutils==0.2.0; python_full_version >= "3.6.1" and python_version >= "3.6"
ipython==7.16.1; python_version >= "3.6"
ipywidgets==7.6.3
iso8601==0.1.14
jedi==0.18.0; python_version >= "3.6"
jinja2==2.11.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+joblib==1.0.1; python_version >= "3.6"
jsonschema==3.2.0; python_version >= "3.6"
-jupyter-client==6.1.12; python_full_version >= "3.6.1" and python_version >= "3.6"
-jupyter-console==6.3.0; python_version >= "3.6"
+jupyter-client==6.2.0; python_full_version >= "3.6.1" and python_version >= "3.6"
+jupyter-console==6.4.0; python_version >= "3.6"
jupyter-core==4.7.1; python_full_version >= "3.6.1" and python_version >= "3.6"
jupyter==1.0.0
jupyterlab-pygments==0.1.2; python_version >= "3.6"
jupyterlab-widgets==1.0.0; python_version >= "3.6"
kiwisolver==1.3.1; python_version >= "3.6"
korean-lunar-calendar==0.2.1
-lxml==4.6.2; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
+lxml==4.6.3; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
markupsafe==1.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
matplotlib==3.3.4; python_version >= "3.6"
mistune==0.8.4; python_version >= "3.6"
more-itertools==8.7.0; python_version >= "3.5"
-mplfinance==0.12.7a10
+mplfinance==0.12.7a12
msgpack==1.0.2
multidict==5.1.0; python_version >= "3.6"
multitasking==0.0.9
mypy-extensions==0.4.3; python_version >= "3.6"
nbclient==0.5.3; python_full_version >= "3.6.1" and python_version >= "3.6"
nbconvert==6.0.7; python_version >= "3.6"
-nbformat==5.1.2; python_full_version >= "3.6.1" and python_version >= "3.6"
+nbformat==5.1.3; python_full_version >= "3.6.1" and python_version >= "3.6"
nest-asyncio==1.5.1; python_full_version >= "3.6.1" and python_version >= "3.6"
-notebook==6.2.0; python_version >= "3.5"
+notebook==6.3.0; python_version >= "3.6"
numpy==1.19.5; python_version >= "3.6"
+oandapyv20==0.6.3
oauthlib==3.1.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
osqp==0.6.2.post0; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
@@ -81,22 +83,24 @@ pandas-ta==0.2.45b
pandas==1.1.5; python_full_version >= "3.6.1"
pandocfilters==1.4.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
papermill==2.3.3; python_version >= "3.6"
-parso==0.8.1; python_version >= "3.6"
+parso==0.8.2; python_version >= "3.6"
pathspec==0.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+patsy==0.5.1; python_version >= "3.6"
pexpect==4.8.0; sys_platform != "win32" and python_version >= "3.6"
pickleshare==0.7.5; python_version >= "3.6"
pillow==8.2.0; python_version >= "3.6"
plotly==4.14.3
+pmdarima==1.8.0; python_version >= "3.6"
praw==7.2.0; python_version >= "3.6" and python_version < "4.0"
prawcore==2.0.0; python_version >= "3.6" and python_version < "4.0"
prettytable==2.1.0; python_version >= "3.6"
-prometheus-client==0.9.0; python_version >= "3.5"
-prompt-toolkit==3.0.17; python_full_version >= "3.6.1"
+prometheus-client==0.10.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+prompt-toolkit==3.0.18; python_full_version >= "3.6.1"
psaw==0.0.12; python_version >= "3"
ptyprocess==0.7.0; os_name != "nt" and python_version >= "3.6" and sys_platform != "win32"
py==1.10.0; python_version >= "3.6" and python_full_version < "3.0.0" and implementation_name == "pypy" or implementation_name == "pypy" and python_version >= "3.6" and python_full_version >= "3.4.0"
pyally==1.1.2
-pycoingecko==1.4.0
+pycoingecko==1.4.1
pycparser==2.20; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pygments==2.8.1; python_version >= "3.6"
pymeeus==0.5.11; python_version >= "3.5"
@@ -107,8 +111,9 @@ pyparsing==2.4.7; python_version >= "3.6" and python_full_version < "3.0.0" or p
pyportfolioopt==1.4.1; python_full_version >= "3.6.1" and python_full_version < "4.0.0"
pyrsistent==0.14.11
pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0"
+python-coinmarketcap==0.2
python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0")
-python-dotenv==0.15.0; python_version >= "3"
+python-dotenv==0.17.0; python_version >= "3"
pytrends==4.7.3
pytz==2021.1; python_full_version >= "3.6.1" and python_version >= "3.5"
pywin32==300; sys_platform == "win32" and python_version >= "3.6"
@@ -119,41 +124,47 @@ qdldl==0.1.5.post0; python_full_version >= "3.6.1" and python_full_version < "4.
qtconsole==5.0.3; python_version >= "3.6"
qtpy==1.9.0; python_version >= "3.6"
quandl==3.6.1; python_version >= "3.5"
-rapidfuzz==1.3.0; python_version >= "3.5"
+rapidfuzz==1.4.1; python_version >= "3.5"
regex==2020.11.13
requests-oauthlib==1.3.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
requests==2.25.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
retrying==1.3.3
robin-stocks==2.0.3; python_version >= "3"
+scikit-learn==0.24.1; python_version >= "3.6"
scipy==1.5.4; python_version >= "3.6"
screeninfo==0.6.7
-scs==2.1.2; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
+scs==2.1.3; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
seaborn==0.11.1; python_version >= "3.6"
-send2trash==1.5.0; python_version >= "3.5"
-six==1.15.0; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") and (python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.5")
+selenium==3.141.0
+send2trash==1.5.0; python_version >= "3.6"
+six==1.15.0; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6")
soupsieve==2.2.1; python_version >= "3.6"
+statsmodels==0.12.2; python_version >= "3.6"
+tabulate==0.8.9
tenacity==7.0.0; python_version >= "3.6"
termcolor==1.1.0
-terminado==0.9.3; python_version >= "3.6"
+terminado==0.9.4; python_version >= "3.6"
testpath==0.4.4; python_version >= "3.6"
textwrap3==0.9.2; python_version >= "3.6"
+threadpoolctl==2.1.0; python_version >= "3.6"
timeseriescrossvalidation @ git+https://github.com/DidierRLopes/TimeSeriesCrossValidation.git@master
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
tornado==6.1; python_full_version >= "3.6.1" and python_version >= "3.6"
-tqdm==4.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+tqdm==4.60.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
tradingview-ta==3.2.3; python_version >= "3.5"
traitlets==4.3.3; python_full_version >= "3.6.1" and python_version >= "3.6"
-typed-ast==1.4.2; python_version >= "3.6"
+typed-ast==1.4.3; python_version >= "3.6"
typing-extensions==3.7.4.3; python_version < "3.8" and python_version >= "3.6"
update-checker==0.18.0; python_version >= "3.6" and python_version < "4.0"
-urllib3==1.26.4; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4"
+urllib3==1.26.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6"
user-agent==0.1.9
+valinvest==0.0.2; python_version >= "3.6"
wcwidth==0.2.5; python_version >= "3.6" and python_full_version >= "3.6.1"
webencodings==0.5.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
websocket-client==0.58.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
websockets==8.1; python_full_version >= "3.6.1"
widgetsnbextension==3.5.1
yarl==1.6.3; python_version >= "3.6"
-yfinance==0.1.55
+yfinance==0.1.59
zipp==3.4.1; python_version < "3.8" and python_version >= "3.6"
-zope.interface==5.3.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
+zope.interface==5.4.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
diff --git a/requirements-old.txt b/requirements-old.txt
index 3a4b6bb05c4..6dcb6d00577 100644
--- a/requirements-old.txt
+++ b/requirements-old.txt
@@ -93,6 +93,7 @@ pyparsing==2.4.7; python_full_version >= "3.6.0" and python_version >= "3.6"
pyportfolioopt==1.4.1
pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0"
pystan==2.18
+python-coinmarketcap==0.2
python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.5" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "2.7" and python_full_version < "3.0.0" and python_version < "4" or python_version >= "2.7" and python_version < "4" and python_full_version >= "3.3.0")
pytest==6.2.2; python_version >= "3.6"
pytrends==4.7.3
@@ -109,6 +110,7 @@ sacremoses==0.0.43; python_full_version >= "3.6.0" and python_version >= "3.6"
scikit-learn==0.24.1; python_version >= "3.6"
scipy==1.5.4; python_version >= "3.6"
segtok==1.5.10; python_version >= "3.6"
+selenium==3.141.0
sentencepiece==0.1.91; python_full_version >= "3.6.0" and python_version >= "3.6"
setuptools-git==1.2
six==1.15.0; python_full_version >= "3.6.0" and python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0")
diff --git a/requirements-win.txt b/requirements-win.txt
index 560a2508261..399b80c6f67 100644
--- a/requirements-win.txt
+++ b/requirements-win.txt
@@ -95,6 +95,7 @@ pyparsing==2.4.7; python_full_version >= "3.6.0" and python_version >= "3.6"
pyportfolioopt==1.4.1
pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0"
pystan==2.19.1.1
+python-coinmarketcap==0.2
python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.5" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "2.7" and python_full_version < "3.0.0" and python_version < "4" or python_version >= "2.7" and python_version < "4" and python_full_version >= "3.3.0")
pytest==6.2.2; python_version >= "3.6"
pytrends==4.7.3
@@ -111,6 +112,7 @@ sacremoses==0.0.43; python_full_version >= "3.6.0" and python_version >= "3.6"
scikit-learn==0.24.1; python_version >= "3.6"
scipy==1.6.1; python_version >= "3.6"
segtok==1.5.10; python_version >= "3.6"
+selenium==3.141.0
sentencepiece==0.1.91; python_full_version >= "3.6.0" and python_version >= "3.6"
setuptools-git==1.2
six==1.15.0; python_full_version >= "3.6.0" and python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0")
diff --git a/requirements.txt b/requirements.txt
index 29b46fbad43..654cd4398b4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,10 @@
aiohttp==3.7.4.post0; python_version >= "3.6"
-alpaca-trade-api==1.1.0
+alpaca-trade-api==1.2.0
alpha-vantage==2.3.1
ansiwrap==0.8.4; python_version >= "3.6"
appdirs==1.4.4; python_version >= "3.6"
appnope==0.1.2; platform_system == "Darwin" and python_version >= "3.6" and sys_platform == "darwin"
-argon2-cffi==20.1.0; python_version >= "3.5"
+argon2-cffi==20.1.0; python_version >= "3.6"
async-generator==1.10; python_full_version >= "3.6.1" and python_version >= "3.6"
async-timeout==3.0.1; python_full_version >= "3.5.3" and python_version >= "3.6"
attrs==20.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
@@ -19,11 +19,11 @@ chardet==4.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or pyt
click==7.1.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
colorama==0.4.4; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
convertdate==2.3.2; python_version >= "3.5"
-cryptography==3.4.6; python_version >= "3.6"
+cryptography==3.4.7; python_version >= "3.6"
cssselect==1.1.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
cvxpy==1.1.12; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
cycler==0.10.0; python_version >= "3.6"
-cython==0.29.17; python_version >= "2.6" and python_full_version < "3.0.0" and sys_platform == "darwin" or python_full_version >= "3.3.0" and sys_platform == "darwin"
+cython==0.29.17; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "darwin" or python_full_version >= "3.3.0" and python_version >= "3.6" and sys_platform == "darwin"
dataclasses==0.8; python_version >= "3.6" and python_version < "3.7"
datetime==4.3; python_version >= "3.5"
decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.2.0" and python_version >= "3.6")
@@ -31,49 +31,51 @@ defusedxml==0.7.1; python_version >= "3.6" and python_full_version < "3.0.0" or
detecta==0.0.5; python_version >= "3.6"
ecos==2.0.7.post1; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
entrypoints==0.3; python_version >= "3.6"
-finviz==1.3.4
-finvizfinance==0.9.3; python_version >= "3.5"
+finviz==1.4.1
+finvizfinance==0.9.6; python_version >= "3.5"
fredapi==0.4.3
-fundamentalanalysis==0.2.6
+fundamentalanalysis==0.2.7
h5py==2.10.0
hijri-converter==2.1.1; python_version >= "3.6"
holidays==0.10.5.2
idna-ssl==1.1.0; python_version < "3.7" and python_version >= "3.6"
idna==2.10; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version < "3.7" and python_version >= "3.6" and python_full_version >= "3.5.0"
-importlib-metadata==3.7.3; python_version < "3.8" and python_version >= "3.6"
+importlib-metadata==4.0.1; python_version < "3.8" and python_version >= "3.6"
inflection==0.5.1; python_version >= "3.5"
-ipykernel==5.5.0; python_version >= "3.6"
+ipykernel==5.5.3; python_version >= "3.6"
ipython-genutils==0.2.0; python_full_version >= "3.6.1" and python_version >= "3.6"
ipython==7.16.1; python_version >= "3.6"
ipywidgets==7.6.3
iso8601==0.1.14
jedi==0.18.0; python_version >= "3.6"
jinja2==2.11.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+joblib==1.0.1; python_version >= "3.6"
jsonschema==3.2.0; python_version >= "3.6"
-jupyter-client==6.1.12; python_full_version >= "3.6.1" and python_version >= "3.6"
-jupyter-console==6.3.0; python_version >= "3.6"
+jupyter-client==6.2.0; python_full_version >= "3.6.1" and python_version >= "3.6"
+jupyter-console==6.4.0; python_version >= "3.6"
jupyter-core==4.7.1; python_full_version >= "3.6.1" and python_version >= "3.6"
jupyter==1.0.0
jupyterlab-pygments==0.1.2; python_version >= "3.6"
jupyterlab-widgets==1.0.0; python_version >= "3.6"
kiwisolver==1.3.1; python_version >= "3.6"
korean-lunar-calendar==0.2.1
-lxml==4.6.2; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
+lxml==4.6.3; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
markupsafe==1.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
matplotlib==3.3.4; python_version >= "3.6"
mistune==0.8.4; python_version >= "3.6"
more-itertools==8.7.0; python_version >= "3.5"
-mplfinance==0.12.7a10
+mplfinance==0.12.7a12
msgpack==1.0.2
multidict==5.1.0; python_version >= "3.6"
multitasking==0.0.9
mypy-extensions==0.4.3; python_version >= "3.6"
nbclient==0.5.3; python_full_version >= "3.6.1" and python_version >= "3.6"
nbconvert==6.0.7; python_version >= "3.6"
-nbformat==5.1.2; python_full_version >= "3.6.1" and python_version >= "3.6"
+nbformat==5.1.3; python_full_version >= "3.6.1" and python_version >= "3.6"
nest-asyncio==1.5.1; python_full_version >= "3.6.1" and python_version >= "3.6"
-notebook==6.2.0; python_version >= "3.5"
+notebook==6.3.0; python_version >= "3.6"
numpy==1.19.5; python_version >= "3.6"
+oandapyv20==0.6.3
oauthlib==3.1.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
osqp==0.6.2.post0; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
@@ -81,22 +83,24 @@ pandas-ta==0.2.45b
pandas==1.1.5; python_full_version >= "3.6.1"
pandocfilters==1.4.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
papermill==2.3.3; python_version >= "3.6"
-parso==0.8.1; python_version >= "3.6"
+parso==0.8.2; python_version >= "3.6"
pathspec==0.8.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
+patsy==0.5.1; python_version >= "3.6"
pexpect==4.8.0; sys_platform != "win32" and python_version >= "3.6"
pickleshare==0.7.5; python_version >= "3.6"
pillow==8.2.0; python_version >= "3.6"
plotly==4.14.3
+pmdarima==1.8.0; python_version >= "3.6"
praw==7.2.0; python_version >= "3.6" and python_version < "4.0"
prawcore==2.0.0; python_version >= "3.6" and python_version < "4.0"
prettytable==2.1.0; python_version >= "3.6"
-prometheus-client==0.9.0; python_version >= "3.5"
-prompt-toolkit==3.0.17; python_full_version >= "3.6.1"
+prometheus-client==0.10.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+prompt-toolkit==3.0.18; python_full_version >= "3.6.1"
psaw==0.0.12; python_version >= "3"
ptyprocess==0.7.0; os_name != "nt" and python_version >= "3.6" and sys_platform != "win32"
py==1.10.0; python_version >= "3.6" and python_full_version < "3.0.0" and implementation_name == "pypy" or implementation_name == "pypy" and python_version >= "3.6" and python_full_version >= "3.4.0"
pyally==1.1.2
-pycoingecko==1.4.0
+pycoingecko==1.4.1
pycparser==2.20; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
pygments==2.8.1; python_version >= "3.6"
pymeeus==0.5.11; python_version >= "3.5"
@@ -107,8 +111,9 @@ pyparsing==2.4.7; python_version >= "3.6" and python_full_version < "3.0.0" or p
pyportfolioopt==1.4.1; python_full_version >= "3.6.1" and python_full_version < "4.0.0"
pyrsistent==0.14.11
pysocks==1.7.1; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0"
+python-coinmarketcap==0.2
python-dateutil==2.8.1; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0")
-python-dotenv==0.15.0; python_version >= "3"
+python-dotenv==0.17.0; python_version >= "3"
pytrends==4.7.3
pytz==2021.1; python_full_version >= "3.6.1" and python_version >= "3.5"
pywin32==300; sys_platform == "win32" and python_version >= "3.6"
@@ -119,41 +124,47 @@ qdldl==0.1.5.post0; python_full_version >= "3.6.1" and python_full_version < "4.
qtconsole==5.0.3; python_version >= "3.6"
qtpy==1.9.0; python_version >= "3.6"
quandl==3.6.1; python_version >= "3.5"
-rapidfuzz==1.3.0; python_version >= "3.5"
+rapidfuzz==1.4.1; python_version >= "3.5"
regex==2020.11.13
requests-oauthlib==1.3.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0"
requests==2.25.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
retrying==1.3.3
robin-stocks==2.0.3; python_version >= "3"
+scikit-learn==0.24.1; python_version >= "3.6"
scipy==1.5.4; python_version >= "3.6"
screeninfo==0.6.7
-scs==2.1.2; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
+scs==2.1.3; python_full_version >= "3.6.1" and python_full_version < "4.0.0" and python_version >= "3.5"
seaborn==0.11.1; python_version >= "3.6"
-send2trash==1.5.0; python_version >= "3.5"
-six==1.15.0; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") and (python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.5")
+selenium==3.141.0
+send2trash==1.5.0; python_version >= "3.6"
+six==1.15.0; python_full_version >= "3.6.1" and python_version >= "3.6" and (python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0") and (python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6")
soupsieve==2.2.1; python_version >= "3.6"
+statsmodels==0.12.2; python_version >= "3.6"
+tabulate==0.8.9
tenacity==7.0.0; python_version >= "3.6"
termcolor==1.1.0
-terminado==0.9.3; python_version >= "3.6"
+terminado==0.9.4; python_version >= "3.6"
testpath==0.4.4; python_version >= "3.6"
textwrap3==0.9.2; python_version >= "3.6"
+threadpoolctl==2.1.0; python_version >= "3.6"
timeseriescrossvalidation @ git+https://github.com/DidierRLopes/TimeSeriesCrossValidation.git@master
toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6"
tornado==6.1; python_full_version >= "3.6.1" and python_version >= "3.6"
-tqdm==4.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
+tqdm==4.60.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6"
tradingview-ta==3.2.3; python_version >= "3.5"
traitlets==4.3.3; python_full_version >= "3.6.1" and python_version >= "3.6"
-typed-ast==1.4.2; python_version >= "3.6"
+typed-ast==1.4.3; python_version >= "3.6"
typing-extensions==3.7.4.3; python_version < "3.8" and python_version >= "3.6"
update-checker==0.18.0; python_version >= "3.6" and python_version < "4.0"
-urllib3==1.26.4; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4"
+urllib3==1.26.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6"
user-agent==0.1.9
+valinvest==0.0.2; python_version >= "3.6"
wcwidth==0.2.5; python_version >= "3.6" and python_full_version >= "3.6.1"
webencodings==0.5.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6"
websocket-client==0.58.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0"
websockets==8.1; python_full_version >= "3.6.1"
widgetsnbextension==3.5.1
yarl==1.6.3; python_version >= "3.6"
-yfinance==0.1.55
+yfinance==0.1.59
zipp==3.4.1; python_version < "3.8" and python_version >= "3.6"
-zope.interface==5.3.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
+zope.interface==5.4.0; python_version >= "3.5" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.5"
diff --git a/terminal.py b/terminal.py
index f246ebd00bb..368f078bcc3 100644
--- a/terminal.py
+++ b/terminal.py
@@ -16,7 +16,7 @@ from gamestonk_terminal import thought_of_the_day as thought
from gamestonk_terminal import res_menu as rm
from gamestonk_terminal.discovery import disc_controller
from gamestonk_terminal.due_diligence import dd_controller
-from gamestonk_terminal.fundamental_analysis import fa_menu as fam
+from gamestonk_terminal.fundamental_analysis import fa_controller
from gamestonk_terminal.helper_funcs import b_is_stock_market_open, get_flair
from gamestonk_terminal.main_helper import clear, export, load, print_help, view, candle
from gamestonk_terminal.menu import session
@@ -35,13 +35,7 @@ from gamestonk_terminal.portfolio_optimization import po_controller
from gamestonk_terminal.forex import fx_controller
-# import warnings
-# warnings.simplefilter("always")
-
-
-# pylint: disable=too-many-branches
-
-
+# pylint: disable=too-many-statements,too-many-branches
def main():
"""
Gamestonk Terminal is an awesome stock market terminal that has been developed for fun,
@@ -98,6 +92,10 @@ def main():
menu_parser.add_argument("opt", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
+ if os.name == "nt":
+ sys.stdin.reconfigure(encoding="utf-8")
+ sys.stdout.reconfigure(encoding="utf-8")
+
# Print first welcome message and help
print("\nWelcome to Gamestonk Terminal 🚀\n")
should_print_help = True
@@ -118,6 +116,10 @@ def main():
print_help(s_ticker, s_start, s_interval, b_is_stock_market_open())
should_print_help = False
+ if gtff.ENABLE_QUICK_EXIT:
+ print("Quick exit enabled")
+ break
+
# Get input command from stdin or user
if not parsed_stdin and len(sys.argv) > 1:
as_input = " ".join(sys.argv[1:])
@@ -199,29 +201,54 @@ def main():
b_quit = mill.papermill_menu()
elif ns_known_args.opt == "ba":
- b_quit = ba_controller.menu(s_ticker, s_start)
+ b_quit = ba_controller.menu(
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker, s_start
+ )
elif ns_known_args.opt == "res":
- b_quit = rm.res_menu(s_ticker, s_start, s_interval)
+ b_quit = rm.res_menu(
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "ca":
b_quit = ca_controller.menu(df_stock, s_ticker, s_start, s_interval)
elif ns_known_args.opt == "fa":
- b_quit = fam.fa_menu(s_ticker, s_start, s_interval)
+ b_quit = fa_controller.menu(
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "fx":
b_quit = fx_controller.menu()
elif ns_known_args.opt == "ta":
- b_quit = ta_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = ta_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "dd":
- b_quit = dd_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = dd_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "eda":
if s_interval == "1440min":
- b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = eda_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
else:
df_stock = yf.download(s_ticker, start=s_start, progress=False)
df_stock = df_stock.rename(
@@ -237,7 +264,12 @@ def main():
df_stock.index.name = "date"
s_interval = "1440min"
- b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = eda_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "op":
b_quit = op_controller.menu(
@@ -279,7 +311,12 @@ def main():
continue
if s_interval == "1440min":
- b_quit = pred_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = pred_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
# If stock data is intradaily, we need to get data again as prediction
# techniques work on daily adjusted data. By default we load data from
# Alpha Vantage because the historical data loaded gives a larger
@@ -297,7 +334,10 @@ def main():
df_stock_pred = df_stock_pred.sort_index(ascending=True)
df_stock_pred = df_stock_pred[s_start:]
b_quit = pred_controller.menu(
- df_stock_pred, s_ticker, s_start, s_interval="1440min"
+ df_stock_pred,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ interval="1440min",
)
except Exception as e:
print(e)
@@ -305,7 +345,12 @@ def main():
return
elif ns_known_args.opt == "ra":
- b_quit = ra_controller.menu(df_stock, s_ticker, s_start, s_interval)
+ b_quit = ra_controller.menu(
+ df_stock,
+ s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
+ s_start,
+ s_interval,
+ )
elif ns_known_args.opt == "scr":
b_quit = screener_controller.menu()
@@ -316,9 +361,9 @@ def main():
if b_quit:
break
- else:
- if not main_cmd:
- should_print_help = True
+
+ if not main_cmd:
+ should_print_help = True
print(
"Hope you enjoyed the terminal. Remember that stonks only go up. Diamond hands.\n"
diff --git a/tests/data/fa_market_watch_api.yaml b/tests/data/fa_market_watch_model.yaml
similarity index 100%
rename from tests/data/fa_market_watch_api.yaml
rename to tests/data/fa_market_watch_model.yaml
diff --git a/tests/test_coingecko_crypto.py b/tests/test_coingecko_crypto.py
index 5f20e2e04d1..e0eed2eed55 100644
--- a/tests/test_coingecko_crypto.py
+++ b/tests/test_coingecko_crypto.py
@@ -1,14 +1,14 @@
from unittest import mock, TestCase
import json
from pycoingecko import CoinGeckoAPI
-from gamestonk_terminal.cryptocurrency.coin_api import load
+from gamestonk_terminal.cryptocurrency.pycoingecko_view import load
# pylint: disable=unused-import
class TestCoinGeckoAPI(TestCase):
@mock.patch(
- "gamestonk_terminal.cryptocurrency.coin_api.CoinGeckoAPI.get_coin_market_chart_by_id"
+ "gamestonk_terminal.cryptocurrency.pycoingecko_view.CoinGeckoAPI.get_coin_market_chart_by_id"
)
def test_coin_api_load(self, mock_load):
"""
diff --git a/tests/test_fa_business_insider_api.py b/tests/test_fa_business_insider_view.py
similarity index 69%
rename from tests/test_fa_business_insider_api.py
rename to tests/test_fa_business_insider_view.py
index 35d7c23205c..b9d35af0af9 100644
--- a/tests/test_fa_business_insider_api.py
+++ b/tests/test_fa_business_insider_view.py
@@ -1,7 +1,7 @@
""" fundamental_analysis/business_insider_api.py tests """
import unittest
-from gamestonk_terminal.fundamental_analysis.business_insider_api import management
+from gamestonk_terminal.fundamental_analysis.business_insider_view import management
class TestFaBusinessInsiderApi(unittest.TestCase):
diff --git a/tests/test_fa_market_watch_api_unit.py b/tests/test_fa_market_watch_model.py
similarity index 86%
rename from tests/test_fa_market_watch_api_unit.py
rename to tests/test_fa_market_watch_model.py
index b48d03445d5..4e671236f00 100644
--- a/tests/test_fa_market_watch_api_unit.py
+++ b/tests/test_fa_market_watch_model.py
@@ -8,7 +8,7 @@ from gamestonk_terminal.test_helper import ( # noqa: F401
pytest_generate_tests,
)
-from gamestonk_terminal.fundamental_analysis.market_watch_api import (
+from gamestonk_terminal.fundamental_analysis.market_watch_model import (
prepare_df_financials,
)
@@ -16,10 +16,10 @@ assertions = unittest.TestCase("__init__")
class TestFaMarketWatchApiUnit:
- @mock.patch("gamestonk_terminal.fundamental_analysis.market_watch_api.requests")
+ @mock.patch("gamestonk_terminal.fundamental_analysis.market_watch_model.requests")
@parameterize_from_file(
"test_prepare_df_financials",
- "../tests/data/fa_market_watch_api.yaml",
+ "../tests/data/fa_market_watch_model.yaml",
)
# pylint: disable=too-many-arguments
def test_prepare_df_financials(
diff --git a/tests/test_fa_market_watch_api.py b/tests/test_fa_market_watch_view.py
similarity index 69%
rename from tests/test_fa_market_watch_api.py
rename to tests/test_fa_market_watch_view.py
index da8057c5d38..9ebe411fdb3 100644
--- a/tests/test_fa_market_watch_api.py
+++ b/tests/test_fa_market_watch_view.py
@@ -1,7 +1,7 @@
""" fundamental_analysis/market_watch_api.py tests """
import unittest
-from gamestonk_terminal.fundamental_analysis.market_watch_api import income
+from gamestonk_terminal.fundamental_analysis.market_watch_view import income
class TestFaMarketWatchApi(unittest.TestCase):
diff --git a/tests/test_fa_yahoo_finance_api.py b/tests/test_fa_yahoo_finance_view.py
similarity index 84%
rename from tests/test_fa_yahoo_finance_api.py
rename to tests/test_fa_yahoo_finance_view.py
index 211c2f006d4..fb068647595 100644
--- a/tests/test_fa_yahoo_finance_api.py
+++ b/tests/test_fa_yahoo_finance_view.py
@@ -2,7 +2,7 @@
import unittest
# pylint: disable=unused-import
-from gamestonk_terminal.fundamental_analysis.yahoo_finance_api import ( # noqa: F401
+from gamestonk_terminal.fundamental_analysis.yahoo_finance_view import ( # noqa: F401
info,
sustainability,
calendar_earnings,