mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
@@ -141,13 +141,12 @@
|
||||
## Portfolio Analysis
|
||||
|
||||
### Short term
|
||||
* [ ] Add Brokers (td, alpaca, webull, etc)
|
||||
* [ ] Merge data from different brokers
|
||||
* [ ] Refactor
|
||||
|
||||
- [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)
|
||||
- [ ] Add Brokers (td, alpaca, webull, etc) (@jmaslek)
|
||||
- [ ] Add Brokers (td, webull, etc) (@jmaslek)
|
||||
- [ ] Merge data from different brokers (@jmaslek)
|
||||
- [ ] Refactoring
|
||||
|
||||
### Long term
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ This page shows the available brokers for loading in data. If yours is not list
|
||||
|
||||
Current brokers:
|
||||
* Robinhood
|
||||
* Alpaca
|
||||
|
||||
|
||||
Once this screen is accessed, the first command to be run is
|
||||
@@ -15,31 +16,40 @@ The brokers should just be your brokers from the list shown on the first menu.
|
||||
````
|
||||
login rh
|
||||
````
|
||||
When td is added, the command will be
|
||||
To login to both robinhood and alpaca:
|
||||
````
|
||||
login rh td
|
||||
login rh alp
|
||||
````
|
||||
After logging in, the help menu will display which brokers you logged into.
|
||||
|
||||
Your login information should be stored as environment variables in [config file](/gamestonk_terminal/config_terminal.py)
|
||||
|
||||
Robinhood has Two Factor Authentication, so you will likely be prompted to enter a code that is texted/emailed to you.
|
||||
###NOTE THAT LOGGING IN WILL SAVE A TOKEN TO `os.path.expanduser("~")/.tokens` WHICH CAN BE USED TO LOGIN EVEN IF USER CREDENTIALS ARE INCORRECT.
|
||||
Your login information should be stored as environment variables in [config file](/gamestonk_terminal/config_terminal.py), but check each individual section for specifics.
|
||||
|
||||
[ROBINHOOD](#ROBINHOOD)
|
||||
* [hold](#hold)
|
||||
* [rhhold](#rhhold)
|
||||
* Look at current (stock only) holdings
|
||||
* [rhhist](#rhhist)
|
||||
* Get and plot historical portfolio
|
||||
|
||||
[ALPACA](#ALPACA)
|
||||
* [alphold](#alphold)
|
||||
* Look at current (stock only) holdings
|
||||
* [alphist](#rhhist)
|
||||
* Get and plot historical portfolio
|
||||
|
||||
## ROBINHOOD <a name="ROBINHOOD"></a>
|
||||
Robinhood has Two Factor Authentication, so you will likely be prompted to enter a code that is texted/emailed to you.
|
||||
###NOTE THAT LOGGING IN WILL SAVE A TOKEN TO `os.path.expanduser("~")/.tokens` WHICH CAN BE USED TO LOGIN EVEN IF USER CREDENTIALS ARE INCORRECT.
|
||||
|
||||
### hold <a name="hold"></a>
|
||||
In order to login, the [config file](/gamestonk_terminal/config_terminal.py) requires two variables:
|
||||
* "GT_RH_USERNAME"
|
||||
* "GT_RH_PASSWORD"
|
||||
|
||||
### rhhold <a name="rhhold"></a>
|
||||
|
||||
Displays current holdings to the console:
|
||||
|
||||
````
|
||||
usage: hold
|
||||
usage: rhhold
|
||||
````
|
||||
There are no additional flags. This just prints all current stonks, their last price, previous close, your equity and
|
||||
the % change from previous close.
|
||||
@@ -60,4 +70,39 @@ usage: rhhist [-s --span] [-i --interval]
|
||||
|
||||
Example Default Output:
|
||||
|
||||

|
||||

|
||||
## ALPACA <a name="ALPACA"></a>
|
||||
|
||||
Alpaca has a nicely maintained python API that is used here. To login, the best approach is to just save the following environment variables:
|
||||
* "APCA_API_BASE_URL"
|
||||
* "APCA_API_KEY_ID"
|
||||
* "APCA_API_SECRET_KEY"
|
||||
|
||||
If these are defined, then the login command does not explicitly need to be run, but the login command verifies all those keys are defined.
|
||||
|
||||
Note that alpaca does support paper trading, so if your base_url is "https://paper-api.alpaca.markets", then this will be importing
|
||||
your paper trading account.
|
||||
|
||||
### alphold <a name="alphold"></a>
|
||||
|
||||
Displays current holdings to the console. Same as rhhold
|
||||
|
||||
````
|
||||
usage: alphold
|
||||
````
|
||||
There are no additional flags. This just prints all current stonks, their last price, previous close, your equity and
|
||||
the % change from previous close.
|
||||
|
||||
Example Output:
|
||||

|
||||
|
||||
### alphist <a name="alphist"></a>
|
||||
Plots historical portfolio. The output plot in this case will not be a candle, as the api provides your equity at a gven time,
|
||||
unlike the robin_stocks, which gives high/low at a given time.
|
||||
|
||||
````
|
||||
usage: alphist [-p --period] [-t --timeframe]
|
||||
````
|
||||
|
||||
* -p/--period The duration of the data in \<number> + \<unit>, such as 1D, where <unit> can be D for day, W for week, M for month and A for year. Defaults to 1M
|
||||
* -t/--timeframe The resolution of time window. 1Min, 5Min, 15Min, 1H, or 1D. If omitted, 1Min for less than 7 days period, 15Min for less than 30 days, or otherwise 1D.
|
||||
|
||||
97
gamestonk_terminal/portfolio/alp_api.py
Normal file
97
gamestonk_terminal/portfolio/alp_api.py
Normal file
@@ -0,0 +1,97 @@
|
||||
import argparse
|
||||
import os
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
import matplotlib.pyplot as plt
|
||||
import alpaca_trade_api as alp_api
|
||||
from termcolor import colored
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
parse_known_args_and_warn,
|
||||
plot_autoscale,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
register_matplotlib_converters()
|
||||
|
||||
|
||||
def login():
|
||||
|
||||
if not (
|
||||
os.getenv("APCA_API_KEY_ID")
|
||||
and os.getenv("APCA_API_SECRET_KEY")
|
||||
and os.getenv("APCA_API_BASE_URL")
|
||||
):
|
||||
raise ValueError("Alpaca Keys not defined in env")
|
||||
|
||||
|
||||
def show_holdings():
|
||||
api = alp_api.REST()
|
||||
positions = api.list_positions()
|
||||
print("")
|
||||
print("Stonk\t last price \t prev close \t equity \t % Change")
|
||||
|
||||
for pos in positions:
|
||||
stonk = pos.symbol
|
||||
last_price = round(float(pos.current_price), 2)
|
||||
prev_close = round(float(pos.lastday_price), 2)
|
||||
eq = round(float(pos.market_value), 2)
|
||||
pct_change = round(float(pos.change_today), 3)
|
||||
to_print = f"{stonk}\t {last_price}\t\t {prev_close}\t\t {eq}\t\t {pct_change}"
|
||||
if pct_change >= 0:
|
||||
print(colored(to_print, "green"))
|
||||
else:
|
||||
print(colored(to_print, "red"))
|
||||
print("")
|
||||
|
||||
|
||||
def plot_historical(l_args):
|
||||
api = alp_api.REST()
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="Port",
|
||||
description="""
|
||||
Historical Portfolio Info
|
||||
""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--period",
|
||||
dest="period",
|
||||
type=str,
|
||||
default="1M",
|
||||
help="Duration of data (<number> + <unit>)",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--timeframe",
|
||||
dest="timeframe",
|
||||
default="1D",
|
||||
type=str,
|
||||
help="Resolution of data (<number> + <unit>)",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, l_args)
|
||||
port_hist = api.get_portfolio_history(
|
||||
period=ns_parser.period, timeframe=ns_parser.timeframe
|
||||
).df
|
||||
|
||||
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
plt.plot(port_hist.index, port_hist.equity)
|
||||
plt.xlim(port_hist.index[0], port_hist.index[-1])
|
||||
plt.ylabel("Equity")
|
||||
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.show()
|
||||
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
@@ -6,33 +6,25 @@ 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.portfolio import rh_api
|
||||
from gamestonk_terminal.portfolio import rh_api, alp_api
|
||||
|
||||
|
||||
class PortfolioController:
|
||||
|
||||
CHOICES = [
|
||||
"help",
|
||||
"q",
|
||||
"quit",
|
||||
"login",
|
||||
"hold",
|
||||
"rhhist",
|
||||
]
|
||||
CHOICES = ["help", "q", "quit", "login", "rhhold", "rhhist", "alphold", "alphist"]
|
||||
|
||||
BROKERS = [
|
||||
"rh",
|
||||
"alp",
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
self.port_parser = argparse.ArgumentParser(add_help=False, prog="port")
|
||||
self.port_parser.add_argument("cmd", choices=self.CHOICES)
|
||||
self.brokers_list = set()
|
||||
self.broker_list = set()
|
||||
|
||||
@staticmethod
|
||||
def print_help(broker_list):
|
||||
if not broker_list:
|
||||
broker_list = [" None"]
|
||||
|
||||
""" Print help """
|
||||
print("\nPortfolio:")
|
||||
@@ -42,24 +34,33 @@ class PortfolioController:
|
||||
)
|
||||
print(" quit quit to abandon program, logs out of brokers")
|
||||
print(" login login to your brokers")
|
||||
print(f"\nCurrent Brokers : {('', ', '.join(broker_list))[bool(broker_list)]}")
|
||||
print(
|
||||
f"\nCurrent Brokers : {('None', ', '.join(broker_list))[bool(broker_list)]}"
|
||||
)
|
||||
print("\nCurrently Supported :")
|
||||
print(" rh Robinhood - fuck these guys")
|
||||
print(" alp Alpaca ")
|
||||
print("\nCommands (login required):")
|
||||
print("")
|
||||
print(" hold view rh holdings")
|
||||
print("\nRobinhood:")
|
||||
print(" rhhold view rh holdings")
|
||||
print(" rhhist plot rh portfolio history")
|
||||
print("\nAlpaca:")
|
||||
print(" alphold view alp holdings")
|
||||
print(" alphist view alp portfolio history")
|
||||
print("")
|
||||
|
||||
def print_portfolio_menu(self):
|
||||
|
||||
print_broke = " "
|
||||
for broker in self.brokers_list:
|
||||
print_broke += broker + " "
|
||||
print("\nCurrent Brokers :" + print_broke)
|
||||
print("")
|
||||
print(" hold check holdings")
|
||||
print(
|
||||
f"\nCurrent Brokers : {('None', ', '.join(self.broker_list))[bool(self.broker_list)]}"
|
||||
)
|
||||
print("\nRobinhood:")
|
||||
print(" rhhold check holdings")
|
||||
print(" rhhist plot historical RH portfolio")
|
||||
print("\nAlpaca:")
|
||||
print(" alphold view alpaca holdings")
|
||||
print(" alphist plot historical alpaca portfolio")
|
||||
|
||||
print("")
|
||||
|
||||
def switch(self, an_input: str):
|
||||
@@ -80,7 +81,7 @@ class PortfolioController:
|
||||
|
||||
def call_help(self, _):
|
||||
"""Process Help command"""
|
||||
self.print_help(self.brokers_list)
|
||||
self.print_help(self.broker_list)
|
||||
|
||||
def call_q(self, _):
|
||||
"""Process Q command - quit the menu"""
|
||||
@@ -102,7 +103,7 @@ class PortfolioController:
|
||||
api = broker + "_api"
|
||||
try:
|
||||
eval(api + ".login()")
|
||||
self.brokers_list.add(broker)
|
||||
self.broker_list.add(broker)
|
||||
logged_in = True
|
||||
except Exception as e:
|
||||
print("")
|
||||
@@ -119,19 +120,29 @@ class PortfolioController:
|
||||
def call_rhhist(self, other_args: List[str]):
|
||||
rh_api.plot_historical(other_args)
|
||||
|
||||
def call_hold(self, _):
|
||||
def call_rhhold(self, _):
|
||||
try:
|
||||
rh_api.show_holdings()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
|
||||
def call_alphold(self, _):
|
||||
try:
|
||||
alp_api.show_holdings()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
|
||||
def call_alphist(self, other_args: List[str]):
|
||||
alp_api.plot_historical(other_args)
|
||||
|
||||
|
||||
def menu():
|
||||
"""Portfolio Analysis Menu"""
|
||||
|
||||
port_controller = PortfolioController()
|
||||
port_controller.print_help(port_controller.brokers_list)
|
||||
port_controller.print_help(port_controller.broker_list)
|
||||
|
||||
while True:
|
||||
# Get input command from user
|
||||
|
||||
Reference in New Issue
Block a user