Merge branch 'main' into forex

This commit is contained in:
DJ
2021-04-23 15:05:36 -06:00
committed by GitHub
80 changed files with 3307 additions and 1334 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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**

View File

@@ -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
 

View File

@@ -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:

View File

@@ -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()

View File

@@ -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)

View File

@@ -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:

View File

@@ -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)

View File

@@ -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",

View File

@@ -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(
[

View File

@@ -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"

View File

@@ -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 <a name="load"></a>
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 <a name="view"></a>
Plot the loaded crypto data.
````
usage: view
````
After loading the above 1 day dogecoin/eur. Running view plots the data:
![doge](https://user-images.githubusercontent.com/18151143/112690617-7832f500-8e52-11eb-84c4-253ab222a918.png)
Plot the loaded crypto data.
![crypto_view](https://user-images.githubusercontent.com/25267873/115787452-20889a80-a3ba-11eb-9216-f7fd1ffc98cf.png)
## top <a name="top"></a>
````
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).
<img width="990" alt="crypto" src="https://user-images.githubusercontent.com/25267873/115787544-4746d100-a3ba-11eb-9433-b7cb9142404a.png">

View File

@@ -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("")

View File

@@ -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()

View File

@@ -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 <a name="map"></a>
@@ -265,3 +267,18 @@ Top ratings updates. [Source: MarketBeat]
<img width="963" alt="ratings" src="https://user-images.githubusercontent.com/25267873/115095983-4544c400-9f1b-11eb-8869-8ec8a0f8eae0.png">
## darkpool <a name="darkpool"></a>
```
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.
![darkpool](https://user-images.githubusercontent.com/25267873/115323195-8d642080-a17f-11eb-9ef8-d456ce769ab7.png)

View File

@@ -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"""

View File

@@ -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

View File

@@ -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

0
gamestonk_terminal/discovery/marketbeat_model.py Executable file → Normal file
View File

View File

@@ -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

4
gamestonk_terminal/discovery/seeking_alpha_model.py Executable file → Normal file
View File

@@ -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:

View File

@@ -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,

View File

@@ -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 <a name="news"></a>
@@ -157,3 +161,26 @@ Sean Seah warnings. Check: Consistent historical earnings per share; Consistentl
* -d : print insights into warnings calculation. Default False.
<img width="927" alt="warnings" src="https://user-images.githubusercontent.com/25267873/108609497-2ec03780-73c6-11eb-8577-d5da80dae213.png">
## dp <a name="dp"></a>
```text
usage: dp
```
Display barchart of dark pool (ATS) and OTC (Non ATS) data
![dp](https://user-images.githubusercontent.com/25267873/115130908-7987b580-9feb-11eb-8bca-1999174178d0.png)
## ftd <a name="ftd"></a>
```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 <https://www.sec.gov/data/foiadocsfailsdatahtm>. [Source: SEC]
* -n : number of latest fails-to-deliver being printed. Default 20.
![ftd](https://user-images.githubusercontent.com/25267873/115201750-93a9bc80-a0ed-11eb-8f13-68508749259e.png)

View File

@@ -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

View File

@@ -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

View File

@@ -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")

View File

@@ -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"))

View File

@@ -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.

View File

@@ -101,6 +101,7 @@ class ForexController:
print(
" edacusum detects abrupt changes using cumulative sum algorithm"
)
print("")
def switch(self, an_input: str):

View File

@@ -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("")

View File

@@ -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 <a name="score"></a>
```text
usage: score
```
Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: Financial Modeling Prep]

View File

@@ -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

View File

@@ -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[

View File

@@ -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"
)

View File

@@ -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

View File

@@ -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!")

View File

@@ -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

View File

@@ -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()

View File

@@ -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"]
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <a name="get"></a>
## exp <a name="exp"></a>
```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.
<img width="955" alt="exp" src="https://user-images.githubusercontent.com/25267873/115161875-f6706900-a097-11eb-8566-bb7b408856a5.png">
## voi <a name="voi"></a>
```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.
![voinio](https://user-images.githubusercontent.com/25267873/115161878-f7a19600-a097-11eb-889b-e9cc945f174d.png)
## vcalls <a name="vcalls"></a>
```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.
![vcalls](https://user-images.githubusercontent.com/25267873/115161874-f5d7d280-a097-11eb-93e2-3a2b20292f09.png)
## vputs <a name="vputs"></a>
```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.
![vputs](https://user-images.githubusercontent.com/25267873/115161873-f40e0f00-a097-11eb-8334-3d4f14b56766.png)
* -e, --expiry : expiration date.
## chains <a name="chains"></a>
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.
<img width="948" alt="chains" src="https://user-images.githubusercontent.com/25267873/115161876-f708ff80-a097-11eb-8073-195979862a45.png">
## info <a name="info"></a>
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:
![im](https://user-images.githubusercontent.com/18151143/115068041-b191da00-9ebf-11eb-941e-4e255787ab94.png)
* -d/--driver : One of {chrome, firefox}. This indicates which driver you have installed.
<img width="989" alt="opinfo" src="https://user-images.githubusercontent.com/25267873/115787028-80cb0c80-a3b9-11eb-97a4-ca208aed3be8.png">

View File

@@ -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)

View File

@@ -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. """

View File

@@ -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("")

View File

@@ -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"])

View File

@@ -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)

View File

@@ -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):

View File

@@ -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

View File

@@ -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(

View File

@@ -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'"

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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]

View File

@@ -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(

View File

@@ -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"""

View File

@@ -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,
)

4
notebooks/templates/due_diligence.ipynb Normal file → Executable file
View File

@@ -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
}
}

2
notebooks/templates/econ_data.ipynb Normal file → Executable file
View File

@@ -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)"
]
},
{

797
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -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"

View File

@@ -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"

View File

@@ -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")

View File

@@ -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")

View File

@@ -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"

View File

@@ -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"

View File

@@ -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):
"""

View File

@@ -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):

View File

@@ -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(

View File

@@ -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):

View File

@@ -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,