diff --git a/README.md b/README.md index ac56f9069c9..f692ff61ab4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@

- Logo + Logo

Gamestonk Terminal 🚀

@@ -136,13 +136,15 @@ cd GamestonkTerminal/ conda install poetry ``` -7.5. If installing python 3.8 +7.1. If installing python 3.8 ``` conda deactivate conda activate gst ``` *The `conda deactivate` -> `conda activate` in the middle is on purpose, this is sometimes required to avoid issues with poetry* +7.2. If on Windows, install/update Microsoft C++ Build Tools from here: https://visualstudio.microsoft.com/visual-cpp-build-tools/ + 8. Install poetry dependencies ``` poetry install @@ -331,6 +333,8 @@ Distributed under the MIT License. See [LICENSE](https://github.com/DidierRLopes "A few things I am not. I am not a cat. I am not an institutional investor, nor am I a hedge fund. I do not have clients and I do not provide personalized investment advice for fees or commissions." DFV +Trading in financial instruments involves high risks including the risk of losing some, or all, of your investment amount, and may not be suitable for all investors. Before deciding to trade in financial instrument you should be fully informed of the risks and costs associated with trading the financial markets, carefully consider your investment objectives, level of experience, and risk appetite, and seek professional advice where needed. The data contained in GST is not necessarily accurate. GST and any provider of the data contained in this website will not accept liability for any loss or damage as a result of your trading, or your reliance on the information displayed. + ## Contacts [Didier Rodrigues Lopes](https://www.linkedin.com/in/didier-lopes/) - dro.lopes@campus.fct.unl.pt diff --git a/ROADMAP.md b/ROADMAP.md index 7b70578079b..fa0af690d63 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -15,13 +15,14 @@ * [Residual Analysis](#Residual-Analysis) * [Portfolio Analysis](#Portfolio-Analysis) * [Portfolio Optimization](#Portfolio-Optimization) -* [FRED](#FRED) +* [Economy](#Economy) * [Options](#Options) * [Credit Analysis](#Credit-Analysis) * [Cryptocurrencies](#Cryptocurrencies) * [Screener](#Screener) * [Forex](#Forex) * [Backtesting](#Backtesting) +* [Resource Collection](#Resource-Collection) ## Additional @@ -146,6 +147,7 @@ * [x] Add alpaca (@jmaslek) - [PR #259](https://github.com/DidierRLopes/GamestonkTerminal/pull/229) * [x] Add robinhood (@jmaslek) - [PR #229](https://github.com/DidierRLopes/GamestonkTerminal/pull/229) * [x] Add Ally Invest (@jmaslek) - [PR #267](https://github.com/DidierRLopes/GamestonkTerminal/pull/267) +* [x] Degiro support (@deel) - [PR #381](https://github.com/DidierRLopes/GamestonkTerminal/pull/381) **NEXT** * [ ] Merge data from different brokers (@jmaslek) @@ -166,8 +168,9 @@ ___ --- -## FRED +## Economy * [x] Implement Economic data (gpd, unemployment rate, ...) (@jmaslek) - [PR #167](https://github.com/DidierRLopes/GamestonkTerminal/pull/167) +* [x] Refactor FRED to ECON menu and add VIX view (@jmaslek) - [PR #405](https://github.com/DidierRLopes/GamestonkTerminal/pull/405) **NEXT** @@ -208,6 +211,7 @@ ___ * [x] Add screener signals (e.g. top gainers, new highs, most volatile, oversold, major news, ...) from Finviz (@didier) - [PR #314](https://github.com/DidierRLopes/GamestonkTerminal/pull/314) * [x] Plot screener historical using Yahoo Finance data (@didier) - [PR #319](https://github.com/DidierRLopes/GamestonkTerminal/pull/319) * [x] Add command to take tickers to portfolio optimization (@didier) - [PR #349](https://github.com/DidierRLopes/GamestonkTerminal/pull/349) +* [x] Add flags to save screeners and run papermill on returned tickers (@alokan) - [PR #414](https://github.com/DidierRLopes/GamestonkTerminal/pull/414) **NEXT** @@ -215,9 +219,21 @@ ___ ## Forex * [x] Add entire forex menu through Oanda (@alokan) - [PR #360](https://github.com/DidierRLopes/GamestonkTerminal/pull/360) +* [x] Add EDA menu, Behavioural Analysis menu, Due Diligence from other users in Reddit, and latest news regarding currency provided. (@alokan) - [PR #387](https://github.com/DidierRLopes/GamestonkTerminal/pull/387) **NEXT** + +--- + +## Resource Collection +* [x] Add hfletters and learn commands to resource collection (@didier) - [PR #427](https://github.com/DidierRLopes/GamestonkTerminal/pull/427) + + +**NEXT** + +--- + ## Backtesting * [x] Add simple backtest menu with simple strategies and benchmarks (@jmaslek) [PR #415](https://github.com/DidierRLopes/GamestonkTerminal/pull/415) @@ -250,6 +266,7 @@ ___ * [x] Add Feature Flags (@aia) - [PR #158](https://github.com/DidierRLopes/GamestonkTerminal/pull/158) * [x] Add ad-hoc builds (@aia) - [PR #192](https://github.com/DidierRLopes/GamestonkTerminal/pull/192) * [x] Add test generators and test parametrization helpers (@aia) - [PR #264](https://github.com/DidierRLopes/GamestonkTerminal/pull/264) +* [x] Sphinx documentation https://gamestonk-terminal.readthedocs.io/en/latest/index.html (@piiq) - [PR #413](https://github.com/DidierRLopes/GamestonkTerminal/pull/413) **NEXT** * [ ] Write a developer guide diff --git a/gamestonk_terminal/README.md b/gamestonk_terminal/README.md index d9dd64c259f..513e0a375a6 100644 --- a/gamestonk_terminal/README.md +++ b/gamestonk_terminal/README.md @@ -3,7 +3,7 @@ ### Table of contents * [Discover Stocks](#Discover-Stocks-) * [Behavioural Analysis](#Behavioural-Analysis-) -* [Research Web pages](#Research-Web-pages) +* [Research](#Research-) * [Fundamental Analysis](#Fundamental-Analysis-) * [Technical Analysis](#Technical-Analysis-) * [Due Diligence](#Due-Diligence-) @@ -14,10 +14,12 @@ * [Comparison Analysis](#Comparison-Analysis-) * [Exploratory Data Analysis](#Exploratory-Data-Analysis-) * [Residual Analysis](#Residual-Analysis-) -* [Economic Data](#Econ-) +* [Economy](#Economy) * [Options](#Options-) * [Screener](#Screener-) * [Forex](#Forex-) +* [Backtesting](#Backtesting-) +* [Resource Collection](#Resource-Collection-) ## Main @@ -115,7 +117,7 @@ Command|Description   -## Research Web pages +## Research [»](research/README.md) Command|Website ----|---- `macroaxis` |www.macroaxis.com @@ -136,11 +138,10 @@ Command|Website `macrotrends` |www.macrotrends.net `newsfilter` |www.newsfilter.io `stockanalysis` |www.stockanalysis.com -`resources` |www.tradinganalysisresources.com   -### Fundamental Analysis [»](fundamental_analysis/README.md) +## Fundamental Analysis [»](fundamental_analysis/README.md) Command|Description ----- | --------- @@ -237,6 +238,7 @@ Command|Technique|Sources `lstm` |Long Short-Term Memory | [Wikipedia](https://en.wikipedia.org/wiki/Long_short-term_memory), [Details](https://colah.github.io/posts/2015-08-Understanding-LSTMs/)   + ## Portfolio Analysis [»](portfolio/README.md) Command|Description|Brokers @@ -250,6 +252,7 @@ Command|Description|Brokers `hold` | view net holdings across all logins   + ## Portfolio Optimization [»](portfolio_optimization/README.md) Command|Description @@ -267,7 +270,6 @@ Command|Description   - ## Cryptocurrency [»](cryptocurrency/README.md) Command|Description @@ -282,6 +284,7 @@ Command|Description `balance`| look at current binance holdings for loaded coin   + ## Comparison Analysis [»](comparison_analysis/README.md) Command|Description|Source ------ | --------|---- @@ -328,23 +331,22 @@ Command|Description|Source `independence` |tests independent and identically distributed (BDS) | [Wikipedia](https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test#Testing_for_statistical_independence)   -## ECON [»](econ/README.md) + +## Economy [»](econ/README.md) Command|Description ------ | -------- -FRED Data | -`gdp` | GDP -`unemp` | Unemployment Rate -`t1` | 1-Year Treasury Constant Maturity Rate -`t5` | 5-Year Treasury Constant Maturity Rate -`t10` | 10-Year Treasury Constant Maturity Rate -`t30` | 30-Year Treasury Constant Maturity Rate -`mort30` | 30-Year Fixed Rate Mortgage Average -`fedrate` | Effective Federal Funds Rate -`moodAAA` | Moody's Seasoned AAA Corporate Bond Yield -`usdcad` | Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) -`cust` | User Specified FRED Data - Please Specify --id -VIX Data | -`view` | Plots VIX Historical Data +`vixcls` | Volatility Index +`gdp` | Gross Domestic Product +`unrate` | Unemployment Rate +`dgs1` | 1-Year Treasury Constant Maturity Rate +`dgs5` | 5-Year Treasury Constant Maturity Rate +`dgs10` | 10-Year Treasury Constant Maturity Rate +`dgs30` | 30-Year Treasury Constant Maturity Rate +`mortgage30us` | 30-Year Fixed Rate Mortgage Average +`fedfunds` | Effective Federal Funds Rate +`aaa` | Moody's Seasoned AAA Corporate Bond Yield +`dexcaus` | Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) +   ## Options [»](options/README.md) @@ -376,7 +378,6 @@ signals |view filter signals (e.g. -s top_gainers)   - ## Forex [»](forex/README.md) Command|Description ------ | -------- @@ -395,5 +396,23 @@ 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 +  + +## Backtesting [»](backtesting/README.md) +Command|Description +------ | -------- +`ema` | buy when price exceeds EMA(l) +`ema_cross` | buy when EMA(short) > EMA(long) +`rsi` | buy when RSI < low and sell when RSI > high + + + +## Resource Collection [»](resource_collection/README.md) +Command|Website +----|---- +`hfletters` |https://miltonfmr.com/hedge-fund-letters/ +`learn` |https://moongangcapital.com/free-stock-market-resources/   + + diff --git a/gamestonk_terminal/backtesting/README.md b/gamestonk_terminal/backtesting/README.md index 6a567e027e4..ee38b09b63a 100644 --- a/gamestonk_terminal/backtesting/README.md +++ b/gamestonk_terminal/backtesting/README.md @@ -1,53 +1,52 @@ # Backtesting -The goal of this menu is to allow super simple research into potential strategies. -We currently provides a couple basic options for starting with backtesting strategies. Note that this is currently just a -simple logic (i.e price comparisons). Obviously these strategies should not be used immediately and should be researched, -improved and further tested on your own. +This menu aims to apply backtesting strategies regarding a pre-loaded ticker, and the usage of the following commands along with an example will be exploited below. Note that this is currently just a simple logic (i.e price comparisons). These strategies should not be used immediately and should be researched, improved and further tested on your own. -The current implementation uses the [bt](#http://pmorissette.github.io/bt/index.html) library. +* [ema](#ema) + * buy when price exceeds EMA(l) +* [ema_cross](#ema_cross) + * buy when EMA(short) > EMA(long) +* [rsi](#rsi) + * buy when RSI < low and sell when RSI > high -Current strategies are: -* [Simple EMA](#SimpleEMA) - * Buys the stock when `price > EMA(l)` - -* [EMA Cross](#EMA Cross) - * Buys when EMA(short) > EMA(long) and sells when the opposite is true - -* [RSI](#RSI) - * Momentum strategy that longs when RSI < threshold (oversold) and shorts when +NOTE: The current implementation uses the [bt](#http://pmorissette.github.io/bt/index.html) library. -### SimpleEMA -This strategy buys when price > EMA(l) +### ema ```` usage: ema [-l] [--spy] [--no_bench] ```` + +This strategy buys when price > EMA(l). * -l: Period of EMA to use. Default = 20. * [--spy]: Flag that overlays the results if you buy and hold SPY * [--no_bench]: Flag that removes the benchmark comparison of just buy and hold the stock. -im: +![ema](https://user-images.githubusercontent.com/25267873/116769584-1eb37c80-aa35-11eb-898b-efa36d4a8f5c.png) +ema2 -### EMA Cross -This strategy goes long when EMA(short) > EMA(long) and goes short when -EMA(short) < EMA(long). I provide the option to go long only through the --no_short flag +### ema_cross ```` usage: ema_cross [-l] [-s] [--spy] [--no_bench] [--no_short] ```` + +This strategy goes long when EMA(short) > EMA(long) and goes short when EMA(short) < EMA(long). It provides the option to go long only through the --no_short flag. * -l/--long: Long period of EMA to use. Default = 50. * -s/--short: Short period of EMA to use. Default = 20. * [--spy]: Flag that overlays the results if you buy and hold SPY * [--no_bench]: Flag that removes the benchmark comparison of just buy and hold the stock. * [--no_short]: Flag that removes the shortable option. Will just be long positions when short > long EMAs. -im -### RSI -This strategy goes long when the RSI is "oversold" - defined as the low parameter. It goes short when -the RSI is "overbought" - defined as the high (upper) parameter +![ema_cross](https://user-images.githubusercontent.com/25267873/116769581-1ce9b900-aa35-11eb-85e9-133b3c0b09ad.png) +ema_cross2 + + +### rsi ```` usage: rsi [-u] [-l] [-p] [--spy] [--no_bench] [--no_short] ```` + +This strategy goes long when the RSI is "oversold" - defined as the low parameter. It goes short when the RSI is "overbought" - defined as the high (upper) parameter * -u/--high: High (upper) value to consider overbought. Default = 70 * -s/--short: Short period of EMA to use. Default = 30 * -p/--periods: Periods to use for RSI calculation. Default = 14. @@ -55,5 +54,5 @@ usage: rsi [-u] [-l] [-p] [--spy] [--no_bench] [--no_short] * [--no_bench]: Flag that removes the benchmark comparison of just buy and hold the stock. * [--no_short]: Flag that removes the shortable option. Will just be long positions when short > long EMAs. - - +![rsi](https://user-images.githubusercontent.com/25267873/116769576-19eec880-aa35-11eb-9e60-f77a31e51db0.png) +rsi2 diff --git a/gamestonk_terminal/backtesting/bt_controller.py b/gamestonk_terminal/backtesting/bt_controller.py index efeaefd6226..a4f05589987 100644 --- a/gamestonk_terminal/backtesting/bt_controller.py +++ b/gamestonk_terminal/backtesting/bt_controller.py @@ -43,7 +43,7 @@ class BacktestingController: def print_help(self): """Print help""" - print("Back Testing Menu\n") + print("\nBacktesting:") print(" help show this backtesting menu again") print(" q quit this menu, and shows back to main menu") print(" quit quit to abandon program") diff --git a/gamestonk_terminal/econ/README.md b/gamestonk_terminal/econ/README.md index b2b8149b044..1e6bb26f4b9 100644 --- a/gamestonk_terminal/econ/README.md +++ b/gamestonk_terminal/econ/README.md @@ -1,134 +1,183 @@ -# ECON +# ECONONMY -## FRED +This menu aims to assess economy data, and the usage of the following commands along with an example will be exploited below. -https://fred.stlouisfed.org +* [fred](#fred) + * display customized FRED from https://fred.stlouisfed.org +* [vixcls](#vixcls) + * Volatility Index +* [gdp](#gdp) + * Gross Domestic Product +* [unrate](#unrate) + * Unemployment Rate +* [dgs1](#dgs1) + * 1-Year Treasury Constant Maturity Rate +* [dgs5](#dgs5) + * 5-Year Treasury Constant Maturity Rate +* [dgs10](#dgs10) + * 10-Year Treasury Constant Maturity Rate +* [dgs30](#dgs30) + * 30-Year Treasury Constant Maturity Rate +* [mortgage30us](#mortgage30us) + * 30-Year Fixed Rate Mortgage Average +* [fedfunds](#fedfunds) + * Effective Federal Funds Rate +* [aaa](#aaa) + * Moody's Seasoned AAA Corporate Bond Yield +* [dexcaus](#dexcaus) + * Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) -The purpose of fred is to have the ability to look at economic data. This page offers 2 options: -* [predefined](#gdp) - * Get predefined data -* [cust](#cust) - * Get custom fred data - -The current predefined options are -* GDP -* 1,5,10,30 Year Treasury Rates -* 30 Year Mortgage Rates -* Unemployment Rate -* Effective Federal Funds rate -* Moody's AAA Corporate Bond -* CAD to USD Conversion. - -## predefined +## fred ```text -usage: selected [-n N_TO_GET] [-s START_DATE] [--noplot] [--hidedata] +usage: fred [-i SERIES_ID] [-s START_DATE] [-t] ``` -Gets predefined data. Arguments -* selected : Key from the predefined list. -* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2019 -* --noplot : Flag to hide plot -* --hidedata : Flag to suppress printing output. Useful for data released daily/weekly. -To plot the 30-Year Mortgage rates since 2018-01-01 suppressing the output. -```` -mort30 -s 2018-01-01 --hidedata -```` +Display customized Federal Reserve Economic Data (FRED) from https://fred.stlouisfed.org. -![mort30](https://user-images.githubusercontent.com/18151143/111521185-3d80dc80-872f-11eb-989d-c2bb256aa213.png) - -To show all GDP data since 1/1/2016, with no plot. -```` -gdp -s 2016-01-01 --noplot -```` -Output: -```` - GDP -Date -2016-01-01 18470.156 -2016-04-01 18656.207 -2016-07-01 18821.359 -2016-10-01 19032.580 -2017-01-01 19237.435 -2017-04-01 19379.232 -2017-07-01 19617.288 -2017-10-01 19937.963 -2018-01-01 20242.215 -2018-04-01 20552.653 -2018-07-01 20742.723 -2018-10-01 20909.853 -2019-01-01 21115.309 -2019-04-01 21329.877 -2019-07-01 21540.325 -2019-10-01 21747.394 -2020-01-01 21561.139 -2020-04-01 19520.114 -2020-07-01 21170.252 -2020-10-01 21487.896 -```` +* -i : FRED Series ID from https://fred.stlouisfed.org. +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. -## cust +## vixcls +```text +usage: vixcls [-s START_DATE] [-t] +``` -The fred database has many different datasets freely available. They each have their own custom SERIES_ID which can be obtained through the website. +Volatility Index -```` -usage: cust [-i --id] [-s START_DATE] [--noplot] [--hidedata] -```` -* -i/--id : Series ID for FRED data. Required argument -* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2015. -* --noplot : Flag to suppress output plot. -* --hidedata : Flag to suppress data output +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. -An example of custom data could be the USD/EURO exchange rate. -According to https://fred.stlouisfed.org/series/DEXUSEU , the series ID is DEXUSEU. So to plot this from the start of February 2021 to now (3/17) +![vixcls](https://user-images.githubusercontent.com/25267873/116769167-160d7700-aa32-11eb-8874-3b864908c9c2.png) -```` -cust --id DEXUSEU -s 2021-02-01 -```` -This will plot and display: -![cust](https://user-images.githubusercontent.com/18151143/111521481-92bcee00-872f-11eb-8a02-e7346e56e462.png) -```` - DEXUSEU -Date -2021-02-01 1.2070 -2021-02-02 1.2020 -2021-02-03 1.2025 -2021-02-04 1.1974 -2021-02-05 1.2035 -2021-02-08 1.2045 -2021-02-09 1.2106 -2021-02-10 1.2132 -2021-02-11 1.2127 -2021-02-12 1.2126 -2021-02-15 NaN -2021-02-16 1.2107 -2021-02-17 1.2042 -2021-02-18 1.2078 -2021-02-19 1.2136 -2021-02-22 1.2155 -2021-02-23 1.2142 -2021-02-24 1.2143 -2021-02-25 1.2229 -2021-02-26 1.2093 -2021-03-01 1.2054 -2021-03-02 1.2079 -2021-03-03 1.2073 -2021-03-04 1.2045 -2021-03-05 1.1914 -2021-03-08 1.1849 -2021-03-09 1.1885 -2021-03-10 1.1900 -2021-03-11 1.1978 -```` +## gdp +```text +usage: gdp [-s START_DATE] [-t] +``` -Note the NaN on 2-15, which corresponds to President's Day. +Gross Domestic Product -## VIX +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. -This command pulls historical VIX data from yfinance module. -```` -usage: view [-s START_DATE] -```` -* -s Start date to plot historical VIX data \ No newline at end of file +![gdp](https://user-images.githubusercontent.com/25267873/116769162-14dc4a00-aa32-11eb-886a-b5368146ed37.png) + + +## unrate +```text +usage: unrate [-s START_DATE] [-t] +``` + +Unemployment Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![unrate](https://user-images.githubusercontent.com/25267873/116769161-14dc4a00-aa32-11eb-91f3-a0f80d687a12.png) + + +## dgs1 +```text +usage: dgs1 [-s START_DATE] [-t] +``` + +1-year Treasury Constant Maturity Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![dgs1](https://user-images.githubusercontent.com/25267873/116769166-160d7700-aa32-11eb-9247-78156af4d527.png) + + +## dgs5 +```text +usage: dgs5 [-s START_DATE] [-t] +``` + +5-year Treasury Constant Maturity Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![dgs5](https://user-images.githubusercontent.com/25267873/116769165-1574e080-aa32-11eb-96ee-c57728d8f57c.png) + + +## dgs10 +```text +usage: dgs10 [-s START_DATE] [-t] +``` + +10-year Treasury Constant Maturity Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![dgs10](https://user-images.githubusercontent.com/25267873/116769164-1574e080-aa32-11eb-93a0-3b8a2b7cb3d2.png) + + +## dgs30 +```text +usage: dgs30 [-s START_DATE] [-t] +``` + +30-year Treasury Constant Maturity Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![dgs30](https://user-images.githubusercontent.com/25267873/116769159-13ab1d00-aa32-11eb-8c3d-e53c8d1f1a19.png) + + +## mortgage30us +```text +usage: mortgage30us [-s START_DATE] [-t] +``` + +30-year Fixed Rate Mortgage Average + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![mortgage30us](https://user-images.githubusercontent.com/25267873/116769157-13128680-aa32-11eb-8826-ccb2e6ae764e.png) + + +## fedfunds +```text +usage: fedfunds [-s START_DATE] [-t] +``` + +Effective Federal Funds Rate + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![fedfunds](https://user-images.githubusercontent.com/25267873/116769158-13ab1d00-aa32-11eb-9dc2-8296bc4f7e2c.png) + + +## aaa +```text +usage: aaa [-s START_DATE] [-t] +``` + +Moody's Seasoned AAA Corporate Bond Yield + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![aaa](https://user-images.githubusercontent.com/25267873/116769160-1443b380-aa32-11eb-84a8-036e15b47c9b.png) + + +## dexcaus +```text +usage: dexcaus [-s START_DATE] [-t] +``` + +Canada / U.S. Foreign Exchange Rate (CAD per 1 USD) + +* -s : Starting date (YYYY-MM-DD) of data. Default: 2019-01-01. +* -t : Only output text data. + +![dexcaus](https://user-images.githubusercontent.com/25267873/116769155-10b02c80-aa32-11eb-8ece-d8e92b8df1af.png) diff --git a/gamestonk_terminal/econ/econ_controller.py b/gamestonk_terminal/econ/econ_controller.py index 1e5eccc3c27..2bdaf1e8727 100644 --- a/gamestonk_terminal/econ/econ_controller.py +++ b/gamestonk_terminal/econ/econ_controller.py @@ -8,7 +8,7 @@ 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.econ import fred_view, vix_view +from gamestonk_terminal.econ import fred_view class EconController: @@ -19,24 +19,24 @@ class EconController: "help", "q", "quit", + "fred", + "vixcls", "gdp", - "unemp", - "t1", - "t5", - "t10", - "t30", - "mort30", - "fedrate", - "moodAAA", - "usdcad", - "cust", - "view", + "unrate", + "dgs1", + "dgs5", + "dgs10", + "dgs30", + "mortgage30us", + "fedfunds", + "aaa", + "dexcaus", ] def __init__(self): """Constructor""" - self.disc_parser = argparse.ArgumentParser(add_help=False, prog="econ") - self.disc_parser.add_argument( + self.econ_parser = argparse.ArgumentParser(add_help=False, prog="econ") + self.econ_parser.add_argument( "cmd", choices=self.CHOICES, ) @@ -50,21 +50,20 @@ class EconController: print(" q quit this menu, and shows back to main menu") print(" quit quit to abandon program") print(" ") - print("VIX:") - print(" view plot VIX") - print(" ") - print("FRED:") - print(" gdp GDP") - print(" unemp Unemployment Rate") - print(" t1 1-Year Treasury Constant Maturity Rate") - print(" t5 5-Year Treasury Constant Maturity Rate") - print(" t10 10-Year Treasury Constant Maturity Rate") - print(" t30 30-Year Treasury Constant Maturity Rate") - print(" mort30 30-Year Fixed Rate Mortgage Average") - print(" fedrate Effective Federal Funds Rate") - print(" moodAAA Moody's Seasoned AAA Corporate Bond Yield") - print(" usdcad Canada / U.S. Foreign Exchange Rate (CAD per 1 USD)") - print(" cust User Specified FRED Data - Please Specify --id") + print( + " fred display customized FRED data from https://fred.stlouisfed.org" + ) + print(" vixcls Volatility Index") + print(" gdp Gross Domestic Product") + print(" unrate Unemployment Rate") + print(" dgs1 1-year Treasury Constant Maturity Rate") + print(" dgs5 5-year Treasury Constant Maturity Rate") + print(" dgs10 10-year Treasury Constant Maturity Rate") + print(" dgs30 30-year Treasury Constant Maturity Rate") + print(" mortgage30us 30-year Fixed Rate Mortgage Average") + print(" fedfunds Effective Federal Funds Rate") + print(" aaa Moody's Seasoned AAA Corporate Bond Yield") + print(" dexcaus Canada / U.S. Foreign Exchange Rate (CAD per 1 USD)") print("") return @@ -78,23 +77,7 @@ class EconController: True - quit the program None - continue in the menu """ - (known_args, other_args) = self.disc_parser.parse_known_args(an_input.split()) - - fred_data_list = [ - "gdp", - "unemp", - "t1", - "t5", - "t10", - "t30", - "mort30", - "fedrate", - "moodAAA", - "usdcad", - ] - - if known_args.cmd in fred_data_list: - return getattr(self, "call_fred_api")(other_args, known_args.cmd) + (known_args, other_args) = self.econ_parser.parse_known_args(an_input.split()) return getattr( self, "call_" + known_args.cmd, lambda: "Command not recognized!" @@ -112,17 +95,53 @@ class EconController: """Process Quit command - quit the program""" return True - def call_fred_api(self, other_args: List[str], cmd: str): - """Process Fred Data call""" - fred_view.get_fred_data(other_args, cmd) + def call_fred(self, other_args: List[str]): + """Process fred command""" + fred_view.display_fred(other_args, "") - def call_view(self, other_args: List[str]): - """Process view for VIX Data.""" - vix_view.view_vix(other_args) + def call_vixcls(self, other_args: List[str]): + """Process vixcls command""" + fred_view.display_fred(other_args, "VIXCLS") - def call_cust(self, other_args: List[str]): - """Process cust call""" - fred_view.custom_data(other_args) + def call_gdp(self, other_args: List[str]): + """Process gdp command""" + fred_view.display_fred(other_args, "GDP") + + def call_unrate(self, other_args: List[str]): + """Process unrate command""" + fred_view.display_fred(other_args, "UNRATE") + + def call_dgs1(self, other_args: List[str]): + """Process dgs1 command""" + fred_view.display_fred(other_args, "DGS1") + + def call_dgs5(self, other_args: List[str]): + """Process dgs5 command""" + fred_view.display_fred(other_args, "DGS5") + + def call_dgs10(self, other_args: List[str]): + """Process dgs10 command""" + fred_view.display_fred(other_args, "DGS10") + + def call_dgs30(self, other_args: List[str]): + """Process dgs30 command""" + fred_view.display_fred(other_args, "DGS30") + + def call_mortgage30us(self, other_args: List[str]): + """Process mortgage30us command""" + fred_view.display_fred(other_args, "MORTGAGE30US") + + def call_fedfunds(self, other_args: List[str]): + """Process fedfunds command""" + fred_view.display_fred(other_args, "FEDFUNDS") + + def call_aaa(self, other_args: List[str]): + """Process aaa command""" + fred_view.display_fred(other_args, "AAA") + + def call_dexcaus(self, other_args: List[str]): + """Process dexcaus command""" + fred_view.display_fred(other_args, "DEXCAUS") def menu(): diff --git a/gamestonk_terminal/econ/fred_view.py b/gamestonk_terminal/econ/fred_view.py index 76f57f57a23..59ccd2c2682 100644 --- a/gamestonk_terminal/econ/fred_view.py +++ b/gamestonk_terminal/econ/fred_view.py @@ -18,138 +18,50 @@ from gamestonk_terminal import feature_flags as gtff register_matplotlib_converters() -api_map = { - "gdp": "GDP", - "t10": "DGS10", - "t1": "DGS1", - "t5": "DGS5", - "t30": "DGS30", - "mort30": "MORTGAGE30US", - "fedrate": "FEDFUNDS", - "moodAAA": "AAA", - "usdcad": "DEXCAUS", - "unemp": "UNRATE", -} -title_map = { - "gdp": "Gross Domestic Product", - "t10": "10-Year Treasury Constant Maturity Rate", - "t1": "1-Year Treasury Constant Maturity Rate", - "t5": "5-Year Treasury Constant Maturity Rate", - "t30": "30-Year Treasury Constant Maturity Rate", - "mort30": "30-Year Mortgage Rate", - "fedrate": "Effective Federal Funds Rate", - "moodAAA": "Moody's Seasoned AAA Corporate Bond Yield", - "usdcad": "Canada / U.S. Foreign Exchange Rate", - "unemp": "Unemployment Rate", +fred_series_description = { + "VIXCLS": "Volatility Index", + "GDP": "Gross Domestic Product", + "UNRATE": "Unemployment Rate", + "DGS1": "1-Year Treasury Constant Maturity Rate", + "DGS5": "5-Year Treasury Constant Maturity Rate", + "DGS10": "10-Year Treasury Constant Maturity Rate", + "DGS30": "30-Year Treasury Constant Maturity Rate", + "MORTGAGE30US": "30-Year Mortgage Rate", + "FEDFUNDS": "Effective Federal Funds Rate", + "AAA": "Moody's Seasoned AAA Corporate Bond Yield", + "DEXCAUS": "Canada / U.S. Foreign Exchange Rate", } -def get_fred_data(other_args: List[str], choice: str): - """Displace Fred data and graph for a selected chosen data series +def display_fred(other_args: List[str], choice: str): + """Display customized Federal Reserve Economic Data (FRED) from https://fred.stlouisfed.org. Parameters ---------- other_args : List[str] argparse other args choice : str - Fred data series: "gdp","unemp", "t1", "t5", "t10", "t30", "mort30", - "fedrate", "moodAAA", "usdcad", + Fred data series: "VIXCLS", "GDP", "DGS1", "DGS5", "DGS10", "DGS30", "MORTGAGE30US", "FEDFUNDS", + "AAA", "DEXCAUS", "UNRATE", """ - fred = Fred(api_key=API_FRED_KEY) - parser = argparse.ArgumentParser( add_help=False, - prog="Custom", + prog=choice if choice else "fred", description=""" - Custom Data + Display customized Federal Reserve Economic Data (FRED) from https://fred.stlouisfed.org. """, ) parser.add_argument( - "-s", - dest="start_date", - type=valid_date, - default="2019-01-01", - required=False, - help="Starting date (YYYY-MM-DD) of data", - ) - - parser.add_argument( - "--noplot", - action="store_false", - default=True, - dest="noplot", - help="Suppress output plot", - ) - - parser.add_argument( - "--hidedata", - action="store_false", - default=True, - dest="hidedata", - help="Suppress data display plot", - ) - - try: - ns_parser = parse_known_args_and_warn(parser, other_args) - - if not ns_parser: - return - - string_to_get = api_map[choice] - title = title_map[choice] - data = fred.get_series(string_to_get, ns_parser.start_date) - - data = pd.DataFrame(data, columns=[f"{string_to_get}"]) - data.index.name = "Date" - if ns_parser.hidedata: - print(data) - print("") - if ns_parser.noplot: - plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) - plt.plot(data.index, data.iloc[:, 0], "-ok") - plt.xlabel("Time") - plt.xlim(data.index[0], data.index[-1]) - plt.ylabel(f"{string_to_get}") - plt.grid(b=True, which="major", color="#666666", linestyle="-") - plt.minorticks_on() - plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) - plt.title(title) - plt.show() - print("") - - if gtff.USE_ION: - plt.ion() - - except SystemExit: - print("") - except Exception as e: - print(e) - print("") - return - - -def custom_data(other_args: List[str]): - """Displace Fred data for a custom series request - - Parameters - ---------- - other_args : List[str] - argparse other args - """ - fred = Fred(api_key=API_FRED_KEY) - - parser = argparse.ArgumentParser( - add_help=False, - prog="Custom", - description=""" - Custom Data - """, - ) - parser.add_argument( - "-i", "--id", dest="series_id", required=True, type=str, help="FRED Series ID" + "-i", + "--id", + dest="series_id", + required=bool(choice), + type=str, + default=choice.upper(), + help="FRED Series ID from https://fred.stlouisfed.org", ) parser.add_argument( @@ -157,58 +69,55 @@ def custom_data(other_args: List[str]): dest="start_date", type=valid_date, default="2019-01-01", - required=False, help="Starting date (YYYY-MM-DD) of data", ) parser.add_argument( - "--noplot", - action="store_false", - default=True, - dest="noplot", - help="Suppress output plot", - ) - - parser.add_argument( - "--hidedata", - action="store_false", - default=True, - dest="hidedata", - help="Suppress data display plot", + "-t", + "--text", + action="store_true", + dest="text", + help="Only output text data", ) try: + if not choice: + if other_args: + if "-" not in other_args[0]: + other_args.insert(0, "-i") ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return - data = fred.get_series(ns_parser.series_id, ns_parser.start_date) + fred = Fred(api_key=API_FRED_KEY) + d_data = fred.get_series(ns_parser.series_id, ns_parser.start_date) - data = pd.DataFrame(data, columns=[f"{ns_parser.series_id}"]) - data.index.name = "Date" - if ns_parser.hidedata: - print(data) - print("") - if ns_parser.noplot: + df_fred = pd.DataFrame(d_data, columns=[f"{ns_parser.series_id}"]) + df_fred.index.name = "Date" + + if ns_parser.text: + print(df_fred.to_string()) + + else: plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) - plt.plot(data.index, data.iloc[:, 0], "-ok") + plt.plot(df_fred.index, df_fred.iloc[:, 0]) plt.xlabel("Time") - plt.xlim(data.index[0], data.index[-1]) - plt.ylabel(f"{ns_parser.series_id}") + plt.xlim(df_fred.index[0], df_fred.index[-1]) + plt.ylabel(f"{ns_parser.series_id.upper()}") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) - plt.title(f"FRED {ns_parser.series_id} Series") - plt.show() - print("") - + if choice: + plt.title(fred_series_description[ns_parser.series_id]) if gtff.USE_ION: plt.ion() + plt.show() + + print("") except SystemExit: print("") except Exception as e: - print(e) - print("") + print(e, "\n") return diff --git a/gamestonk_terminal/econ/vix_view.py b/gamestonk_terminal/econ/vix_view.py deleted file mode 100644 index 82565e0338b..00000000000 --- a/gamestonk_terminal/econ/vix_view.py +++ /dev/null @@ -1,63 +0,0 @@ -""" VIX View """ -__docformat__ = "numpy" -import argparse - -from typing import List -from pandas.plotting import register_matplotlib_converters -import matplotlib.pyplot as plt -import yfinance as yf -from gamestonk_terminal.helper_funcs import ( - parse_known_args_and_warn, - valid_date, - plot_autoscale, -) -from gamestonk_terminal.config_plot import PLOT_DPI -from gamestonk_terminal import feature_flags as gtff - -register_matplotlib_converters() - - -def view_vix(other_args: List[str]): - """ - Plot vix from a starting date using yfinance - Parameters - ---------- - other_args: List[str] - List of argparse arguments - Returns - ------- - Plots VIX historical data - """ - parser = argparse.ArgumentParser(prog="vix_plot", add_help=False) - parser.add_argument( - "-s", - "--start", - type=valid_date, - default="2020-01-01", - dest="start_date", - help="The starting date (format YYYY-MM-DD) of the plot", - ) - - try: - ns_parser = parse_known_args_and_warn(parser, other_args) - if not ns_parser: - return - - vix = yf.download("^VIX", start=ns_parser.start_date, progress=False) - _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) - vix.plot(y="Adj Close", ax=ax) - plt.ylabel("VIX") - plt.grid(b=True, which="major", color="#666666", linestyle="-") - plt.minorticks_on() - plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) - plt.title("Historical VIX Data") - - print("") - - if gtff.USE_ION: - plt.ion() - plt.show() - - except Exception as e: - print(e) - print("") diff --git a/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py b/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py index d2192875f17..3f84e208bd3 100644 --- a/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py +++ b/gamestonk_terminal/fundamental_analysis/yahoo_finance_view.py @@ -213,7 +213,7 @@ def sustainability(other_args: List[str], ticker: str): df_sustainability = stock.sustainability - if not df_sustainability: + if df_sustainability.empty: print(f"No sustainability information in Yahoo for {ticker}") print("") return diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py index eef982c7349..173aa345dec 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -1,5 +1,6 @@ import argparse from sys import stdout +import random from datetime import datetime, timedelta import matplotlib.pyplot as plt import pandas as pd @@ -45,57 +46,59 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): print(f"\n{s_intraday} Stock: {s_ticker}") else: print("\nStock: ?") - print(f"Market {('CLOSED', 'OPEN')[b_is_market_open]}.") + print(f"Market {('CLOSED', 'OPEN')[b_is_market_open]}.\n") - print("\nMenus:") print( - " disc discover trending stocks, \t e.g. map, sectors, high short interest" + " > disc discover trending stocks, \t e.g. map, sectors, high short interest" ) print( - " scr screener stocks, \t\t e.g. overview/performance, using preset filters" + " > scr screener stocks, \t\t e.g. overview/performance, using preset filters" ) - print(" mill papermill menu, \t\t\t menu to generate notebook reports") - print(" econ economic data, \t\t\t from: FRED, VIX") - print(" pa portfolio analysis, \t\t supports: robinhood, alpaca, ally ") - print(" crypto cryptocurrencies, \t\t coingecko, coinmarketcap and binance") + print(" > mill papermill menu, \t\t menu to generate notebook reports") + print(" > econ economic data, \t\t from: FRED, VIX") print( - " po portfolio optimization, \t\t optimal portfolio weights from pyportfolioopt" + " > pa portfolio analysis, \t\t supports: robinhood, alpaca, ally " ) - print(" fx forex menu, \t\t\t forex support through Oanda") + print(" > crypto cryptocurrencies, \t\t from: coingecko, coinmarketcap, binance") + print( + " > po portfolio optimization, \t optimal portfolio weights from pyportfolioopt" + ) + print(" > fx forex menu, \t\t\t forex support through Oanda") + print(" > rc resource collection, \t\t e.g. hf letters") if s_ticker: print( - " ba behavioural analysis, \t from: reddit, stocktwits, twitter, google" + " > ba behavioural analysis, \t from: reddit, stocktwits, twitter, google" ) print( - " res research web page, \t e.g.: macroaxis, yahoo finance, fool" + " > res research web page, \t e.g.: macroaxis, yahoo finance, fool" ) print( - " ca comparison analysis, \t e.g.: historical, correlation, financials" + " > ca comparison analysis, \t e.g.: historical, correlation, financials" ) print( - " fa fundamental analysis, \t e.g.: income, balance, cash, earnings" + " > fa fundamental analysis, \t e.g.: income, balance, cash, earnings" ) print( - " ta technical analysis, \t e.g.: ema, macd, rsi, adx, bbands, obv" + " > ta technical analysis, \t e.g.: ema, macd, rsi, adx, bbands, obv" ) print( - " bt strategy backtester, \t e.g.: simple ema, ema cross, rsi strategies" + " > bt strategy backtester, \t e.g.: simple ema, ema cross, rsi strategies" ) print( - " dd in-depth due-diligence, \t e.g.: news, analyst, shorts, insider, sec" + " > dd in-depth due-diligence, \t e.g.: news, analyst, shorts, insider, sec" ) print( - " eda exploratory data analysis,\t e.g.: decompose, cusum, residuals analysis" + " > eda exploratory data analysis,\t e.g.: decompose, cusum, residuals analysis" ) print( - " pred prediction techniques, \t e.g.: regression, arima, rnn, lstm, prophet" + " > pred prediction techniques, \t e.g.: regression, arima, rnn, lstm, prophet" ) print( - " ra residuals analysis, \t e.g.: model fit, qqplot, hypothesis test" + " > ra residuals analysis, \t e.g.: model fit, qqplot, hypothesis test" ) print( - " op options info, \t e.g.: volume and open interest" + " > op options info , \t e.g.: volume and open interest" ) print("") @@ -181,41 +184,40 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): if not ns_parser: return [s_ticker, s_start, s_interval, df_stock] - except SystemExit: - print("") - return [s_ticker, s_start, s_interval, df_stock] - - # Update values: - s_ticker = ns_parser.s_ticker.upper() - s_start = ns_parser.s_start_date - s_interval = str(ns_parser.n_interval) + "min" - - try: # Daily - if s_interval == "1440min": + if ns_parser.n_interval == 1440: + # Alpha Vantage Source if ns_parser.source == "av": ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") # pylint: disable=unbalanced-tuple-unpacking - df_stock, _ = ts.get_daily_adjusted( + df_stock_candidate, _ = ts.get_daily_adjusted( symbol=ns_parser.s_ticker, outputsize="full" ) - # pylint: disable=no-member - df_stock.sort_index(ascending=True, inplace=True) - # Slice dataframe from the starting date YYYY-MM-DD selected - df_stock = df_stock[ns_parser.s_start_date :] - - elif ns_parser.source == "yf": - df_stock = yf.download( - ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False - ) - # Check that a stock was successfully retrieved - if df_stock.empty: + # Check that loading a stock was not successful + if df_stock_candidate.empty: print("") return [s_ticker, s_start, s_interval, df_stock] - df_stock = df_stock.rename( + # pylint: disable=no-member + df_stock_candidate.sort_index(ascending=True, inplace=True) + + # Slice dataframe from the starting date YYYY-MM-DD selected + df_stock_candidate = df_stock_candidate[ns_parser.s_start_date :] + + # Yahoo Finance Source + elif ns_parser.source == "yf": + df_stock_candidate = yf.download( + ns_parser.s_ticker, start=ns_parser.s_start_date, progress=False + ) + + # Check that loading a stock was not successful + if df_stock_candidate.empty: + print("") + return [s_ticker, s_start, s_interval, df_stock] + + df_stock_candidate = df_stock_candidate.rename( columns={ "Open": "1. open", "High": "2. high", @@ -225,41 +227,57 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): "Volume": "6. volume", } ) - df_stock.index.name = "date" + df_stock_candidate.index.name = "date" - if df_stock.index[0] > s_start: - s_start = df_stock.index[0] + # Check if start time from dataframe is more recent than specified + if df_stock_candidate.index[0] > pd.to_datetime(ns_parser.s_start_date): + s_start = df_stock_candidate.index[0] + else: + s_start = ns_parser.s_start_date # Intraday else: + + # Alpha Vantage Source if ns_parser.source == "av": ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") # pylint: disable=unbalanced-tuple-unpacking - df_stock, _ = ts.get_intraday( - symbol=ns_parser.s_ticker, outputsize="full", interval=s_interval + df_stock_candidate, _ = ts.get_intraday( + symbol=ns_parser.s_ticker, + outputsize="full", + interval=str(ns_parser.n_interval) + "min", ) + + # Check that loading a stock was not successful + if df_stock_candidate.empty: + print("") + return [s_ticker, s_start, s_interval, df_stock] + # pylint: disable=no-member - df_stock.sort_index(ascending=True, inplace=True) + df_stock_candidate.sort_index(ascending=True, inplace=True) # Slice dataframe from the starting date YYYY-MM-DD selected - df_stock = df_stock[ns_parser.s_start_date :] + df_stock_candidate = df_stock_candidate[ns_parser.s_start_date :] + # Check if start time from dataframe is more recent than specified + if df_stock_candidate.index[0] > pd.to_datetime(ns_parser.s_start_date): + s_start = df_stock_candidate.index[0] + else: + s_start = ns_parser.s_start_date + + # Yahoo Finance Source elif ns_parser.source == "yf": - s_int = s_interval[:-2] + s_int = str(ns_parser.n_interval) + "m" d_granularity = {"1m": 6, "5m": 59, "15m": 59, "30m": 59, "60m": 729} s_start_dt = datetime.utcnow() - timedelta(days=d_granularity[s_int]) s_date_start = s_start_dt.strftime("%Y-%m-%d") - s_start = pytz.utc.localize(s_start_dt) - if s_start_dt > ns_parser.s_start_date: - print( - f"Using Yahoo Finance with granularity {s_int} the starting date is set to: {s_date_start}\n" - ) + # Using Yahoo Finance with granularity {s_int} the starting date is set to: {s_date_start} - df_stock = yf.download( + df_stock_candidate = yf.download( ns_parser.s_ticker, start=s_date_start, progress=False, @@ -268,7 +286,7 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): ) else: - df_stock = yf.download( + df_stock_candidate = yf.download( ns_parser.s_ticker, start=ns_parser.s_start_date.strftime("%Y-%m-%d"), progress=False, @@ -276,12 +294,17 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): prepost=ns_parser.b_prepost, ) - # Check that a stock was successfully retrieved - if df_stock.empty: + # Check that loading a stock was not successful + if df_stock_candidate.empty: print("") return [s_ticker, s_start, s_interval, df_stock] - df_stock = df_stock.rename( + if s_start_dt > ns_parser.s_start_date: + s_start = pytz.utc.localize(s_start_dt) + else: + s_start = ns_parser.s_start_date + + df_stock_candidate = df_stock_candidate.rename( columns={ "Open": "1. open", "High": "2. high", @@ -291,26 +314,29 @@ def load(l_args, s_ticker, s_start, s_interval, df_stock): "Volume": "6. volume", } ) - df_stock.index.name = "date" + df_stock_candidate.index.name = "date" - return [s_ticker, s_start, s_interval, df_stock] + s_intraday = (f"Intraday {s_interval}", "Daily")[ns_parser.n_interval == 1440] + + print( + f"Loading {s_intraday} {ns_parser.s_ticker.upper()} stock " + f"with starting period {s_start.strftime('%Y-%m-%d')} for analysis.\n" + ) + + return [ + ns_parser.s_ticker.upper(), + s_start, + str(ns_parser.n_interval) + "min", + df_stock_candidate, + ] except Exception as e: - print(e) - print("Either the ticker or the API_KEY are invalids. Try again!\n") + print(e, "\nEither the ticker or the API_KEY are invalids. Try again!\n") return [s_ticker, s_start, s_interval, df_stock] - s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"] - - if s_start: - print( - f"Loading {s_intraday} {s_ticker} stock with starting period {s_start.strftime('%Y-%m-%d')} for analysis." - ) - else: - print(f"Loading {s_intraday} {s_ticker} stock for analysis.") - - print("") - return [s_ticker, s_start, s_interval, df_stock] + except SystemExit: + print("") + return [s_ticker, s_start, s_interval, df_stock] def candle(s_ticker: str, s_start: str): @@ -513,3 +539,32 @@ def export(l_args, df_stock): df_stock.to_clipboard() print("") + + +def print_goodbye(): + goodbye_msg = [ + "An informed ape, is a strong ape. ", + "Remember that stonks only go up. ", + "Diamond hands. ", + "Apes together strong. ", + "This is our way. ", + "Keep the spacesuit ape, we haven't reached the moon yet. ", + "I am not a cat. I'm an ape. ", + "We like the terminal. ", + ] + + goodbye_hr = datetime.now().hour + if goodbye_hr < 5: + goodbye_msg_time = "Go get some rest soldier!" + elif goodbye_hr < 11: + goodbye_msg_time = "Rise and shine baby!" + elif goodbye_hr < 17: + goodbye_msg_time = "Enjoy your day!" + elif goodbye_hr < 23: + goodbye_msg_time = "Tomorrow's another day!" + else: + goodbye_msg_time = "Go get some rest soldier!" + + print( + goodbye_msg[random.randint(0, len(goodbye_msg) - 1)] + goodbye_msg_time + "\n" + ) diff --git a/gamestonk_terminal/res_menu.py b/gamestonk_terminal/res_menu.py deleted file mode 100644 index 3815cebbc8e..00000000000 --- a/gamestonk_terminal/res_menu.py +++ /dev/null @@ -1,180 +0,0 @@ -import argparse -import webbrowser - - -def print_research(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("\nResearch Mode:") - print(" help show this research menu again") - print(" q quit this menu, and shows back to main menu") - print(" quit quit to abandon program") - print("") - print(" macroaxis www.macroaxis.com") - print(" yahoo www.finance.yahoo.com") - print(" finviz www.finviz.com") - print(" marketwatch www.marketwatch.com") - print(" fool www.fool.com") - print(" businessinsider www.markets.businessinsider.com") - print(" fmp www.financialmodelingprep.com") - print(" fidelity www.eresearch.fidelity.com") - print(" tradingview www.tradingview.com") - print(" marketchameleon www.marketchameleon.com") - print(" stockrow www.stockrow.com") - print(" barchart www.barchart.com") - print(" grufity www.grufity.com") - print(" fintel www.fintel.com") - print(" zacks www.zacks.com") - print(" macrotrends www.macrotrends.net") - print(" newsfilter www.newsfilter.io") - print(" stockanalysis www.stockanalysis.com") - print("") - print(" resources trading analysis, tips and research") - print("") - - -# pylint: disable=too-many-branches -def res_menu(s_ticker, s_start, s_interval): - # Add list of arguments that the research parser accepts - res_parser = argparse.ArgumentParser(add_help=False, prog="discovery") - res_parser.add_argument( - "cmd", - choices=[ - "help", - "q", - "quit", - "macroaxis", - "yahoo", - "finviz", - "marketwatch", - "fool", - "businessinsider", - "fmp", - "fidelity", - "tradingview", - "marketchameleon", - "stockrow", - "barchart", - "grufity", - "fintel", - "zacks", - "macrotrends", - "newsfilter", - "resources", - "stockanalysis", - ], - ) - - print_research(s_ticker, s_start, s_interval) - - # Loop forever and ever - while True: - # Get input command from user - as_input = input("> ") - - # Parse fundamental analysis command of the list of possible commands - try: - (ns_known_args, _) = res_parser.parse_known_args(as_input.split()) - except SystemExit: - print("The command selected doesn't exist\n") - continue - - try: - if ns_known_args.cmd == "help": - print_research(s_ticker, s_start, s_interval) - - elif ns_known_args.cmd == "q": - # Just leave the RES menu - return False - - elif ns_known_args.cmd == "quit": - # Abandon the program - return True - - elif ns_known_args.cmd == "macroaxis": - webbrowser.open(f"https://www.macroaxis.com/invest/market/{s_ticker}") - - elif ns_known_args.cmd == "yahoo": - webbrowser.open(f"https://finance.yahoo.com/quote/{s_ticker}") - - elif ns_known_args.cmd == "finviz": - webbrowser.open(f"https://finviz.com/quote.ashx?t={s_ticker}") - - elif ns_known_args.cmd == "marketwatch": - webbrowser.open( - f"https://www.marketwatch.com/investing/stock/{s_ticker}" - ) - - elif ns_known_args.cmd == "fool": - webbrowser.open(f"https://www.fool.com/quote/{s_ticker}") - - elif ns_known_args.cmd == "businessinsider": - webbrowser.open( - f"https://markets.businessinsider.com/stocks/{s_ticker}-stock/" - ) - - elif ns_known_args.cmd == "fmp": - webbrowser.open( - f"https://financialmodelingprep.com/financial-summary/{s_ticker}" - ) - - elif ns_known_args.cmd == "fidelity": - webbrowser.open( - f"https://eresearch.fidelity.com/eresearch/goto/evaluate/snapshot.jhtml?symbols={s_ticker}" - ) - - elif ns_known_args.cmd == "tradingview": - webbrowser.open(f"https://www.tradingview.com/symbols/{s_ticker}") - - elif ns_known_args.cmd == "marketchameleon": - webbrowser.open(f"https://marketchameleon.com/Overview/{s_ticker}") - - elif ns_known_args.cmd == "stockrow": - webbrowser.open(f"https://stockrow.com/{s_ticker}") - - elif ns_known_args.cmd == "barchart": - webbrowser.open( - f"https://www.barchart.com/stocks/quotes/{s_ticker}/overview" - ) - - elif ns_known_args.cmd == "grufity": - webbrowser.open(f"https://grufity.com/stock/{s_ticker}") - - elif ns_known_args.cmd == "fintel": - webbrowser.open(f"https://fintel.io/s/us/{s_ticker}") - - elif ns_known_args.cmd == "zacks": - webbrowser.open(f"https://www.zacks.com/stock/quote/{s_ticker}") - - elif ns_known_args.cmd == "macrotrends": - webbrowser.open( - f"https://www.macrotrends.net/stocks/charts/{s_ticker}/{s_ticker}/market-cap" - ) - - elif ns_known_args.cmd == "newsfilter": - webbrowser.open(f"https://newsfilter.io/search?query={s_ticker}") - - elif ns_known_args.cmd == "stockanalysis": - webbrowser.open(f"https://stockanalysis.com/stocks/{s_ticker}") - - elif ns_known_args.cmd == "resources": - # webbrowser.open(f"https://www.tradinganalysisresources.com/2020/05/free-references-and-resources.html") - webbrowser.open( - "https://moongangcapital.com/free-stock-market-resources/" - ) - - else: - print("Command not recognized!") - - print("") - - except SystemExit: - print("") - return False diff --git a/gamestonk_terminal/research/README.md b/gamestonk_terminal/research/README.md new file mode 100644 index 00000000000..e32f91071cb --- /dev/null +++ b/gamestonk_terminal/research/README.md @@ -0,0 +1,28 @@ +# RESEARCH + +This menu aims to investigate a stock from a website of reference. The list of the supported websites is displayed below. + +
+ +Command|Website + ----|---- +`macroaxis` |www.macroaxis.com +`yahoo` |www.finance.yahoo.com +`finviz` |www.finviz.com +`marketwatch` |www.marketwatch.com +`fool` |www.fool.com +`businessinsider` |www.markets.businessinsider.com +`fmp` |www.financialmodelingprep.com +`fidelity` |www.eresearch.fidelity.com +`tradingview` |www.tradingview.com +`marketchameleon` |www.marketchameleon.com +`stockrow` |www.stockrow.com +`barchart` |www.barchart.com +`grufity` |www.grufity.com +`fintel` |www.fintel.com +`zacks` |www.zacks.com +`macrotrends` |www.macrotrends.net +`newsfilter` |www.newsfilter.io +`stockanalysis` |www.stockanalysis.com + +
diff --git a/gamestonk_terminal/research/res_controller.py b/gamestonk_terminal/research/res_controller.py new file mode 100644 index 00000000000..a5f2bf68346 --- /dev/null +++ b/gamestonk_terminal/research/res_controller.py @@ -0,0 +1,232 @@ +"""Research Controller Module""" +__docformat__ = "numpy" + +import argparse +import webbrowser +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 +from gamestonk_terminal.menu import session + + +class ResearchController: + """Research Controller class""" + + # Command choices + CHOICES = [ + "help", + "q", + "quit", + "macroaxis", + "yahoo", + "finviz", + "marketwatch", + "fool", + "businessinsider", + "fmp", + "fidelity", + "tradingview", + "marketchameleon", + "stockrow", + "barchart", + "grufity", + "fintel", + "zacks", + "macrotrends", + "newsfilter", + "stockanalysis", + ] + + def __init__(self, ticker: str, start: datetime, interval: str): + """Constructor""" + self.ticker = ticker + self.start = start + self.interval = interval + self.res_parser = argparse.ArgumentParser(add_help=False, prog="res") + self.res_parser.add_argument( + "cmd", + choices=self.CHOICES, + ) + + @staticmethod + def print_help(self): + """Print help""" + + s_intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"] + + if self.start: + print( + f"\n{s_intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})" + ) + else: + print(f"\n{s_intraday} Stock: {self.ticker}") + + print("\nResearch:") + print(" help show this behavioural analysis menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print("") + print(" macroaxis www.macroaxis.com") + print(" yahoo www.finance.yahoo.com") + print(" finviz www.finviz.com") + print(" marketwatch www.marketwatch.com") + print(" fool www.fool.com") + print(" businessinsider www.markets.businessinsider.com") + print(" fmp www.financialmodelingprep.com") + print(" fidelity www.eresearch.fidelity.com") + print(" tradingview www.tradingview.com") + print(" marketchameleon www.marketchameleon.com") + print(" stockrow www.stockrow.com") + print(" barchart www.barchart.com") + print(" grufity www.grufity.com") + print(" fintel www.fintel.com") + print(" zacks www.zacks.com") + print(" macrotrends www.macrotrends.net") + print(" newsfilter www.newsfilter.io") + print(" stockanalysis www.stockanalysis.com") + + 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.res_parser.parse_known_args(an_input.split()) + + if other_args: + print(f"The following args were unexpected: {other_args}") + + return getattr( + self, "call_" + known_args.cmd, lambda: "Command not recognized!" + )(None) + + def call_help(self, _): + """Process Help command""" + self.print_help(self) + + 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_macroaxis(self, _): + """Process macroaxis command""" + webbrowser.open(f"https://www.macroaxis.com/invest/market/{self.ticker}") + + def call_yahoo(self, _): + """Process yahoo command""" + webbrowser.open(f"https://finance.yahoo.com/quote/{self.ticker}") + + def call_finviz(self, _): + """Process finviz command""" + webbrowser.open(f"https://finviz.com/quote.ashx?t={self.ticker}") + + def call_marketwatch(self, _): + """Process marketwatch command""" + webbrowser.open(f"https://www.marketwatch.com/investing/stock/{self.ticker}") + + def call_fool(self, _): + """Process fool command""" + webbrowser.open(f"https://www.fool.com/quote/{self.ticker}") + + def call_businessinsider(self, _): + """Process businessinsider command""" + webbrowser.open( + f"https://markets.businessinsider.com/stocks/{self.ticker}-stock/" + ) + + def call_fmp(self, _): + """Process fmp command""" + webbrowser.open( + f"https://financialmodelingprep.com/financial-summary/{self.ticker}" + ) + + def call_fidelity(self, _): + """Process fidelity command""" + webbrowser.open( + f"https://eresearch.fidelity.com/eresearch/goto/evaluate/snapshot.jhtml?symbols={self.ticker}" + ) + + def call_tradingview(self, _): + """Process tradingview command""" + webbrowser.open(f"https://www.tradingview.com/symbols/{self.ticker}") + + def call_marketchameleon(self, _): + """Process marketchameleon command""" + webbrowser.open(f"https://marketchameleon.com/Overview/{self.ticker}") + + def call_stockrow(self, _): + """Process stockrow command""" + webbrowser.open(f"https://stockrow.com/{self.ticker}") + + def call_barchart(self, _): + """Process barchart command""" + webbrowser.open( + f"https://www.barchart.com/stocks/quotes/{self.ticker}/overview" + ) + + def call_grufity(self, _): + """Process grufity command""" + webbrowser.open(f"https://grufity.com/stock/{self.ticker}") + + def call_fintel(self, _): + """Process fintel command""" + webbrowser.open(f"https://fintel.io/s/us/{self.ticker}") + + def call_zacks(self, _): + """Process zacks command""" + webbrowser.open(f"https://www.zacks.com/stock/quote/{self.ticker}") + + def call_macrotrends(self, _): + """Process macrotrends command""" + webbrowser.open( + f"https://www.macrotrends.net/stocks/charts/{self.ticker}/{self.ticker}/market-cap" + ) + + def call_newsfilter(self, _): + """Process newsfilter command""" + webbrowser.open(f"https://newsfilter.io/search?query={self.ticker}") + + def call_stockanalysis(self, _): + """Process stockanalysis command""" + webbrowser.open(f"https://stockanalysis.com/stocks/{self.ticker}/") + + +def menu(ticker: str, start: datetime, interval: str): + """Research Menu""" + + res_controller = ResearchController(ticker, start, interval) + res_controller.call_help(None) + print("") + + while True: + # Get input command from user + if session and gtff.USE_PROMPT_TOOLKIT: + completer = NestedCompleter.from_nested_dict( + {c: None for c in res_controller.CHOICES} + ) + an_input = session.prompt( + f"{get_flair()} (res)> ", + completer=completer, + ) + else: + an_input = input(f"{get_flair()} (res)> ") + + try: + process_input = res_controller.switch(an_input) + print("") + + if process_input is not None: + return process_input + + except SystemExit: + print("The command selected doesn't exist\n") + continue diff --git a/gamestonk_terminal/resource_collection/README.md b/gamestonk_terminal/resource_collection/README.md new file mode 100644 index 00000000000..80a2ba94580 --- /dev/null +++ b/gamestonk_terminal/resource_collection/README.md @@ -0,0 +1,28 @@ +# RESOURCE COLLECTION + +This menu aims to store a collection of useful resources that can't be scraped, or extracted in a "useful" manner, and the usage of the following commands along with an example will be exploited below. + +* [hfletters](#hfletters) + * hedge fund letters or reports +* [learn](#learn) + * trading analysis, tips and resources + + +## hfletters + +```text +usage: hfletters +``` + +Captura de ecrã 2021-05-01, às 21 13 22 +Captura de ecrã 2021-05-01, às 21 14 08 + + +## learn + +```text +usage: learn +``` + +Captura de ecrã 2021-05-01, às 21 16 07 + diff --git a/gamestonk_terminal/resource_collection/rc_controller.py b/gamestonk_terminal/resource_collection/rc_controller.py new file mode 100644 index 00000000000..4ba30e38107 --- /dev/null +++ b/gamestonk_terminal/resource_collection/rc_controller.py @@ -0,0 +1,109 @@ +"""Resource Collection Controller Module""" +__docformat__ = "numpy" + +import argparse +import webbrowser +from typing import List +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 + + +class ResourceCollectionController: + """Resources Controller class""" + + # Command choices + CHOICES = ["help", "q", "quit", "hfletters", "learn"] + + def __init__(self): + """Constructor""" + self.rc_parser = argparse.ArgumentParser(add_help=False, prog="rc") + self.rc_parser.add_argument( + "cmd", + choices=self.CHOICES, + ) + + @staticmethod + def print_help(): + """Print help""" + + print("\nResources:") + print(" help show this behavioural analysis menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print("") + print(" hfletters hedge fund letters or reports") + print(" learn trading analysis, tips and resources") + 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.rc_parser.parse_known_args(an_input.split()) + + if other_args: + print(f"The following args were unexpected: {other_args}") + + 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_hfletters(self, other_args: List[str]): + """Process hfletters command""" + webbrowser.open("https://miltonfmr.com/hedge-fund-letters/") + print("") + + def call_learn(self, other_args: List[str]): + """Process learn command""" + webbrowser.open("https://moongangcapital.com/free-stock-market-resources/") + print("") + + +def menu(): + """Resource Collection Menu""" + + rc_controller = ResourceCollectionController() + rc_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 rc_controller.CHOICES} + ) + an_input = session.prompt( + f"{get_flair()} (rc)> ", + completer=completer, + ) + else: + an_input = input(f"{get_flair()} (rc)> ") + + try: + process_input = rc_controller.switch(an_input) + + if process_input is not None: + return process_input + + except SystemExit: + print("The command selected doesn't exist\n") + continue diff --git a/images/gst_logo.png b/images/gst_logo.png new file mode 100644 index 00000000000..dbb05e0d2b5 Binary files /dev/null and b/images/gst_logo.png differ diff --git a/images/gst_logo_rGreen.png b/images/gst_logo_rGreen.png new file mode 100644 index 00000000000..c33253803a1 Binary files /dev/null and b/images/gst_logo_rGreen.png differ diff --git a/terminal.py b/terminal.py index 6765b0f68f5..69e6e6f5919 100644 --- a/terminal.py +++ b/terminal.py @@ -13,12 +13,19 @@ from prompt_toolkit.completion import NestedCompleter from gamestonk_terminal import config_terminal as cfg from gamestonk_terminal import feature_flags as gtff 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_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.main_helper import ( + clear, + export, + load, + print_help, + view, + candle, + print_goodbye, +) from gamestonk_terminal.menu import session from gamestonk_terminal.papermill import papermill_controller as mill from gamestonk_terminal.behavioural_analysis import ba_controller @@ -34,6 +41,8 @@ from gamestonk_terminal.screener import screener_controller from gamestonk_terminal.portfolio_optimization import po_controller from gamestonk_terminal.forex import fx_controller from gamestonk_terminal.backtesting import bt_controller +from gamestonk_terminal.resource_collection import rc_controller +from gamestonk_terminal.research import res_controller # pylint: disable=too-many-statements,too-many-branches @@ -47,7 +56,7 @@ def main(): os.system("") s_ticker = "" - s_start = "" + s_start = "2015-01-01" df_stock = pd.DataFrame() s_interval = "1440min" @@ -89,6 +98,7 @@ def main(): "ra", "po", "fx", + "rc", ] menu_parser.add_argument("opt", choices=choices) @@ -102,7 +112,7 @@ def main(): print(e, "\n") # Print first welcome message and help - print("\nWelcome to Gamestonk Terminal 🚀\n") + print("\nWelcome to Gamestonk Terminal Ape.\n") should_print_help = True parsed_stdin = False @@ -211,7 +221,7 @@ def main(): ) elif ns_known_args.opt == "res": - b_quit = rm.res_menu( + b_quit = res_controller.menu( s_ticker.split(".")[0] if "." in s_ticker else s_ticker, s_start, s_interval, @@ -365,6 +375,9 @@ def main(): s_ticker.split(".")[0] if "." in s_ticker else s_ticker, s_start ) + elif ns_known_args.opt == "rc": + b_quit = rc_controller.menu() + else: print("Shouldn't see this command!") continue @@ -375,9 +388,7 @@ def main(): if not main_cmd: should_print_help = True - print( - "Hope you enjoyed the terminal. Remember that stonks only go up. Diamond hands.\n" - ) + print_goodbye() if __name__ == "__main__": diff --git a/tests/test_fred_fred_view.py b/tests/test_fred_fred_view.py index 9187649de93..a24db3fd0a2 100644 --- a/tests/test_fred_fred_view.py +++ b/tests/test_fred_fred_view.py @@ -5,7 +5,7 @@ from io import StringIO import pandas as pd # pylint: disable=unused-import -from gamestonk_terminal.econ.fred_view import get_fred_data # noqa: F401 +from gamestonk_terminal.econ.fred_view import display_fred # noqa: F401 fred_data_mock = """ ,GDP @@ -17,14 +17,15 @@ fred_data_mock = """ 2020-04-01,19520.114 2020-07-01,21170.252 2020-10-01,21494.731 +2021-01-01,22048.894 """ class TestFredFredView(unittest.TestCase): @mock.patch("gamestonk_terminal.econ.fred_view.Fred.get_series") - def test_get_fred_data(self, mock_get_series): + def test_display_fred(self, mock_get_series): fred_data = pd.read_csv(StringIO(fred_data_mock), header=0, index_col=0) mock_get_series.return_value = fred_data - get_fred_data(["--noplot"], "gdp") + display_fred(["-t"], "gdp")