mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-11 20:01:16 +00:00
Merge branch 'main' into forex
This commit is contained in:
6
.github/workflows/Mac.yml
vendored
6
.github/workflows/Mac.yml
vendored
@@ -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
|
||||
|
||||
38
.github/workflows/test.yml
vendored
38
.github/workflows/test.yml
vendored
@@ -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
|
||||
|
||||
5
.github/workflows/windows.yml
vendored
5
.github/workflows/windows.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
10
README.md
10
README.md
@@ -260,6 +260,8 @@ These are the ones where a key is necessary:
|
||||
* Tradier: https://developer.tradier.com/getting_started
|
||||
* Oanda API: https://developer.oanda.com
|
||||
|
||||
When these are obtained, don't forget to update [config_terminal.py](/gamestonk_terminal/config_terminal.py).
|
||||
|
||||
Alternatively, you can also set them to the following environment variables: GT_API_KEY_ALPHAVANTAGE, GT_API_KEY_FINANCIALMODELINGPREP, GT_API_KEY_QUANDL, GT_API_REDDIT_CLIENT_ID, GT_API_REDDIT_CLIENT_SECRET, GT_API_REDDIT_USERNAME, GT_API_REDDIT_USER_AGENT, GT_API_REDDIT_PASSWORD, GT_API_TWITTER_KEY, GT_API_TWITTER_SECRET_KEY, GT_API_TWITTER_BEARER_TOKEN, GT_API_POLYGON_KEY, GT_FRED_API_KEY, GT_API_NEWS_TOKEN, GT_OANDA_TOKEN, GT_OANDA_ACCOUNT, GT_TRADIER_TOKEN.
|
||||
|
||||
Example:
|
||||
@@ -267,6 +269,11 @@ Example:
|
||||
export GT_API_REDDIT_USERNAME=SexyYear
|
||||
```
|
||||
|
||||
Environment variables can also be set in a `.env` file at the top of the repo. This file is ignored by git so your API keys will stay secret. The above example stored in `.env` would be:
|
||||
```
|
||||
GT_API_REDDIT_USERNAME=SexyYear
|
||||
```
|
||||
|
||||
Note that it is not necessary to have a valid Alpha Vantage key to get daily OHLC values.
|
||||
|
||||
### Usage
|
||||
@@ -359,6 +366,9 @@ Distributed under the MIT License. See [LICENSE](https://github.com/DidierRLopes
|
||||
[Artem Veremy](https://www.linkedin.com/in/veremey/) - artem@veremey.net
|
||||
|
||||
[James Maslek](https://www.linkedin.com/in/james-maslek-b6810186/) - jmaslek11@gmail.com
|
||||
|
||||
Feel free to share loss porn, memes or any questions at https://discord.gg/Up2QGbMKHY
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
* [VICE article](https://www.vice.com/en/article/qjp9vp/gamestonk-terminal-is-a-diy-meme-stock-version-of-bloomberg-terminal)
|
||||
|
||||
20
ROADMAP.md
20
ROADMAP.md
@@ -20,6 +20,7 @@
|
||||
* [Credit Analysis](#Credit-Analysis)
|
||||
* [Cryptocurrencies](#Cryptocurrencies)
|
||||
* [Screener](#Screener)
|
||||
* [Forex](#Forex)
|
||||
|
||||
## Additional
|
||||
|
||||
@@ -36,6 +37,8 @@
|
||||
* [x] Analyse sectors/industry performance, overview and valuation from Finviz (@didier) - [PR #315](https://github.com/DidierRLopes/GamestonkTerminal/pull/315)
|
||||
* [x] Add latest and trending news commands (@hinxx) - [PR #347](https://github.com/DidierRLopes/GamestonkTerminal/pull/347)
|
||||
* [x] Add top ratings updates (@hinxx) - [PR #357](https://github.com/DidierRLopes/GamestonkTerminal/pull/357)
|
||||
* [x] Add dark pool (ATS) data of tickers with growing trades activity (@didier) - [PR #372](https://github.com/DidierRLopes/GamestonkTerminal/pull/372)
|
||||
|
||||
|
||||
**NEXT**
|
||||
|
||||
@@ -61,6 +64,7 @@
|
||||
|
||||
## Fundamental Analysis
|
||||
* [x] Rearrange FA menu to have AV and FMP as submenus (@didier) - [PR #166](https://github.com/DidierRLopes/GamestonkTerminal/pull/166)
|
||||
* [x] Add Fundamental Analysis score (@didier) - [PR #383](https://github.com/DidierRLopes/GamestonkTerminal/pull/383)
|
||||
|
||||
**NEXT**
|
||||
* [ ] Add Treasury Yield Curve data (@aia) - [PR #281](https://github.com/DidierRLopes/GamestonkTerminal/pull/281)
|
||||
@@ -79,6 +83,8 @@
|
||||
---
|
||||
|
||||
## Due Diligence
|
||||
* [x] Add dark pools (ATS) vs Non-ATS data over time (@didier) - [PR #363](https://github.com/DidierRLopes/GamestonkTerminal/pull/363)
|
||||
* [x] Add failure to deliver command (@hinxx) - [PR #366](#https://github.com/DidierRLopes/GamestonkTerminal/pull/366)
|
||||
|
||||
**NEXT**
|
||||
|
||||
@@ -147,7 +153,7 @@
|
||||
* [ ] Refactoring
|
||||
* [ ] Summaries / tear sheets (@jmaslek)
|
||||
|
||||
___
|
||||
___
|
||||
|
||||
## Portfolio Optimization
|
||||
* [x] Basic Optimization through PyPortFolioOpt(@jmaslek) - [PR #329](https://github.com/DidierRLopes/GamestonkTerminal/pull/329)
|
||||
@@ -169,6 +175,7 @@ ___
|
||||
## Options
|
||||
* [x] Add Volume graph (@lolrenx) - [PR #209](https://github.com/DidierRLopes/GamestonkTerminal/pull/209)
|
||||
* [x] Add Open Interest graph (@lolrenx) - [PR #209](https://github.com/DidierRLopes/GamestonkTerminal/pull/209)
|
||||
* [x] Add options information data (IV rank, etc) (@jmaslek) - [PR #375](https://github.com/DidierRLopes/GamestonkTerminal/pull/375)
|
||||
|
||||
**NEXT**
|
||||
* [ ] Add max pain graph (@lolrenx)
|
||||
@@ -185,11 +192,13 @@ ___
|
||||
|
||||
## Cryptocurrencies
|
||||
* [x] Add Coingecko (@jmaslek) - [PR #283](#https://github.com/DidierRLopes/GamestonkTerminal/pull/283)
|
||||
* [x] view top coins from coinmarketcap (@jmaslek) - [PR #378](https://github.com/DidierRLopes/GamestonkTerminal/pull/378)
|
||||
|
||||
**NEXT**
|
||||
* [ ] Add [Coinpaprika](https://coinpaprika.com/api/)
|
||||
* [ ] Add crypto charts
|
||||
|
||||
* [ ] Add binance
|
||||
* [ ] Add top altcoin lists
|
||||
---
|
||||
|
||||
## Screener
|
||||
@@ -203,6 +212,13 @@ ___
|
||||
|
||||
---
|
||||
|
||||
## Forex
|
||||
* [x] Add entire forex menu through Oanda (@alokan) - [PR #360](https://github.com/DidierRLopes/GamestonkTerminal/pull/360)
|
||||
|
||||
**NEXT**
|
||||
|
||||
---
|
||||
|
||||
## Backend
|
||||
|
||||
**NEXT**
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
0
gamestonk_terminal/comparison_analysis/__init__.py
Normal file
0
gamestonk_terminal/comparison_analysis/__init__.py
Normal 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:
|
||||
|
||||
@@ -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)
|
||||
@@ -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",
|
||||
@@ -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(
|
||||
[
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||
Plot the loaded crypto data.
|
||||
|
||||

|
||||
|
||||
|
||||
## 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">
|
||||
|
||||
|
||||
100
gamestonk_terminal/cryptocurrency/coinmarketcap_view.py
Normal file
100
gamestonk_terminal/cryptocurrency/coinmarketcap_view.py
Normal 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("")
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
265
gamestonk_terminal/discovery/finra_ats_view.py
Normal file
265
gamestonk_terminal/discovery/finra_ats_view.py
Normal 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
|
||||
@@ -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
0
gamestonk_terminal/discovery/marketbeat_model.py
Executable file → Normal 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
4
gamestonk_terminal/discovery/seeking_alpha_model.py
Executable file → Normal 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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||

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

|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
305
gamestonk_terminal/due_diligence/finra_view.py
Normal file
305
gamestonk_terminal/due_diligence/finra_view.py
Normal 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
|
||||
108
gamestonk_terminal/due_diligence/sec_view.py
Normal file
108
gamestonk_terminal/due_diligence/sec_view.py
Normal 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")
|
||||
@@ -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"))
|
||||
|
||||
@@ -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.
|
||||
@@ -101,6 +101,7 @@ class ForexController:
|
||||
print(
|
||||
" edacusum detects abrupt changes using cumulative sum algorithm"
|
||||
)
|
||||
|
||||
print("")
|
||||
|
||||
def switch(self, an_input: str):
|
||||
|
||||
@@ -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("")
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
@@ -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[
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
262
gamestonk_terminal/fundamental_analysis/fa_controller.py
Normal file
262
gamestonk_terminal/fundamental_analysis/fa_controller.py
Normal 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
|
||||
@@ -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!")
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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"]
|
||||
)
|
||||
111
gamestonk_terminal/fundamental_analysis/market_watch_model.py
Normal file
111
gamestonk_terminal/fundamental_analysis/market_watch_model.py
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||

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

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

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

|
||||
* -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">
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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. """
|
||||
|
||||
104
gamestonk_terminal/options/op_scrape_view.py
Normal file
104
gamestonk_terminal/options/op_scrape_view.py
Normal 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("")
|
||||
@@ -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"])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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
4
notebooks/templates/due_diligence.ipynb
Normal file → Executable 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
2
notebooks/templates/econ_data.ipynb
Normal file → Executable 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
797
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
87
terminal.py
87
terminal.py
@@ -16,7 +16,7 @@ from gamestonk_terminal import thought_of_the_day as thought
|
||||
from gamestonk_terminal import res_menu as rm
|
||||
from gamestonk_terminal.discovery import disc_controller
|
||||
from gamestonk_terminal.due_diligence import dd_controller
|
||||
from gamestonk_terminal.fundamental_analysis import fa_menu as fam
|
||||
from gamestonk_terminal.fundamental_analysis import fa_controller
|
||||
from gamestonk_terminal.helper_funcs import b_is_stock_market_open, get_flair
|
||||
from gamestonk_terminal.main_helper import clear, export, load, print_help, view, candle
|
||||
from gamestonk_terminal.menu import session
|
||||
@@ -35,13 +35,7 @@ from gamestonk_terminal.portfolio_optimization import po_controller
|
||||
from gamestonk_terminal.forex import fx_controller
|
||||
|
||||
|
||||
# import warnings
|
||||
# warnings.simplefilter("always")
|
||||
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
|
||||
# pylint: disable=too-many-statements,too-many-branches
|
||||
def main():
|
||||
"""
|
||||
Gamestonk Terminal is an awesome stock market terminal that has been developed for fun,
|
||||
@@ -98,6 +92,10 @@ def main():
|
||||
menu_parser.add_argument("opt", choices=choices)
|
||||
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
|
||||
|
||||
if os.name == "nt":
|
||||
sys.stdin.reconfigure(encoding="utf-8")
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
# Print first welcome message and help
|
||||
print("\nWelcome to Gamestonk Terminal 🚀\n")
|
||||
should_print_help = True
|
||||
@@ -118,6 +116,10 @@ def main():
|
||||
print_help(s_ticker, s_start, s_interval, b_is_stock_market_open())
|
||||
should_print_help = False
|
||||
|
||||
if gtff.ENABLE_QUICK_EXIT:
|
||||
print("Quick exit enabled")
|
||||
break
|
||||
|
||||
# Get input command from stdin or user
|
||||
if not parsed_stdin and len(sys.argv) > 1:
|
||||
as_input = " ".join(sys.argv[1:])
|
||||
@@ -199,29 +201,54 @@ def main():
|
||||
b_quit = mill.papermill_menu()
|
||||
|
||||
elif ns_known_args.opt == "ba":
|
||||
b_quit = ba_controller.menu(s_ticker, s_start)
|
||||
b_quit = ba_controller.menu(
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker, s_start
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "res":
|
||||
b_quit = rm.res_menu(s_ticker, s_start, s_interval)
|
||||
b_quit = rm.res_menu(
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "ca":
|
||||
b_quit = ca_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
|
||||
elif ns_known_args.opt == "fa":
|
||||
b_quit = fam.fa_menu(s_ticker, s_start, s_interval)
|
||||
b_quit = fa_controller.menu(
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "fx":
|
||||
b_quit = fx_controller.menu()
|
||||
|
||||
elif ns_known_args.opt == "ta":
|
||||
b_quit = ta_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = ta_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "dd":
|
||||
b_quit = dd_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = dd_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "eda":
|
||||
if s_interval == "1440min":
|
||||
b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = eda_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
else:
|
||||
df_stock = yf.download(s_ticker, start=s_start, progress=False)
|
||||
df_stock = df_stock.rename(
|
||||
@@ -237,7 +264,12 @@ def main():
|
||||
df_stock.index.name = "date"
|
||||
s_interval = "1440min"
|
||||
|
||||
b_quit = eda_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = eda_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "op":
|
||||
b_quit = op_controller.menu(
|
||||
@@ -279,7 +311,12 @@ def main():
|
||||
continue
|
||||
|
||||
if s_interval == "1440min":
|
||||
b_quit = pred_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = pred_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
# If stock data is intradaily, we need to get data again as prediction
|
||||
# techniques work on daily adjusted data. By default we load data from
|
||||
# Alpha Vantage because the historical data loaded gives a larger
|
||||
@@ -297,7 +334,10 @@ def main():
|
||||
df_stock_pred = df_stock_pred.sort_index(ascending=True)
|
||||
df_stock_pred = df_stock_pred[s_start:]
|
||||
b_quit = pred_controller.menu(
|
||||
df_stock_pred, s_ticker, s_start, s_interval="1440min"
|
||||
df_stock_pred,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
interval="1440min",
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -305,7 +345,12 @@ def main():
|
||||
return
|
||||
|
||||
elif ns_known_args.opt == "ra":
|
||||
b_quit = ra_controller.menu(df_stock, s_ticker, s_start, s_interval)
|
||||
b_quit = ra_controller.menu(
|
||||
df_stock,
|
||||
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
|
||||
s_start,
|
||||
s_interval,
|
||||
)
|
||||
|
||||
elif ns_known_args.opt == "scr":
|
||||
b_quit = screener_controller.menu()
|
||||
@@ -316,9 +361,9 @@ def main():
|
||||
|
||||
if b_quit:
|
||||
break
|
||||
else:
|
||||
if not main_cmd:
|
||||
should_print_help = True
|
||||
|
||||
if not main_cmd:
|
||||
should_print_help = True
|
||||
|
||||
print(
|
||||
"Hope you enjoyed the terminal. Remember that stonks only go up. Diamond hands.\n"
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
@@ -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(
|
||||
@@ -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):
|
||||
@@ -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,
|
||||
Reference in New Issue
Block a user