mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Merge branch 'develop' into feature/openbb-sdk-v4
This commit is contained in:
4
README.md
vendored
4
README.md
vendored
@@ -135,7 +135,9 @@ Any of our social media platforms: [openbb.co/links](https://openbb.co/links)
|
||||
|
||||
## 6. Star History
|
||||
|
||||
This is a proxy of our growth and that we are just getting started. But for more metrics important to us check [openbb.co/open](https://openbb.co/open).
|
||||
This is a proxy of our growth and that we are just getting started.
|
||||
|
||||
But for more metrics important to us check [openbb.co/open](https://openbb.co/open).
|
||||
|
||||
[](https://star-history.com/#openbb-finance/OpenBBTerminal&Date)
|
||||
|
||||
|
||||
2
build/docker/compose.env
vendored
2
build/docker/compose.env
vendored
@@ -1,2 +1,2 @@
|
||||
OPENBBTERMINAL_DOCKER_REGISTRY="ghcr.io"
|
||||
OPENBBTERMINAL_DOCKER_RELEASE_VERSION="3.2.0"
|
||||
OPENBBTERMINAL_DOCKER_RELEASE_VERSION="3.2.1"
|
||||
|
||||
6
build/nsis/setup.nsi
vendored
6
build/nsis/setup.nsi
vendored
@@ -10,7 +10,7 @@
|
||||
!define NAME "OpenBB Terminal"
|
||||
!define COMPANY "OpenBB"
|
||||
!define APPFILE "OpenBBTerminal.exe"
|
||||
!define VERSION "3.2.0"
|
||||
!define VERSION "3.2.1"
|
||||
!define SLUG "${NAME} v${VERSION}"
|
||||
|
||||
;--------------------------------
|
||||
@@ -20,8 +20,8 @@
|
||||
VIAddVersionKey Comments "An installer for OpenBB Terminal. For additional details, visit OpenBB.co"
|
||||
VIAddVersionKey CompanyName OpenBB.co
|
||||
VIAddVersionKey FileDescription "OpenBB Terminal Program"
|
||||
VIAddVersionKey FileVersion 3.2.0.0
|
||||
VIAddVersionKey ProductVersion 3.2.0.0
|
||||
VIAddVersionKey FileVersion 3.2.1.0
|
||||
VIAddVersionKey ProductVersion 3.2.1.0
|
||||
VIAddVersionKey InternalName "OpenBB Terminal"
|
||||
|
||||
;--------------------------------
|
||||
|
||||
4
build/pyinstaller/version.rc
vendored
4
build/pyinstaller/version.rc
vendored
@@ -32,10 +32,10 @@ VSVersionInfo(
|
||||
[StringStruct('Comments', 'The OpenBB Terminal. For additional details, visit OpenBB.co'),
|
||||
StringStruct('CompanyName', 'OpenBB'),
|
||||
StringStruct('FileDescription', 'OpenBB Terminal Program'),
|
||||
StringStruct('FileVersion', '3.2.0.0'),
|
||||
StringStruct('FileVersion', '3.2.1.0'),
|
||||
StringStruct('InternalName', 'OpenBB Terminal'),
|
||||
StringStruct('ProductName', 'OpenBB Terminal'),
|
||||
StringStruct('ProductVersion', '3.2.0.0')])
|
||||
StringStruct('ProductVersion', '3.2.1.0')])
|
||||
]),
|
||||
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
||||
]
|
||||
|
||||
@@ -255,6 +255,7 @@ class AccountController(BaseController):
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
page=ns_parser.page,
|
||||
size=ns_parser.size,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
df, page, pages = get_personal_routines_info(response)
|
||||
if not df.empty:
|
||||
@@ -356,6 +357,7 @@ class AccountController(BaseController):
|
||||
"routine": routine,
|
||||
"tags": tags,
|
||||
"public": ns_parser.public,
|
||||
"base_url": Hub.BackendEnvironment.BASE_URL,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
|
||||
@@ -412,6 +414,7 @@ class AccountController(BaseController):
|
||||
response = Hub.download_routine(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
uuid=self.REMOTE_CHOICES[name],
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
data = [response.json(), "personal"]
|
||||
@@ -499,6 +502,7 @@ class AccountController(BaseController):
|
||||
response = Hub.delete_routine(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
uuid=self.REMOTE_CHOICES[name],
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
if (
|
||||
response
|
||||
@@ -551,6 +555,7 @@ class AccountController(BaseController):
|
||||
|
||||
response = Hub.generate_personal_access_token(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
days=ns_parser.days,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Reddit View."""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import textwrap
|
||||
@@ -212,10 +213,10 @@ def display_wsb_community(limit: int = 10, new: bool = False):
|
||||
Flag to sort by new instead of hot, by default False
|
||||
"""
|
||||
subs = reddit_model.get_wsb_community(limit, new)
|
||||
# I am not proud of this, but it works to eliminate the max recursion bug
|
||||
subs = pd.read_csv(io.StringIO(subs.to_csv()), index_col=0).fillna("-")
|
||||
if not subs.empty:
|
||||
# for sub in subs.iterrows():
|
||||
# print_reddit_post(sub)
|
||||
print(print_rich_table(subs))
|
||||
print_rich_table(subs)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
|
||||
@@ -18,7 +18,7 @@ from openbb_terminal.rich_config import console
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
BASE_URL = "https://api.ultimainsights.ai/v1"
|
||||
ULTIMA_BASE_URL = "https://api.ultimainsights.ai/v1"
|
||||
NO_API_KEY = "REPLACE_ME"
|
||||
|
||||
|
||||
@@ -69,10 +69,10 @@ def get_news(term: str = "", sort: str = "articlePublishedDate") -> pd.DataFrame
|
||||
if term in supported_terms():
|
||||
if auth_header:
|
||||
data = request(
|
||||
f"{BASE_URL}/getNewsArticles/{term}", headers=auth_header
|
||||
f"{ULTIMA_BASE_URL}/getNewsArticles/{term}", headers=auth_header
|
||||
)
|
||||
else:
|
||||
data = request(f"{BASE_URL}/getNewsArticles/{term}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getNewsArticles/{term}")
|
||||
else:
|
||||
console.print(
|
||||
"[red]Ticker not supported. Unable to retrieve data\n[/red]"
|
||||
@@ -150,7 +150,7 @@ def supported_terms() -> list:
|
||||
# https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error/73270162#73270162
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
|
||||
os.environ["SSL_CERT_FILE"] = certifi.where()
|
||||
data = request(f"{BASE_URL}/supportedTickers")
|
||||
data = request(f"{ULTIMA_BASE_URL}/supportedTickers")
|
||||
return list(data.json())
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ def get_company_info(ticker: str) -> dict:
|
||||
os.environ["SSL_CERT_FILE"] = certifi.where()
|
||||
|
||||
if ticker in supported_terms():
|
||||
data = request(f"{BASE_URL}/getCompanyInfo/{ticker}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getCompanyInfo/{ticker}")
|
||||
return data.json()
|
||||
console.print("[red]Ticker not supported. Unable to retrieve data\n[/red]")
|
||||
return {}
|
||||
@@ -213,9 +213,11 @@ def get_top_headlines(ticker: str) -> dict:
|
||||
|
||||
if ticker in supported_terms():
|
||||
if auth_header:
|
||||
data = request(f"{BASE_URL}/getTopHeadlines/{ticker}", headers=auth_header)
|
||||
data = request(
|
||||
f"{ULTIMA_BASE_URL}/getTopHeadlines/{ticker}", headers=auth_header
|
||||
)
|
||||
else:
|
||||
data = request(f"{BASE_URL}/getTopHeadlines/{ticker}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getTopHeadlines/{ticker}")
|
||||
if (
|
||||
hasattr(data, "status") and data.status_code == 429
|
||||
): # If data request failed
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from argparse import ArgumentParser
|
||||
from contextlib import contextmanager
|
||||
from inspect import isfunction, unwrap
|
||||
from os import environ
|
||||
from types import MethodType
|
||||
from typing import Callable, List
|
||||
from unittest.mock import patch
|
||||
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.helper_funcs import check_file_type_saved, check_positive
|
||||
from openbb_terminal.rich_config import get_ordered_list_sources
|
||||
|
||||
@@ -211,7 +211,7 @@ def __patch_controller_functions(controller):
|
||||
),
|
||||
]
|
||||
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
rich.start()
|
||||
patched_function_list = []
|
||||
for patcher in patcher_list:
|
||||
@@ -219,7 +219,7 @@ def __patch_controller_functions(controller):
|
||||
|
||||
yield patched_function_list
|
||||
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
rich.stop()
|
||||
for patcher in patcher_list:
|
||||
patcher.stop()
|
||||
@@ -317,7 +317,7 @@ def build_controller_choice_map(controller) -> dict:
|
||||
argument_parser=argument_parser
|
||||
)
|
||||
except Exception as exception:
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() == "true":
|
||||
if get_current_system().DEBUG_MODE:
|
||||
raise Exception(
|
||||
f"On command : `{command}`.\n{str(exception)}"
|
||||
) from exception
|
||||
|
||||
@@ -28,7 +28,7 @@ class SystemModel(BaseModel):
|
||||
PLATFORM: str = str(platform.platform())
|
||||
|
||||
# OpenBB section
|
||||
VERSION: str = "3.2.0"
|
||||
VERSION: str = "3.2.1"
|
||||
|
||||
# Logging section
|
||||
LOGGING_APP_ID: str = "REPLACE_ME"
|
||||
@@ -54,6 +54,7 @@ class SystemModel(BaseModel):
|
||||
# Others
|
||||
TEST_MODE: bool = False
|
||||
DEBUG_MODE: bool = False
|
||||
DEV_BACKEND: bool = False
|
||||
ENABLE_AUTHENTICATION: bool = True
|
||||
HEADLESS: bool = False
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import plotly.graph_objects as go
|
||||
from packaging import version
|
||||
from reportlab.graphics import renderPDF
|
||||
|
||||
# pylint: disable=C0415
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
|
||||
# pylint: disable=C0411,C0412,C0415
|
||||
try:
|
||||
from pywry import PyWry
|
||||
except ImportError as e:
|
||||
@@ -441,8 +443,10 @@ class Backend(PyWry):
|
||||
self.check_backend()
|
||||
endpoint = {True: "login", False: "logout"}[login]
|
||||
|
||||
json_url = f"{BackendEnvironment.HUB_URL}{endpoint}?pywry=true"
|
||||
|
||||
outgoing = dict(
|
||||
json_data=dict(url=f"https://my.openbb.co/{endpoint}?pywry=true"),
|
||||
json_data=dict(url=json_url),
|
||||
**self.get_kwargs(endpoint.title()),
|
||||
width=900,
|
||||
height=800,
|
||||
|
||||
@@ -59,7 +59,6 @@ class StocksController(model.StocksRoot):
|
||||
`sentiment_chart`: Plots sentiments from symbol\n
|
||||
`snews`: Get headlines sentiment using VADER model over time. [Source: Finnhub]\n
|
||||
`snews_chart`: Display stock price and headlines sentiment using VADER model over time. [Source: Finnhub]\n
|
||||
`spacc`: Get top tickers from r/SPACs [Source: reddit].\n
|
||||
`stalker`: Gets messages from given user [Source: stocktwits].\n
|
||||
`text_sent`: Find the sentiment of a post and related comments.\n
|
||||
`trending`: Get trending tickers from stocktwits [Source: stocktwits].\n
|
||||
|
||||
@@ -59,7 +59,6 @@ class StocksBehavioralAnalysis(Category):
|
||||
`sentiment_chart`: Plots sentiments from symbol\n
|
||||
`snews`: Get headlines sentiment using VADER model over time. [Source: Finnhub]\n
|
||||
`snews_chart`: Display stock price and headlines sentiment using VADER model over time. [Source: Finnhub]\n
|
||||
`spacc`: Get top tickers from r/SPACs [Source: reddit].\n
|
||||
`stalker`: Gets messages from given user [Source: stocktwits].\n
|
||||
`text_sent`: Find the sentiment of a post and related comments.\n
|
||||
`trending`: Get trending tickers from stocktwits [Source: stocktwits].\n
|
||||
@@ -94,7 +93,6 @@ class StocksBehavioralAnalysis(Category):
|
||||
self.snews_chart = (
|
||||
lib.stocks_ba_finnhub_view.display_stock_price_headlines_sentiment
|
||||
)
|
||||
self.spacc = lib.stocks_ba_reddit_model.get_spac_community
|
||||
self.stalker = lib.stocks_ba_stocktwits_model.get_stalker
|
||||
self.text_sent = lib.stocks_ba_reddit_model.get_sentiment
|
||||
self.trending = lib.stocks_ba_stocktwits_model.get_trending
|
||||
|
||||
1
openbb_terminal/core/sdk/trail_map.csv
vendored
1
openbb_terminal/core/sdk/trail_map.csv
vendored
@@ -400,7 +400,6 @@ stocks.ba.regions,stocks_ba_google_model.get_regions,stocks_ba_google_view.displ
|
||||
stocks.ba.rise,stocks_ba_google_model.get_rise,
|
||||
stocks.ba.sentiment,stocks_ba_twitter_model.get_sentiment,stocks_ba_twitter_view.display_sentiment
|
||||
stocks.ba.snews,stocks_ba_finnhub_model.get_headlines_sentiment,stocks_ba_finnhub_view.display_stock_price_headlines_sentiment
|
||||
stocks.ba.spacc,stocks_ba_reddit_model.get_spac_community,
|
||||
stocks.ba.stalker,stocks_ba_stocktwits_model.get_stalker,
|
||||
stocks.ba.text_sent,stocks_ba_reddit_model.get_sentiment,
|
||||
stocks.ba.trending,stocks_ba_stocktwits_model.get_trending,
|
||||
|
||||
|
@@ -1,13 +1,16 @@
|
||||
BASE_URL = "https://payments.openbb.co/"
|
||||
# BASE_URL = "http://127.0.0.1:8000/"
|
||||
class HubEnvironment:
|
||||
# BASE_URL = "http://127.0.0.1:8000/"
|
||||
BASE_URL = "https://payments.openbb.co/"
|
||||
HUB_URL = "https://my.openbb.co/"
|
||||
|
||||
HUB_URL = "https://my.openbb.co/"
|
||||
REGISTER_URL = HUB_URL + "register"
|
||||
SUPPORT_URL = HUB_URL + "app/terminal/support"
|
||||
SOURCES_URL = HUB_URL + "app/terminal/data-sources"
|
||||
KEYS_URL = HUB_URL + "app/terminal/api-keys"
|
||||
COLORS_URL = HUB_URL + "app/terminal/theme"
|
||||
CHARTS_TABLES_URL = HUB_URL + "app/terminal/theme/charts-tables"
|
||||
def __new__(cls, *args, **kwargs): # pylint: disable=W0613
|
||||
"""Create a singleton instance of the backend."""
|
||||
if not hasattr(cls, "instance"):
|
||||
cls.instance = super().__new__(cls) # pylint: disable=E1120
|
||||
return cls.instance
|
||||
|
||||
|
||||
BackendEnvironment = HubEnvironment()
|
||||
|
||||
DEFAULT_ROUTINES_URL = "https://openbb-cms.directus.app/items/Routines"
|
||||
|
||||
|
||||
@@ -7,18 +7,22 @@ import requests
|
||||
from jose import jwt
|
||||
|
||||
from openbb_terminal.core.session.constants import (
|
||||
BASE_URL,
|
||||
CONNECTION_ERROR_MSG,
|
||||
CONNECTION_TIMEOUT_MSG,
|
||||
DEFAULT_ROUTINES_URL,
|
||||
TIMEOUT,
|
||||
BackendEnvironment,
|
||||
)
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.current_user import get_current_user
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
|
||||
def create_session(
|
||||
email: str, password: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
email: str,
|
||||
password: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Create a session.
|
||||
|
||||
@@ -71,7 +75,7 @@ def check_token_expiration(token: str):
|
||||
|
||||
|
||||
def create_session_from_token(
|
||||
token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
token: str, base_url: str = BackendEnvironment.BASE_URL, timeout: int = TIMEOUT
|
||||
):
|
||||
"""Create a session from token.
|
||||
|
||||
@@ -108,7 +112,10 @@ def create_session_from_token(
|
||||
|
||||
|
||||
def delete_session(
|
||||
auth_header: str, token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
token: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Delete the session.
|
||||
|
||||
@@ -190,7 +197,7 @@ def get_session(email: str, password: str) -> dict:
|
||||
dict
|
||||
The session info.
|
||||
"""
|
||||
response = create_session(email, password)
|
||||
response = create_session(email, password, base_url=BackendEnvironment.BASE_URL)
|
||||
if response is None:
|
||||
return {}
|
||||
return process_session_response(response)
|
||||
@@ -209,14 +216,14 @@ def get_session_from_token(token: str) -> dict:
|
||||
dict
|
||||
The session info.
|
||||
"""
|
||||
response = create_session_from_token(token)
|
||||
response = create_session_from_token(token, base_url=BackendEnvironment.BASE_URL)
|
||||
if response is None:
|
||||
return {}
|
||||
return process_session_response(response)
|
||||
|
||||
|
||||
def fetch_user_configs(
|
||||
session: dict, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
session: dict, base_url: str = BackendEnvironment.BASE_URL, timeout: int = TIMEOUT
|
||||
) -> Optional[requests.Response]:
|
||||
"""Fetch user configurations.
|
||||
|
||||
@@ -258,7 +265,10 @@ def fetch_user_configs(
|
||||
|
||||
|
||||
def clear_user_configs(
|
||||
config: str, auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
config: str,
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Clear user configurations to the server.
|
||||
|
||||
@@ -307,7 +317,7 @@ def upload_user_field(
|
||||
key: str,
|
||||
value: Any,
|
||||
auth_header: str,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
silent: bool = False,
|
||||
) -> Optional[requests.Response]:
|
||||
@@ -365,7 +375,7 @@ def upload_config(
|
||||
value: str,
|
||||
type_: Literal["settings", "terminal_style"],
|
||||
auth_header: str,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Patch user configurations to the server.
|
||||
@@ -429,7 +439,7 @@ def upload_routine(
|
||||
override: bool = False,
|
||||
tags: str = "",
|
||||
public: bool = False,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Send a routine to the server.
|
||||
@@ -467,7 +477,6 @@ def upload_routine(
|
||||
"version": get_current_system().VERSION,
|
||||
"public": public,
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
headers={"Authorization": auth_header},
|
||||
@@ -476,7 +485,21 @@ def upload_routine(
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
console.print("[green]Successfully uploaded your routine.[/green]")
|
||||
username = get_current_user().profile.username
|
||||
console.print("[green]Successfully uploaded your routine.[/]")
|
||||
|
||||
run_env = BackendEnvironment.HUB_URL.rstrip("/")
|
||||
|
||||
if public:
|
||||
console.print(
|
||||
f"\n[yellow]Share or edit it at {run_env}/u/{username}/routine/{name.replace(' ', '-')}[/]"
|
||||
)
|
||||
else:
|
||||
console.print(f"\n[yellow]Go to {run_env} to edit this script,[/]")
|
||||
console.print(
|
||||
f"[yellow]or even make it public so you can access it at "
|
||||
f"{run_env}/u/{username}/routine/{name.replace(' ', '-')}[/]"
|
||||
)
|
||||
elif response.status_code != 409: # 409: routine already exists
|
||||
console.print(
|
||||
"[red]" + response.json().get("detail", "Unknown error.") + "[/red]"
|
||||
@@ -496,7 +519,7 @@ def upload_routine(
|
||||
def download_routine(
|
||||
auth_header: str,
|
||||
uuid: UUID,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Download a routine from the server.
|
||||
@@ -520,7 +543,7 @@ def download_routine(
|
||||
try:
|
||||
response = requests.get(
|
||||
headers={"Authorization": auth_header},
|
||||
url=base_url + "terminal/script/" + uuid,
|
||||
url=base_url + "terminal/script/" + uuid, # type: ignore
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 404:
|
||||
@@ -542,7 +565,7 @@ def download_routine(
|
||||
def delete_routine(
|
||||
auth_header: str,
|
||||
uuid: UUID,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Delete a routine from the server.
|
||||
@@ -566,7 +589,7 @@ def delete_routine(
|
||||
try:
|
||||
response = requests.delete(
|
||||
headers={"Authorization": auth_header},
|
||||
url=base_url + "terminal/script/" + uuid,
|
||||
url=base_url + "terminal/script/" + uuid, # type: ignore
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
@@ -592,7 +615,7 @@ def list_routines(
|
||||
fields: Optional[List[str]] = None,
|
||||
page: int = 1,
|
||||
size: int = 10,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
silent: bool = False,
|
||||
) -> Optional[requests.Response]:
|
||||
@@ -683,7 +706,10 @@ def get_default_routines(
|
||||
|
||||
|
||||
def generate_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT, days: int = 30
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
days: int = 30,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Generate an OpenBB Personal Access Token.
|
||||
@@ -732,7 +758,9 @@ def generate_personal_access_token(
|
||||
|
||||
|
||||
def get_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Show the user's OpenBB Personal Access Token.
|
||||
@@ -777,7 +805,9 @@ def get_personal_access_token(
|
||||
|
||||
|
||||
def revoke_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Delete the user's OpenBB Personal Access Token.
|
||||
|
||||
@@ -51,6 +51,7 @@ def download_routines(auth_header: str, silent: bool = False) -> list:
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
silent=silent,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
|
||||
@@ -5,11 +5,11 @@ from prompt_toolkit import PromptSession
|
||||
import openbb_terminal.core.session.local_model as Local
|
||||
from openbb_terminal.core.config.paths import PACKAGE_DIRECTORY
|
||||
from openbb_terminal.core.plots.backend import plots_backend
|
||||
from openbb_terminal.core.session.constants import (
|
||||
REGISTER_URL,
|
||||
SUPPORT_URL,
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_system import (
|
||||
get_current_system,
|
||||
set_system_variable,
|
||||
)
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.session_model import (
|
||||
LoginStatus,
|
||||
create_session,
|
||||
@@ -24,8 +24,12 @@ def display_welcome_message(links: bool = True) -> None:
|
||||
with open(PACKAGE_DIRECTORY / "core" / "session" / "banner.txt") as f:
|
||||
console.print(f"[menu]{f.read()}[/menu]\n")
|
||||
if links:
|
||||
console.print(f"Register : [cmds]{REGISTER_URL}[/cmds]")
|
||||
console.print(f"Support : [cmds]{SUPPORT_URL}[/cmds]")
|
||||
console.print(
|
||||
f"Register : [cmds]{BackendEnvironment.HUB_URL + 'register'}[/cmds]"
|
||||
)
|
||||
console.print(
|
||||
f"Support : [cmds]{BackendEnvironment.HUB_URL + 'app/terminal/support'}[/cmds]"
|
||||
)
|
||||
|
||||
|
||||
def get_user_input() -> Tuple[str, str, bool]:
|
||||
@@ -135,13 +139,15 @@ def prompt_cli(welcome: bool = True):
|
||||
|
||||
|
||||
# pylint: disable=inconsistent-return-statements
|
||||
def launch_terminal(debug: bool = False, queue: Optional[List[str]] = None):
|
||||
def launch_terminal(
|
||||
debug: bool = False, dev: bool = False, queue: Optional[List[str]] = None
|
||||
):
|
||||
"""Launch terminal"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_terminal import terminal_controller
|
||||
|
||||
if queue:
|
||||
return terminal_controller.main(debug, queue, module="")
|
||||
return terminal_controller.main(debug, dev, queue, module="")
|
||||
|
||||
terminal_controller.parse_args_and_run()
|
||||
|
||||
@@ -170,8 +176,13 @@ def main(
|
||||
welcome: bool = True,
|
||||
prompt: bool = True,
|
||||
queue: Optional[List[str]] = None,
|
||||
dev: bool = False,
|
||||
):
|
||||
"""Main function"""
|
||||
if dev:
|
||||
set_system_variable("DEV_BACKEND", True)
|
||||
BackendEnvironment.BASE_URL = "https://payments.openbb.dev/"
|
||||
BackendEnvironment.HUB_URL = "https://my.openbb.dev/"
|
||||
|
||||
local_session = Local.get_session() if session is None else session
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ def login(session: Dict, remember: bool = False) -> LoginStatus:
|
||||
preferences=get_current_user().preferences,
|
||||
sources=SourcesModel(),
|
||||
)
|
||||
response = Hub.fetch_user_configs(session)
|
||||
response = Hub.fetch_user_configs(session, Hub.BackendEnvironment.BASE_URL)
|
||||
if response is not None:
|
||||
if response.status_code == 200:
|
||||
configs = json.loads(response.content)
|
||||
@@ -159,6 +159,7 @@ def update_backend_sources(auth_header, configs, silent: bool = True):
|
||||
key="features_sources",
|
||||
value=updated_sources,
|
||||
auth_header=auth_header,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
silent=silent,
|
||||
)
|
||||
except Exception:
|
||||
@@ -190,7 +191,7 @@ def logout(
|
||||
|
||||
success = True
|
||||
|
||||
r = Hub.delete_session(auth_header, token)
|
||||
r = Hub.delete_session(auth_header, token, base_url=Hub.BackendEnvironment.BASE_URL)
|
||||
if not r or r.status_code != 200:
|
||||
success = False
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ class EconometricsController(BaseController):
|
||||
"type",
|
||||
"desc",
|
||||
"corr",
|
||||
"season",
|
||||
"index",
|
||||
"clean",
|
||||
"add",
|
||||
@@ -165,7 +164,7 @@ class EconometricsController(BaseController):
|
||||
}
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["load"] = {
|
||||
"--file": {c: {} for c in self.DATA_FILES},
|
||||
"-f": "--file",
|
||||
@@ -188,9 +187,9 @@ class EconometricsController(BaseController):
|
||||
"granger",
|
||||
"coint",
|
||||
"corr",
|
||||
"season",
|
||||
"lag",
|
||||
"vif",
|
||||
"panel",
|
||||
]:
|
||||
choices[feature] = dict()
|
||||
|
||||
@@ -216,7 +215,6 @@ class EconometricsController(BaseController):
|
||||
"norm",
|
||||
"root",
|
||||
"coint",
|
||||
"season",
|
||||
"lag",
|
||||
"regressions",
|
||||
"ols",
|
||||
@@ -279,7 +277,6 @@ class EconometricsController(BaseController):
|
||||
mt.add_cmd("type", self.files)
|
||||
mt.add_cmd("desc", self.files)
|
||||
mt.add_cmd("corr", self.files)
|
||||
mt.add_cmd("season", self.files)
|
||||
mt.add_cmd("index", self.files)
|
||||
mt.add_cmd("clean", self.files)
|
||||
mt.add_cmd("add", self.files)
|
||||
@@ -752,79 +749,6 @@ class EconometricsController(BaseController):
|
||||
ns_parser.export,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_season(self, other_args: List[str]):
|
||||
"""Process season command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="season",
|
||||
description="The seasonality for a given column",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--values",
|
||||
help="Dataset.column values to be displayed in a plot",
|
||||
dest="values",
|
||||
choices={
|
||||
f"{dataset}.{column}": {column: None, dataset: None}
|
||||
for dataset, dataframe in self.datasets.items()
|
||||
for column in dataframe.columns
|
||||
},
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
help="A time lag to highlight on the plot",
|
||||
dest="m",
|
||||
type=int,
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--max_lag",
|
||||
help="The maximal lag order to consider",
|
||||
dest="max_lag",
|
||||
type=int,
|
||||
default=24,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--alpha",
|
||||
help="The confidence interval to display",
|
||||
dest="alpha",
|
||||
type=float,
|
||||
default=0.05,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-v")
|
||||
ns_parser = self.parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_ONLY_FIGURES_ALLOWED
|
||||
)
|
||||
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if not ns_parser.values:
|
||||
console.print("[red]Please enter valid dataset.\n[/red]")
|
||||
return
|
||||
|
||||
try:
|
||||
dataset, col = ns_parser.values.split(".")
|
||||
data = self.datasets[dataset]
|
||||
data.name = dataset
|
||||
except ValueError:
|
||||
console.print("[red]Please enter 'dataset'.'column'.[/red]\n")
|
||||
return
|
||||
|
||||
econometrics_view.display_seasonality(
|
||||
data=data,
|
||||
column=col,
|
||||
export=ns_parser.export,
|
||||
m=ns_parser.m,
|
||||
max_lag=ns_parser.max_lag,
|
||||
alpha=ns_parser.alpha,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_type(self, other_args: List[str]):
|
||||
"""Process type command"""
|
||||
|
||||
@@ -200,63 +200,6 @@ def display_corr(
|
||||
return fig.show(external=external_axes)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_seasonality(
|
||||
data: pd.DataFrame,
|
||||
column: str = "close",
|
||||
export: str = "",
|
||||
sheet_name: Optional[str] = None,
|
||||
m: Optional[int] = None,
|
||||
max_lag: int = 24,
|
||||
alpha: float = 0.05,
|
||||
external_axes: bool = False,
|
||||
) -> Union[OpenBBFigure, None]:
|
||||
"""Plot seasonality from a dataset
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data: pd.DataFrame
|
||||
The dataframe to plot
|
||||
column: str
|
||||
The column of the dataframe to analyze
|
||||
sheet_name: str
|
||||
Optionally specify the name of the sheet the data is exported to.
|
||||
export: str
|
||||
Format to export image
|
||||
m: Optional[int]
|
||||
Optionally, a time lag to highlight on the plot. Default is none.
|
||||
max_lag: int
|
||||
The maximal lag order to consider. Default is 24.
|
||||
alpha: float
|
||||
The confidence interval to display. Default is 0.05.
|
||||
external_axes : bool, optional
|
||||
Whether to return the figure object or not, by default False
|
||||
"""
|
||||
|
||||
if data.empty:
|
||||
return console.print("No data to plot")
|
||||
|
||||
series = data[column]
|
||||
|
||||
ending = get_ending(data.name, column)
|
||||
|
||||
fig = OpenBBFigure()
|
||||
fig.set_title(f"Seasonality{ending}", wrap=True, wrap_width=55)
|
||||
fig.add_corr_plot(series, m=m, max_lag=max_lag, alpha=alpha)
|
||||
fig.update_xaxes(autorange=False, range=[-1, max_lag + 1])
|
||||
fig.add_legend_label()
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"plot",
|
||||
sheet_name=sheet_name,
|
||||
figure=fig,
|
||||
)
|
||||
|
||||
return fig.show(external=external_axes)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_norm(
|
||||
data: pd.Series,
|
||||
|
||||
@@ -83,7 +83,7 @@ class QaController(StockBaseController):
|
||||
self.resolution = "" # For the views
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["pick"] = {c: {} for c in self.options}
|
||||
choices["unitroot"] = {
|
||||
"--fuller_reg": {c: {} for c in self.FULLER_REG},
|
||||
|
||||
@@ -646,7 +646,6 @@ def get_index(
|
||||
end=end_date,
|
||||
interval=interval,
|
||||
progress=False,
|
||||
show_errors=False,
|
||||
ignore_tz=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class FeatureFlagsController(BaseController):
|
||||
super().__init__(queue)
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def print_help(self):
|
||||
|
||||
@@ -1115,8 +1115,8 @@ class ForecastController(BaseController):
|
||||
description="The seasonality for a given column",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--values",
|
||||
"-d",
|
||||
"--dataset",
|
||||
help="Dataset.column values to be displayed in a plot",
|
||||
dest="values",
|
||||
choices=self.get_dataset_columns(),
|
||||
|
||||
@@ -16,7 +16,29 @@ def get_historical(
|
||||
source: Optional[str] = "YahooFinance",
|
||||
expiry: Optional[str] = "",
|
||||
) -> pd.DataFrame:
|
||||
"""Get historical futures data"""
|
||||
"""Get historical futures data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbols : Union[str, List[str]]
|
||||
The futures symbols you want to retrieve historical data for.
|
||||
It can be either a single symbol as a string or a list of symbols.
|
||||
start_date : str
|
||||
The start date of the historical data you want to retrieve. The date should be in the format "YYYY-MM-DD".
|
||||
end_date : str
|
||||
The end date of the historical data you want to retrieve. The date should be in the format "YYYY-MM-DD".
|
||||
source : Optional[str], default "YahooFinance"
|
||||
The source from which you want to retrieve the historical data.
|
||||
Valid values for the source are "YahooFinance" and "DataBento".
|
||||
expiry : Optional[str], default ""
|
||||
The expiry date for futures contracts. This parameter is optional and defaults to an empty string.
|
||||
It is applicable only when the source is "YahooFinance" and the symbols are futures contracts.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
A pandas DataFrame containing the historical data for the given symbols and date range.
|
||||
"""
|
||||
if source == "YahooFinance":
|
||||
if isinstance(symbols, str):
|
||||
symbols = [symbols]
|
||||
|
||||
@@ -8,7 +8,7 @@ import logging
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
from openbb_terminal import keys_model, keys_view
|
||||
from openbb_terminal.core.session.constants import KEYS_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_user import get_current_user, is_local
|
||||
from openbb_terminal.core.session.env_handler import get_reading_order
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
@@ -75,7 +75,11 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
"""
|
||||
reading_order = get_reading_order()
|
||||
hierarchy = "\n ".join(list(map(str, reversed(reading_order))))
|
||||
return hierarchy if is_local() else f"{KEYS_URL}\n {hierarchy}"
|
||||
return (
|
||||
hierarchy
|
||||
if is_local()
|
||||
else f"{BackendEnvironment.HUB_URL + 'app/terminal/api-keys'}\n {hierarchy}"
|
||||
)
|
||||
|
||||
def print_help(self, update_status: bool = True, reevaluate: bool = True):
|
||||
"""Print help"""
|
||||
|
||||
@@ -29,8 +29,8 @@ from openbb_terminal.account.show_prompt import get_show_prompt
|
||||
from openbb_terminal.core.completer.choices import build_controller_choice_map
|
||||
from openbb_terminal.core.config.paths import HIST_FILE_PATH
|
||||
from openbb_terminal.core.session import hub_model as Hub
|
||||
from openbb_terminal.core.session.constants import SCRIPT_TAGS
|
||||
from openbb_terminal.core.session.current_user import get_current_user, is_local
|
||||
from openbb_terminal.core.session.routines_handler import read_routine
|
||||
from openbb_terminal.cryptocurrency import cryptocurrency_helpers
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
@@ -85,6 +85,7 @@ SUPPORT_TYPE = ["bug", "suggestion", "question", "generic"]
|
||||
|
||||
# TODO: We should try to avoid these global variables
|
||||
RECORD_SESSION = False
|
||||
RECORD_SESSION_LOCAL_ONLY = False
|
||||
SESSION_RECORDED = list()
|
||||
SESSION_RECORDED_NAME = ""
|
||||
SESSION_RECORDED_DESCRIPTION = ""
|
||||
@@ -111,7 +112,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
"reset",
|
||||
"support",
|
||||
"wiki",
|
||||
"record",
|
||||
"stop",
|
||||
"screenshot",
|
||||
"askobb",
|
||||
@@ -892,8 +892,9 @@ class BaseController(metaclass=ABCMeta):
|
||||
action="store",
|
||||
dest="name",
|
||||
type=str,
|
||||
default=datetime.now().strftime("%Y%m%d_%H%M%S_routine.openbb"),
|
||||
help="Routine file name to be saved.",
|
||||
default="",
|
||||
help="Routine title name to be saved - only use characters, digits and whitespaces.",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
@@ -901,15 +902,30 @@ class BaseController(metaclass=ABCMeta):
|
||||
type=str,
|
||||
dest="description",
|
||||
help="The description of the routine",
|
||||
default=f"Routine recorded at {datetime.now().strftime('%H:%M')} from the OpenBB Terminal",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tag1",
|
||||
type=str,
|
||||
dest="tag1",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--tags",
|
||||
"--tag2",
|
||||
type=str,
|
||||
dest="tags",
|
||||
help="The tags of the routine",
|
||||
dest="tag2",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tag3",
|
||||
type=str,
|
||||
dest="tag3",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
@@ -921,32 +937,107 @@ class BaseController(metaclass=ABCMeta):
|
||||
help="Whether the routine should be public or not",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--local",
|
||||
dest="local",
|
||||
action="store_true",
|
||||
help="Only save the routine locally - this is necessary if you are running terminal in guest mode.",
|
||||
default=False,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-n")
|
||||
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
|
||||
if ns_parser:
|
||||
if not ns_parser.name:
|
||||
console.print(
|
||||
"[red]Set a routine title by using the '-n' flag. E.g. 'record -n Morning routine'[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag1 = (
|
||||
" ".join(ns_parser.tag1)
|
||||
if isinstance(ns_parser.tag1, list)
|
||||
else ns_parser.tag1
|
||||
)
|
||||
if tag1 and tag1 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag1' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag2 = (
|
||||
" ".join(ns_parser.tag2)
|
||||
if isinstance(ns_parser.tag2, list)
|
||||
else ns_parser.tag2
|
||||
)
|
||||
if tag2 and tag2 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag2' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag3 = (
|
||||
" ".join(ns_parser.tag3)
|
||||
if isinstance(ns_parser.tag3, list)
|
||||
else ns_parser.tag3
|
||||
)
|
||||
if tag3 and tag3 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag3' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
if is_local() and not ns_parser.local:
|
||||
console.print(
|
||||
"[red]Recording session to the OpenBB Hub is not supported in guest mode.[/red]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Sign to OpenBB Hub to register: http://openbb.co[/yellow]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Otherwise set the flag '-l' to save the file locally.[/yellow]"
|
||||
)
|
||||
return
|
||||
|
||||
# Check if title has a valid format
|
||||
title = " ".join(ns_parser.name) if ns_parser.name else ""
|
||||
pattern = re.compile(r"^[a-zA-Z0-9\s]+$")
|
||||
if not pattern.match(title):
|
||||
console.print(
|
||||
f"[red]Title '{title}' has invalid format. Please use only digits, characters and whitespaces.[/]"
|
||||
)
|
||||
return
|
||||
|
||||
global RECORD_SESSION
|
||||
global RECORD_SESSION_LOCAL_ONLY
|
||||
global SESSION_RECORDED_NAME
|
||||
global SESSION_RECORDED_DESCRIPTION
|
||||
global SESSION_RECORDED_TAGS
|
||||
global SESSION_RECORDED_PUBLIC
|
||||
|
||||
SESSION_RECORDED_NAME = (
|
||||
ns_parser.name
|
||||
if ".openbb" in ns_parser.name
|
||||
else ns_parser.name + ".openbb"
|
||||
RECORD_SESSION = True
|
||||
RECORD_SESSION_LOCAL_ONLY = ns_parser.local
|
||||
SESSION_RECORDED_NAME = title
|
||||
SESSION_RECORDED_DESCRIPTION = (
|
||||
" ".join(ns_parser.description)
|
||||
if isinstance(ns_parser.description, list)
|
||||
else ns_parser.description
|
||||
)
|
||||
SESSION_RECORDED_TAGS = tag1 if tag1 else ""
|
||||
SESSION_RECORDED_TAGS += "," + tag2 if tag2 else ""
|
||||
SESSION_RECORDED_TAGS += "," + tag3 if tag3 else ""
|
||||
|
||||
SESSION_RECORDED_DESCRIPTION = " ".join(ns_parser.description)
|
||||
SESSION_RECORDED_TAGS = " ".join(ns_parser.tags) if ns_parser.tags else ""
|
||||
SESSION_RECORDED_PUBLIC = ns_parser.public
|
||||
|
||||
console.print(
|
||||
"[green]The session is successfully being recorded."
|
||||
+ " Remember to 'stop' before exiting terminal!\n[/green]"
|
||||
f"[green]The routine '{title}' is successfully being recorded.[/green]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Remember to run 'stop' command when you are done!\n[/yellow]"
|
||||
)
|
||||
RECORD_SESSION = True
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_stop(self, _) -> None:
|
||||
@@ -956,57 +1047,102 @@ class BaseController(metaclass=ABCMeta):
|
||||
|
||||
if not RECORD_SESSION:
|
||||
console.print(
|
||||
"[red]There is no session being recorded. Start one using 'record'[/red]\n"
|
||||
"[red]There is no session being recorded. Start one using the command 'record'[/red]\n"
|
||||
)
|
||||
elif not SESSION_RECORDED:
|
||||
elif len(SESSION_RECORDED) < 5:
|
||||
console.print(
|
||||
"[red]There is no session to be saved. Run at least 1 command after starting 'record'[/red]\n"
|
||||
"[red]Run at least 4 commands before stopping recording a session.[/red]\n"
|
||||
)
|
||||
else:
|
||||
current_user = get_current_user()
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY, SESSION_RECORDED_NAME
|
||||
)
|
||||
|
||||
if os.path.isfile(routine_file):
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
datetime.now().strftime("%Y%m%d_%H%M%S_") + SESSION_RECORDED_NAME,
|
||||
# Check if the user just wants to store routine locally
|
||||
# This works regardless of whether they are logged in or not
|
||||
if RECORD_SESSION_LOCAL_ONLY:
|
||||
# Whitespaces are replaced by underscores and an .openbb extension is added
|
||||
title_for_local_storage = (
|
||||
SESSION_RECORDED_NAME.replace(" ", "_") + ".openbb"
|
||||
)
|
||||
|
||||
# Writing to file
|
||||
with open(routine_file, "w") as file1:
|
||||
# Writing data to a file
|
||||
file1.writelines([c + "\n\n" for c in SESSION_RECORDED[:-1]])
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
title_for_local_storage,
|
||||
)
|
||||
|
||||
console.print(
|
||||
f"[green]Your routine has been recorded and saved here: {routine_file}[/green]\n"
|
||||
)
|
||||
|
||||
if not is_local():
|
||||
routine = read_routine(file_name=routine_file)
|
||||
if routine is not None:
|
||||
name = SESSION_RECORDED_NAME.split(sep=".openbb", maxsplit=-1)[0]
|
||||
kwargs = {
|
||||
"auth_header": current_user.profile.get_auth_header(),
|
||||
"name": name,
|
||||
"description": SESSION_RECORDED_DESCRIPTION,
|
||||
"routine": routine,
|
||||
"tags": SESSION_RECORDED_TAGS,
|
||||
"public": SESSION_RECORDED_PUBLIC,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
if response is not None and response.status_code == 409:
|
||||
i = console.input(
|
||||
"A routine with the same name already exists, "
|
||||
"do you want to replace it? (y/n): "
|
||||
)
|
||||
# If file already exists, add a timestamp to the name
|
||||
if os.path.isfile(routine_file):
|
||||
i = console.input(
|
||||
"A local routine with the same name already exists, "
|
||||
"do you want to override it? (y/n): "
|
||||
)
|
||||
console.print("")
|
||||
while i.lower() not in ["y", "yes", "n", "no"]:
|
||||
i = console.input("Select 'y' or 'n' to proceed: ")
|
||||
console.print("")
|
||||
if i.lower() in ["y", "yes"]:
|
||||
kwargs["override"] = True # type: ignore
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
else:
|
||||
console.print("[info]Aborted.[/info]")
|
||||
|
||||
if i.lower() in ["n", "no"]:
|
||||
new_name = (
|
||||
datetime.now().strftime("%Y%m%d_%H%M%S_")
|
||||
+ title_for_local_storage
|
||||
)
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
new_name,
|
||||
)
|
||||
console.print(
|
||||
f"[yellow]The routine name has been updated to '{new_name}'[/yellow]\n"
|
||||
)
|
||||
|
||||
# Writing to file
|
||||
with open(routine_file, "w") as file1:
|
||||
lines = ["# OpenBB Terminal - Routine", "\n"]
|
||||
username = get_current_user().profile.username
|
||||
lines += [f"# Author: {username}", "\n\n"] if username else ["\n"]
|
||||
lines += [
|
||||
f"# Title: {SESSION_RECORDED_NAME}",
|
||||
"\n",
|
||||
f"# Tags: {SESSION_RECORDED_TAGS}",
|
||||
"\n\n",
|
||||
f"# Description: {SESSION_RECORDED_DESCRIPTION}",
|
||||
"\n\n",
|
||||
]
|
||||
lines += [c + "\n" for c in SESSION_RECORDED[:-1]]
|
||||
# Writing data to a file
|
||||
file1.writelines(lines)
|
||||
|
||||
console.print(
|
||||
f"[green]Your routine has been recorded and saved here: {routine_file}[/green]\n"
|
||||
)
|
||||
|
||||
# If user doesn't specify they want to store routine locally
|
||||
else:
|
||||
# Confirm that the user is logged in
|
||||
if not is_local():
|
||||
# routine = read_routine(file_name=routine_file)
|
||||
routine = "\n".join(SESSION_RECORDED[:-1])
|
||||
|
||||
if routine is not None:
|
||||
kwargs = {
|
||||
"auth_header": current_user.profile.get_auth_header(),
|
||||
"name": SESSION_RECORDED_NAME,
|
||||
"description": SESSION_RECORDED_DESCRIPTION,
|
||||
"routine": routine,
|
||||
"tags": SESSION_RECORDED_TAGS,
|
||||
"public": SESSION_RECORDED_PUBLIC,
|
||||
"base_url": Hub.BackendEnvironment.BASE_URL,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
if response is not None and response.status_code == 409:
|
||||
i = console.input(
|
||||
"A routine with the same name already exists, "
|
||||
"do you want to replace it? (y/n): "
|
||||
)
|
||||
console.print("")
|
||||
if i.lower() in ["y", "yes"]:
|
||||
kwargs["override"] = True # type: ignore
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
else:
|
||||
console.print("[info]Aborted.[/info]")
|
||||
|
||||
# Clear session to be recorded again
|
||||
RECORD_SESSION = False
|
||||
|
||||
@@ -43,7 +43,7 @@ class DegiroController(BaseController):
|
||||
self.__degiro_view = DegiroView()
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
|
||||
zero_to_hundred: dict = {str(c): {} for c in range(0, 100)}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ __docformat__ = "numpy"
|
||||
import datetime
|
||||
import logging
|
||||
import warnings
|
||||
from os import environ
|
||||
from typing import Any, Dict
|
||||
|
||||
import numpy as np
|
||||
@@ -12,6 +11,7 @@ import pandas as pd
|
||||
import yfinance as yf
|
||||
from tqdm import tqdm
|
||||
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.portfolio.allocation_model import get_allocation
|
||||
from openbb_terminal.portfolio.portfolio_helper import (
|
||||
@@ -196,7 +196,7 @@ class PortfolioEngine:
|
||||
|
||||
# Load transactions from file
|
||||
if path.endswith(".xlsx"):
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
warnings.filterwarnings(
|
||||
"ignore", category=UserWarning, module="openpyxl"
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ class ParametersController(BaseController):
|
||||
self.DATA_FILES = params_helpers.load_data_files()
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["set"] = {c: None for c in self.models}
|
||||
choices["set"]["--model"] = {c: None for c in self.models}
|
||||
choices["set"]["-m"] = "--model"
|
||||
|
||||
@@ -21,7 +21,7 @@ from openbb_terminal.core.config.paths import (
|
||||
SETTINGS_ENV_FILE,
|
||||
STYLES_DIRECTORY_REPO,
|
||||
)
|
||||
from openbb_terminal.core.session.constants import CHARTS_TABLES_URL, COLORS_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_user import (
|
||||
get_current_user,
|
||||
is_local,
|
||||
@@ -231,7 +231,7 @@ class SettingsController(BaseController):
|
||||
" Then, place the downloaded file 'openbb_config.richstyle.json'"
|
||||
f" inside {get_current_user().preferences.USER_STYLES_DIRECTORY} or "
|
||||
f"{STYLES_DIRECTORY_REPO}. If you have a hub account you can change colors "
|
||||
f"here {COLORS_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme'}.",
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-s")
|
||||
@@ -246,6 +246,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="settings",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print("Colors updated.")
|
||||
@@ -266,7 +267,7 @@ class SettingsController(BaseController):
|
||||
dest="style",
|
||||
choices=["dark", "light"],
|
||||
help="Choose chart style. If you have a hub account you can change theme "
|
||||
f"here {CHARTS_TABLES_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme/charts-tables'}.",
|
||||
required="-h" not in other_args and "--help" not in other_args,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -282,6 +283,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="terminal_style",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
theme.apply_style(ns_parser.style)
|
||||
@@ -303,7 +305,7 @@ class SettingsController(BaseController):
|
||||
dest="style",
|
||||
choices=["dark", "light"],
|
||||
help="Choose table style. If you have a hub account you can change theme "
|
||||
f"here {CHARTS_TABLES_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme/charts-tables'}.",
|
||||
required="-h" not in other_args and "--help" not in other_args,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -319,6 +321,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="terminal_style",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print("Table theme updated.\n")
|
||||
|
||||
@@ -8,7 +8,7 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from openbb_terminal.core.session.constants import SOURCES_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
|
||||
# IMPORTATION THIRDPARTY
|
||||
# IMPORTATION INTERNAL
|
||||
@@ -54,7 +54,7 @@ class SourcesController(BaseController):
|
||||
if Path(sources_file).exists() and os.stat(sources_file).st_size > 0:
|
||||
self.source = sources_file
|
||||
else:
|
||||
self.source = SOURCES_URL
|
||||
self.source = BackendEnvironment.HUB_URL + "app/terminal/data-sources"
|
||||
|
||||
def parse_input(self, an_input: str) -> List:
|
||||
"""Parse controller input
|
||||
@@ -176,6 +176,7 @@ class SourcesController(BaseController):
|
||||
key="features_sources",
|
||||
value=choices,
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.BASE_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print(
|
||||
|
||||
@@ -47,7 +47,6 @@ class BehaviouralAnalysisController(StockBaseController):
|
||||
"load",
|
||||
"wsb",
|
||||
"popular",
|
||||
"spacc",
|
||||
"getdd",
|
||||
"redditsent",
|
||||
"bullbear",
|
||||
@@ -97,7 +96,6 @@ class BehaviouralAnalysisController(StockBaseController):
|
||||
mt.add_cmd("snews", self.ticker)
|
||||
mt.add_cmd("wsb")
|
||||
mt.add_cmd("popular")
|
||||
mt.add_cmd("spacc")
|
||||
mt.add_cmd("getdd")
|
||||
mt.add_cmd("redditsent", self.ticker)
|
||||
mt.add_cmd("trending")
|
||||
@@ -137,40 +135,6 @@ class BehaviouralAnalysisController(StockBaseController):
|
||||
symbol=self.ticker, export=ns_parser.export
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_spacc(self, other_args: List[str]):
|
||||
"""Process spacc command."""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="spacc",
|
||||
description="""Print other users SPACs announcement under subreddit 'SPACs'. [Source: Reddit]""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--limit",
|
||||
action="store",
|
||||
dest="n_limit",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="limit of posts with SPACs retrieved",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--popular",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_popular",
|
||||
help="popular flag, if true the posts retrieved are based on score rather than time",
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-l")
|
||||
ns_parser = self.parse_known_args_and_warn(parser, other_args)
|
||||
if ns_parser:
|
||||
reddit_view.display_spac_community(
|
||||
limit=ns_parser.n_limit, popular=ns_parser.b_popular
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_wsb(self, other_args: List[str]):
|
||||
"""Process wsb command."""
|
||||
|
||||
@@ -442,7 +442,10 @@ class ComparisonAnalysisController(BaseController):
|
||||
other_args.insert(0, "-s")
|
||||
ns_parser = self.parse_known_args_and_warn(parser, other_args)
|
||||
if ns_parser:
|
||||
self.similar = list(set(ns_parser.l_similar + [self.ticker.upper()]))
|
||||
if self.ticker:
|
||||
self.similar = list(set(ns_parser.l_similar + [self.ticker.upper()]))
|
||||
else:
|
||||
self.similar = list(set(ns_parser.l_similar))
|
||||
self.user = "Custom"
|
||||
console.print(
|
||||
f"[{self.user}] Similar Companies: {', '.join(self.similar)}", "\n"
|
||||
|
||||
@@ -275,8 +275,8 @@ def get_government_buys(
|
||||
else -float(x["min"]),
|
||||
axis=1,
|
||||
)
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=True)
|
||||
df_gov = df_gov[df_gov.Transaction == "Purchase"]
|
||||
df_gov = df_gov.sort_values(by="Amount", ascending=False).reset_index(drop=True)
|
||||
|
||||
return df_gov
|
||||
|
||||
@@ -348,7 +348,11 @@ def get_government_sells(
|
||||
)
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=True)
|
||||
|
||||
df_gov = (
|
||||
df_gov[df_gov.Transaction == "Sale"]
|
||||
.sort_values(by="Amount", key=lambda x: abs(x), ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
return df_gov
|
||||
|
||||
|
||||
|
||||
@@ -320,8 +320,8 @@ def display_vol_surface(
|
||||
tick_kwargs = dict(tickfont=dict(size=13), titlefont=dict(size=16))
|
||||
fig.update_layout(
|
||||
scene=dict(
|
||||
xaxis=dict(title="Strike", **tick_kwargs),
|
||||
yaxis=dict(title="DTE", **tick_kwargs),
|
||||
xaxis=dict(title="DTE", **tick_kwargs),
|
||||
yaxis=dict(title="Strike", **tick_kwargs),
|
||||
zaxis=dict(title=z, **tick_kwargs),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -20,7 +20,6 @@ import certifi
|
||||
import pandas as pd
|
||||
import requests
|
||||
from prompt_toolkit import PromptSession
|
||||
from prompt_toolkit.completion import NestedCompleter
|
||||
from prompt_toolkit.formatted_text import HTML
|
||||
from prompt_toolkit.styles import Style
|
||||
|
||||
@@ -34,9 +33,10 @@ from openbb_terminal.core.config.paths import (
|
||||
SETTINGS_ENV_FILE,
|
||||
)
|
||||
from openbb_terminal.core.log.generation.custom_logger import log_terminal
|
||||
from openbb_terminal.core.session import session_controller
|
||||
from openbb_terminal.core.session import constants, session_controller
|
||||
from openbb_terminal.core.session.current_system import set_system_variable
|
||||
from openbb_terminal.core.session.current_user import get_current_user, set_preference
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
from openbb_terminal.helper_funcs import (
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
check_positive,
|
||||
@@ -90,6 +90,7 @@ class TerminalController(BaseController):
|
||||
"news",
|
||||
"intro",
|
||||
"askobb",
|
||||
"record",
|
||||
]
|
||||
CHOICES_MENUS = [
|
||||
"stocks",
|
||||
@@ -142,44 +143,10 @@ class TerminalController(BaseController):
|
||||
|
||||
def update_runtime_choices(self):
|
||||
"""Update runtime choices."""
|
||||
self.ROUTINE_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in get_current_user().preferences.USER_ROUTINES_DIRECTORY.rglob(
|
||||
"*.openbb"
|
||||
)
|
||||
}
|
||||
if get_current_user().profile.get_token():
|
||||
self.ROUTINE_DEFAULT_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "default"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
self.ROUTINE_PERSONAL_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "personal"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
|
||||
self.ROUTINE_CHOICES["--file"] = {
|
||||
filename: None for filename in self.ROUTINE_FILES
|
||||
}
|
||||
self.ROUTINE_CHOICES["--example"] = None
|
||||
self.ROUTINE_CHOICES["-e"] = None
|
||||
self.ROUTINE_CHOICES["--input"] = None
|
||||
self.ROUTINE_CHOICES["-i"] = None
|
||||
self.ROUTINE_CHOICES["--help"] = None
|
||||
self.ROUTINE_CHOICES["--h"] = None
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
# choices: dict = self.choices_default
|
||||
choices: dict = {c: {} for c in self.controller_choices} # type: ignore
|
||||
choices["support"] = self.SUPPORT_CHOICES
|
||||
choices["exe"] = self.ROUTINE_CHOICES
|
||||
choices["news"] = self.NEWS_CHOICES
|
||||
choices["news"]["--source"] = {c: {} for c in ["Biztoc", "Feedparser"]}
|
||||
choices["hold"] = {c: None for c in ["on", "off", "-s", "--sameaxis"]}
|
||||
@@ -187,6 +154,56 @@ class TerminalController(BaseController):
|
||||
if biztoc_model.BIZTOC_TAGS:
|
||||
choices["news"]["--tag"] = {c: {} for c in biztoc_model.BIZTOC_TAGS}
|
||||
|
||||
self.ROUTINE_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in get_current_user().preferences.USER_ROUTINES_DIRECTORY.rglob(
|
||||
"*.openbb"
|
||||
)
|
||||
}
|
||||
if get_current_user().profile.get_token():
|
||||
self.ROUTINE_DEFAULT_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "default"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
self.ROUTINE_PERSONAL_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "personal"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
|
||||
choices["exe"] = {
|
||||
"--file": {
|
||||
filename: {} for filename in list(self.ROUTINE_FILES.keys())
|
||||
},
|
||||
"-f": "--file",
|
||||
"--example": None,
|
||||
"-e": "--example",
|
||||
"--input": None,
|
||||
"-i": "--input",
|
||||
"--url": None,
|
||||
}
|
||||
|
||||
choices["record"] = {
|
||||
"--name": None,
|
||||
"-n": "--name",
|
||||
"--description": None,
|
||||
"-d": "--description",
|
||||
"--public": None,
|
||||
"-p": "--public",
|
||||
"--local": None,
|
||||
"-l": "--local",
|
||||
"--tag1": {c: None for c in constants.SCRIPT_TAGS},
|
||||
"--tag2": {c: None for c in constants.SCRIPT_TAGS},
|
||||
"--tag3": {c: None for c in constants.SCRIPT_TAGS},
|
||||
}
|
||||
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def print_help(self):
|
||||
@@ -1084,6 +1101,7 @@ def run_routine(file: str, routines_args=Optional[str]):
|
||||
|
||||
def main(
|
||||
debug: bool,
|
||||
dev: bool,
|
||||
path_list: List[str],
|
||||
routines_args: Optional[List[str]] = None,
|
||||
**kwargs,
|
||||
@@ -1094,6 +1112,8 @@ def main(
|
||||
----------
|
||||
debug : bool
|
||||
Whether to run the terminal in debug mode
|
||||
dev:
|
||||
Points backend towards development environment instead of production
|
||||
test : bool
|
||||
Whether to run the terminal in integrated test mode
|
||||
filtert : str
|
||||
@@ -1113,6 +1133,11 @@ def main(
|
||||
if debug:
|
||||
set_system_variable("DEBUG_MODE", True)
|
||||
|
||||
if dev:
|
||||
set_system_variable("DEV_BACKEND", True)
|
||||
constants.BackendEnvironment.BASE_URL = "https://payments.openbb.dev/"
|
||||
constants.BackendEnvironment.HUB_URL = "https://my.openbb.dev/"
|
||||
|
||||
cfg.start_plot_backend()
|
||||
|
||||
if isinstance(path_list, list) and path_list[0].endswith(".openbb"):
|
||||
@@ -1140,6 +1165,13 @@ def parse_args_and_run():
|
||||
default=False,
|
||||
help="Runs the terminal in debug mode.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dev",
|
||||
dest="dev",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Points backend towards development environment instead of production",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--file",
|
||||
help="The path or .openbb file to run.",
|
||||
@@ -1211,6 +1243,7 @@ def parse_args_and_run():
|
||||
|
||||
main(
|
||||
ns_parser.debug,
|
||||
ns_parser.dev,
|
||||
ns_parser.path,
|
||||
ns_parser.routine_args,
|
||||
module=ns_parser.module,
|
||||
|
||||
@@ -23,7 +23,7 @@ from openbb_terminal import thought_of_the_day as thought
|
||||
from openbb_terminal.base_helpers import load_env_files
|
||||
from openbb_terminal.core.config.paths import HIST_FILE_PATH, SETTINGS_ENV_FILE
|
||||
from openbb_terminal.core.plots.backend import plots_backend
|
||||
from openbb_terminal.core.session.constants import REGISTER_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.current_user import (
|
||||
get_current_user,
|
||||
@@ -257,7 +257,8 @@ def print_guest_block_msg():
|
||||
console.print(
|
||||
"[info]You are currently logged as a guest.[/info]\n"
|
||||
"[info]Login to use this feature.[/info]\n\n"
|
||||
f"[info]If you don't have an account, you can create one here: [/info][cmds]{REGISTER_URL}\n[/cmds]"
|
||||
"[info]If you don't have an account, you can create one here: [/info]"
|
||||
f"[cmds]{BackendEnvironment.HUB_URL + 'register'}\n[/cmds]"
|
||||
)
|
||||
|
||||
|
||||
@@ -369,6 +370,7 @@ def reset(queue: Optional[List[str]] = None):
|
||||
plots_backend().close(reset=True)
|
||||
load_env_files()
|
||||
debug = get_current_system().DEBUG_MODE
|
||||
dev = get_current_system().DEV_BACKEND
|
||||
|
||||
try:
|
||||
# save the current user
|
||||
@@ -399,7 +401,7 @@ def reset(queue: Optional[List[str]] = None):
|
||||
if is_local():
|
||||
from openbb_terminal.terminal_controller import main
|
||||
|
||||
main(debug, queue_list, module="") # type: ignore
|
||||
main(debug, dev, queue_list, module="") # type: ignore
|
||||
else:
|
||||
from openbb_terminal.core.session import session_controller
|
||||
|
||||
|
||||
8
poetry.lock
generated
vendored
8
poetry.lock
generated
vendored
@@ -2298,13 +2298,13 @@ user_agent = "*"
|
||||
|
||||
[[package]]
|
||||
name = "finvizfinance"
|
||||
version = "0.14.5"
|
||||
version = "0.14.6rc2"
|
||||
description = "Finviz Finance. Information downloader."
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "finvizfinance-0.14.5-py3-none-any.whl", hash = "sha256:1b22bfd7af36f01a08c6032e19f64e810ae3f42bfba681e9a2132226a5a90924"},
|
||||
{file = "finvizfinance-0.14.5.tar.gz", hash = "sha256:c97fe0e69d681d9108113aed943988561665d0d4dbd64ffa0b666a2899c25899"},
|
||||
{file = "finvizfinance-0.14.6rc2-py3-none-any.whl", hash = "sha256:70742b5054e84fbe5a1ffcc7cad97ca9225292e07ce0349dcb78462d5e5e51a0"},
|
||||
{file = "finvizfinance-0.14.6rc2.tar.gz", hash = "sha256:736f3064faac1f8ba6d06fdd7c77f79a3e831c2048fc6442759861fce4c4a6e8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -10495,4 +10495,4 @@ optimization = ["Riskfolio-Lib"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8.1,<3.11, !=3.9.7"
|
||||
content-hash = "10cccda4c8b51c57241490d53d46268092e6ffe9054c8ef22b7e58477ad3b98c"
|
||||
content-hash = "cf28c86b1360b436443a486b5ed8b33101e35d3a6c02f81c7dc85515e520c634"
|
||||
|
||||
4
pyproject.toml
vendored
4
pyproject.toml
vendored
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "openbb"
|
||||
version = "3.2.0"
|
||||
version = "3.2.1"
|
||||
description = "Investment Research for Everyone, Anywhere."
|
||||
license = "MIT"
|
||||
authors = ["Didier Rodrigues Lopes"]
|
||||
@@ -42,7 +42,7 @@ robin-stocks = "^2.0.3"
|
||||
pycoingecko = "^3.1.0"
|
||||
detecta = "^0.0.5"
|
||||
tradingview-ta = "^3.2.3"
|
||||
finvizfinance = "^0.14.0"
|
||||
finvizfinance = "0.14.6rc2"
|
||||
statsmodels = "^0.13"
|
||||
python-coinmarketcap = "^0.2"
|
||||
oandapyV20 = "^0.6.3"
|
||||
|
||||
2
requirements-full.txt
vendored
2
requirements-full.txt
vendored
@@ -98,7 +98,7 @@ filelock==3.12.2 ; python_full_version >= "3.8.1" and python_full_version != "3.
|
||||
financedatabase==2.1.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finnhub-python==2.4.18 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finviz==1.4.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finvizfinance==0.14.5 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finvizfinance==0.14.6rc2 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
flake8==6.0.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
flask==2.3.2 ; python_full_version >= "3.8.1" and python_version < "3.11" and python_full_version != "3.9.7"
|
||||
fonttools==4.41.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
|
||||
2
requirements.txt
vendored
2
requirements.txt
vendored
@@ -65,7 +65,7 @@ ffn==0.3.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" a
|
||||
financedatabase==2.1.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finnhub-python==2.4.18 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finviz==1.4.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finvizfinance==0.14.5 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
finvizfinance==0.14.6rc2 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
flake8==6.0.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
fonttools==4.41.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
formulaic==0.6.4 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11"
|
||||
|
||||
@@ -34,8 +34,9 @@ def main():
|
||||
and ("--login" in sys.argv[1:] or is_installer())
|
||||
and sys.stdin.isatty()
|
||||
)
|
||||
dev = "--dev" in sys.argv[1:]
|
||||
|
||||
session_controller.main(prompt=prompt_login)
|
||||
session_controller.main(prompt=prompt_login, dev=dev)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -404,7 +404,10 @@ def test_call_list(mocker, test_user):
|
||||
controller.call_list(other_args=["--page", "1", "--size", "10"])
|
||||
|
||||
mock_list_routines.assert_called_once_with(
|
||||
auth_header="Bearer 123", page=1, size=10
|
||||
auth_header="Bearer 123",
|
||||
page=1,
|
||||
size=10,
|
||||
base_url="https://payments.openbb.co/",
|
||||
)
|
||||
|
||||
|
||||
@@ -446,6 +449,7 @@ def test_call_upload(mocker, test_user):
|
||||
routine="do something",
|
||||
tags="stocks",
|
||||
public=False,
|
||||
base_url="https://payments.openbb.co/",
|
||||
)
|
||||
|
||||
|
||||
@@ -484,6 +488,7 @@ def test_call_download(mocker, test_user):
|
||||
mock_download_routine.assert_called_once_with(
|
||||
auth_header="Bearer 123",
|
||||
uuid="script1",
|
||||
base_url="https://payments.openbb.co/",
|
||||
)
|
||||
mock_save_routine.assert_called_once_with(
|
||||
file_name="script1.openbb", routine=["do something", "personal"]
|
||||
@@ -555,6 +560,7 @@ def test_call_generate(mocker, monkeypatch, test_user):
|
||||
|
||||
mock_generate.assert_called_once_with(
|
||||
auth_header="Bearer 123",
|
||||
base_url="https://payments.openbb.co/",
|
||||
days=30,
|
||||
)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ def test_create_session_success(email, password):
|
||||
assert response.json() == TEST_RESPONSE
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "login",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "login",
|
||||
json={"email": email, "password": password, "remember": True},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -113,7 +113,7 @@ def test_create_session_from_token_success(mocker, token):
|
||||
assert response.json() == TEST_RESPONSE
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "sdk/login",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "sdk/login",
|
||||
json={"token": token},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -151,7 +151,7 @@ def test_delete_session_success(auth_header, token):
|
||||
assert response.status_code == 200
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "logout",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "logout",
|
||||
headers={"Authorization": "Bearer test_token"},
|
||||
json={"token": "test_token"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
@@ -233,7 +233,9 @@ def test_get_session_success():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session("email", "password")
|
||||
assert result == {"session": "info"}
|
||||
create_session_mock.assert_called_once_with("email", "password")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"email", "password", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_401():
|
||||
@@ -246,7 +248,9 @@ def test_get_session_401():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session("email", "password")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("email", "password")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"email", "password", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_403():
|
||||
@@ -259,7 +263,9 @@ def test_get_session_403():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session("email", "password")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("email", "password")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"email", "password", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_failed_to_request():
|
||||
@@ -268,7 +274,9 @@ def test_get_session_failed_to_request():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session("email", "password")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("email", "password")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"email", "password", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_from_token():
|
||||
@@ -282,7 +290,9 @@ def test_get_session_from_token():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {"session": "info"}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"token", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_from_token_401():
|
||||
@@ -295,7 +305,9 @@ def test_get_session_from_token_401():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"token", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_from_token_403():
|
||||
@@ -308,7 +320,9 @@ def test_get_session_from_token_403():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"token", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
def test_get_session_from_token_failed_to_request():
|
||||
@@ -318,7 +332,9 @@ def test_get_session_from_token_failed_to_request():
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
create_session_mock.assert_called_once_with(
|
||||
"token", base_url="https://payments.openbb.co/"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token_type, access_token", [("TokenType", "AccessToken")])
|
||||
@@ -336,7 +352,7 @@ def test_fetch_user_configs_success(token_type, access_token):
|
||||
assert result == mock_response
|
||||
requests_get_mock.assert_called_once()
|
||||
_, kwargs = requests_get_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {
|
||||
"Authorization": f"{token_type.title()} {access_token}"
|
||||
}
|
||||
@@ -352,7 +368,7 @@ def test_fetch_user_configs_failure():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert isinstance(result, requests.Response)
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -366,7 +382,7 @@ def test_fetch_user_configs_connection_error():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -378,7 +394,7 @@ def test_fetch_user_configs_timeout():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -390,7 +406,7 @@ def test_fetch_user_configs_exception():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -415,7 +431,7 @@ def test_upload_config_success(key, value, type_, auth_header):
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": f"{auth_header}"}
|
||||
assert kwargs["json"] == {"key": f"features_{type_}.{key}", "value": value}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -434,7 +450,7 @@ def test_upload_config_failure():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -451,7 +467,7 @@ def test_upload_config_connection_error():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -468,7 +484,7 @@ def test_upload_config_timeout():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -485,7 +501,7 @@ def test_upload_config_exception():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -504,7 +520,7 @@ def test_clear_user_configs_success():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -523,7 +539,7 @@ def test_clear_user_configs_failure():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -539,7 +555,7 @@ def test_clear_user_configs_timeout():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -555,7 +571,7 @@ def test_clear_user_configs_connection_error():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -570,7 +586,7 @@ def test_clear_user_configs_exception():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
|
||||
@@ -234,6 +234,7 @@ def test_download_routine(mocker, test_user, silent=False):
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url="https://payments.openbb.co/",
|
||||
silent=silent,
|
||||
)
|
||||
|
||||
@@ -272,6 +273,7 @@ def test_download_default_routine_exception(mocker, test_user, silent=False):
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url="https://payments.openbb.co/",
|
||||
silent=silent,
|
||||
)
|
||||
|
||||
@@ -310,6 +312,7 @@ def test_download_personal_routine_exception(mocker, test_user, silent=False):
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url="https://payments.openbb.co/",
|
||||
silent=silent,
|
||||
)
|
||||
|
||||
@@ -339,5 +342,6 @@ def test_download_default_and_personal_routine_exception(
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url="https://payments.openbb.co/",
|
||||
silent=silent,
|
||||
)
|
||||
|
||||
@@ -75,7 +75,9 @@ def test_login_no_response(mocker):
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.NO_RESPONSE
|
||||
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_fetch_user_configs.assert_called_once_with(
|
||||
TEST_SESSION, "https://payments.openbb.co/"
|
||||
)
|
||||
mock_apply_configs.assert_not_called()
|
||||
mock_update_flair.assert_not_called()
|
||||
mock_get_updated_hub_sources.assert_not_called()
|
||||
@@ -96,7 +98,9 @@ def test_login_fail_response(mocker):
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.FAILED
|
||||
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_fetch_user_configs.assert_called_once_with(
|
||||
TEST_SESSION, "https://payments.openbb.co/"
|
||||
)
|
||||
mock_apply_configs.assert_not_called()
|
||||
mock_update_flair.assert_not_called()
|
||||
mock_get_updated_hub_sources.assert_not_called()
|
||||
@@ -119,7 +123,9 @@ def test_login_success_response(mocker):
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.SUCCESS
|
||||
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_fetch_user_configs.assert_called_once_with(
|
||||
TEST_SESSION, "https://payments.openbb.co/"
|
||||
)
|
||||
mock_apply_configs.assert_called_once()
|
||||
mock_update_flair.assert_called_once()
|
||||
|
||||
@@ -142,10 +148,13 @@ def test_logout_user(mocker, guest):
|
||||
|
||||
auth_header = "Bearer test_token"
|
||||
token = "test_token"
|
||||
base_url = "https://payments.openbb.co/"
|
||||
session_model.logout(auth_header, token)
|
||||
|
||||
if not guest:
|
||||
mock_delete_session.assert_called_once_with(auth_header, token)
|
||||
mock_delete_session.assert_called_once_with(
|
||||
auth_header, token, base_url=base_url
|
||||
)
|
||||
assert mock_remove.call_args_list[0] == mocker.call(SESSION_FILE_PATH)
|
||||
assert mock_remove.call_args_list[1] == mocker.call(HIST_FILE_PATH)
|
||||
assert mock_remove.call_args_list[2] == mocker.call(
|
||||
|
||||
@@ -238,16 +238,6 @@ def test_call_func_expect_queue(expected_queue, queue, func):
|
||||
@pytest.mark.parametrize(
|
||||
"tested_func, other_args, mocked_func, called_args, called_kwargs",
|
||||
[
|
||||
(
|
||||
"call_spacc",
|
||||
["--limit=5", "--popular"],
|
||||
"reddit_view.display_spac_community",
|
||||
[],
|
||||
dict(
|
||||
limit=5,
|
||||
popular=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"call_wsb",
|
||||
["--limit=5", "--new"],
|
||||
@@ -426,7 +416,6 @@ def test_call_func(
|
||||
@pytest.mark.parametrize(
|
||||
"func",
|
||||
[
|
||||
"call_spacc",
|
||||
"call_wsb",
|
||||
"call_popular",
|
||||
"call_bullbear",
|
||||
|
||||
@@ -6,7 +6,6 @@ Ticker: TSLA
|
||||
snews stock price displayed over sentiment of news headlines [Finnhub]
|
||||
wsb show what WSB gang is up to in subreddit wallstreetbets [Reddit]
|
||||
popular show popular tickers [Reddit]
|
||||
spacc show other users spacs announcements from subreddit SPACs [Reddit]
|
||||
getdd gets due diligence from another user's post [Reddit]
|
||||
redditsent searches reddit for ticker and finds reddit sentiment [Reddit]
|
||||
trending trending stocks [Stocktwits]
|
||||
|
||||
@@ -68,10 +68,10 @@ def no_suppress():
|
||||
@pytest.mark.vcr(record_mode="none")
|
||||
@pytest.mark.record_stdout
|
||||
@pytest.mark.parametrize(
|
||||
"debug, path",
|
||||
[(True, None), (False, ["scripts/test_alt_covid.openbb"])],
|
||||
"debug, dev, path",
|
||||
[(True, False, None), (False, False, ["scripts/test_alt_covid.openbb"])],
|
||||
)
|
||||
def test_menu(mocker, debug, path):
|
||||
def test_menu(mocker, debug, dev, path):
|
||||
mocker.patch(target="terminal_controller.terminal")
|
||||
mocker.patch(target="terminal_controller.suppress_stdout", side_effect=no_suppress)
|
||||
terminal_controller.main(debug, path)
|
||||
terminal_controller.main(debug, dev, path)
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.0.0
|
||||
version: "2.0.0"
|
||||
date: 2022-11-29
|
||||
description: v2.0.0
|
||||
sidebar_position: 104
|
||||
sidebar_position: 105
|
||||
---
|
||||
|
||||
## Major Release Notes
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.1.0
|
||||
version: "2.1.0"
|
||||
date: 2022-12-21
|
||||
description: v2.1.0
|
||||
sidebar_position: 103
|
||||
sidebar_position: 104
|
||||
---
|
||||
|
||||
## What's new
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.2.0
|
||||
version: "2.2.0"
|
||||
date: 2022-01-19
|
||||
description: v2.2.0
|
||||
sidebar_position: 102
|
||||
sidebar_position: 103
|
||||
---
|
||||
|
||||
## What's new
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.3.0
|
||||
version: "2.3.0"
|
||||
date: 2023-01-31
|
||||
description: v2.3.0
|
||||
sidebar_position: 101
|
||||
sidebar_position: 102
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.3.1
|
||||
version: "2.3.1"
|
||||
date: 2023-02-01
|
||||
description: v2.3.1
|
||||
sidebar_position: 100
|
||||
sidebar_position: 101
|
||||
---
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.4.0
|
||||
version: "2.4.0"
|
||||
date: 2023-02-14
|
||||
description: v2.4.0
|
||||
sidebar_position: 99
|
||||
sidebar_position: 100
|
||||
---
|
||||
|
||||
## What's new
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.4.1
|
||||
version: "2.4.1"
|
||||
date: 2023-02-17
|
||||
description: v2.4.1
|
||||
sidebar_position: 98
|
||||
sidebar_position: 99
|
||||
---
|
||||
|
||||
## What's new
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v2.5.0
|
||||
version: "2.5.0"
|
||||
date: 2023-03-01
|
||||
description: v2.5.0
|
||||
sidebar_position: 97
|
||||
sidebar_position: 98
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: 2.5.1
|
||||
version: "2.5.1"
|
||||
date: 2023-03-01
|
||||
description: Current - v2.5.1
|
||||
sidebar_position: 96
|
||||
sidebar_position: 97
|
||||
---
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v3.0.0
|
||||
version: "3.0.0"
|
||||
date: 2023-04-25
|
||||
description: v3.0.0
|
||||
sidebar_position: 95
|
||||
sidebar_position: 96
|
||||
---
|
||||
|
||||
## What's new
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v3.0.1
|
||||
version: "3.0.1"
|
||||
date: 2023-05-15
|
||||
description: v3.0.1
|
||||
sidebar_position: 94
|
||||
sidebar_position: 95
|
||||
---
|
||||
|
||||
## Thank you and welcome to our new contributors 🔥
|
||||
|
||||
@@ -3,7 +3,7 @@ title: v3.1.0
|
||||
version: "3.1.0"
|
||||
date: 2023-06-21
|
||||
description: v3.1.0
|
||||
sidebar_position: 93
|
||||
sidebar_position: 94
|
||||
---
|
||||
|
||||
## Thank you and welcome to our new contributors 🔥
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: Current - v3.2.0
|
||||
title: v3.2.0
|
||||
version: "3.2.0"
|
||||
date: 2023-07-21
|
||||
description: Current - v3.2.0
|
||||
sidebar_position: 92
|
||||
sidebar_position: 93
|
||||
---
|
||||
|
||||
## Thank you and welcome to our new contributors 🔥
|
||||
|
||||
54
website/content/terminal/changelog/version3_2_1.mdx
vendored
Normal file
54
website/content/terminal/changelog/version3_2_1.mdx
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Current - v3.2.1
|
||||
version: "3.2.1"
|
||||
date: 2023-08-16
|
||||
description: Current - v3.2.1
|
||||
sidebar_position: 92
|
||||
---
|
||||
|
||||
## What's new 🎉
|
||||
|
||||
We are super excited to launch community routines in the terminal!
|
||||
|
||||
This is accompanied by our usual bug fix and general enhancements.
|
||||
|
||||
## What's changed 🚀
|
||||
* hotfix/simplify-regex (#5324) @DidierRLopes
|
||||
* Fix routines creation from the Terminal to Hub (#5312) @DidierRLopes
|
||||
* Fix regex (#5320) @DidierRLopes
|
||||
* Creates a "--dev" flag that points to dev backend for testing with hub (#5319) @DidierRLopes
|
||||
* small fixy (#5318) @DidierRLopes
|
||||
* few more updates (#5317) @DidierRLopes
|
||||
* --debug points to dev env (#5316) @DidierRLopes
|
||||
* Silly (#5313) @DidierRLopes
|
||||
* hotfix/ `/stocks/fa/pt` show all price targets on hover (#5305) @tehcoderer
|
||||
* hotfix/options-hist: Fixes `options/hist` to display date column when raw is True (#5304) @deeleeramone
|
||||
* Allow the exe command to run URLs (#5295) @colin99d
|
||||
* Feature/news sentiment (#5274) @Sai-132
|
||||
* hotfix/ conflict docstrings (#5293) @tehcoderer
|
||||
* hotfix / forecast, qa/hist (#5290) @tehcoderer
|
||||
* Fixed the get routines to meet the new backend standard (#5271) @colin99d
|
||||
* Actually fix databento this time (#5287) @jmaslek
|
||||
* add `--india` flag to `stocks/load` (#5281) @the-praxs
|
||||
* Feature/options_views: Add a Variety of Views/Charts to Extend the OptionsChains Class (#5222) @deeleeramone
|
||||
* hotfix/economy-controller-sort-filter: Fwd P/E regex fix (#5273) @deeleeramone
|
||||
* Update all_api_keys.json (#5277) @DidierRLopes
|
||||
* Move hub api keys ts (#5267) @montezdesousa
|
||||
* Hotfix `economy/overview` rates displaying as dates (#5269) @tehcoderer
|
||||
* Adds details/image for installing C++ Build Tools (#5268) @deeleeramone
|
||||
* hotfix/gdp-units - better GDP units (#5262) @deeleeramone
|
||||
* Hotfix/ locking when deploying streamlit app (#5261) @tehcoderer
|
||||
* Fix issue where incorrect key for biztoc prints exception (#5257) @jmaslek
|
||||
* Check token expiration before request (#5255) @montezdesousa
|
||||
* hotfix/economy-report-duplicate-table: fixes duplicate tables. (#5252) @deeleeramone
|
||||
* hotfix/docs-sdk-basics-headTitle: fix headTitle (#5253) @deeleeramone
|
||||
* Fix/reports (#5251) @jmaslek
|
||||
* Fix/reports (#5250) @jmaslek
|
||||
* Release/3.2.0 (#5243) @jmaslek
|
||||
|
||||
We are proud of our community contributors and staunch supporters of open-source ecosystems.
|
||||
Help us promote our community by tagging `@openbb_finance` on Twitter with a link to your pull request,
|
||||
and join our Discord server to chat about your contribution! We want to hear about your experience!
|
||||
|
||||
### Links 🦋
|
||||
[Website](https://openbb.co/), [Twitter](https://twitter.com/openbb_finance), [Linkedin](https://www.linkedin.com/company/openbb-finance), [Instagram](https://www.instagram.com/openbb.finance/), [Reddit](https://www.reddit.com/r/openbb/), [Discord](https://discord.com/invite/xPHTuHCmuV)
|
||||
@@ -37,7 +37,7 @@ Install the OpenBB Terminal on MacOS (Big Sur or later). There are two versions
|
||||
<div style={{
|
||||
height: 80
|
||||
}}>
|
||||
<InstallerButton href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.0/x86.64.MacOS.OpenBB.Terminal.v3.2.0.pkg" label="Mac Intel Installer" /> <InstallerButton href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.0/ARM64.MacOS.OpenBB.Terminal.v3.2.0.pkg" label="Mac M1 Installer" />
|
||||
<InstallerButton href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.1/x86.64.MacOS.OpenBB.Terminal.v3.2.1.pkg" label="Mac Intel Installer" /> <InstallerButton href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.1/ARM64.MacOS.OpenBB.Terminal.v3.2.1.pkg" label="Mac M1 Installer" />
|
||||
</div>
|
||||
|
||||
<details><summary>Minimum Requirements</summary>
|
||||
|
||||
@@ -30,7 +30,7 @@ import InstallerButton from "@site/src/components/General/InstallerButton";
|
||||
|
||||
This section provides you with the installation file as well as the guide to install the OpenBB Terminal via Windows (10 or greater).
|
||||
|
||||
<InstallerButton type="windows" href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.0/Windows.OpenBB.Terminal.v3.2.0.exe" label="Windows Installer" />
|
||||
<InstallerButton type="windows" href="https://github.com/OpenBB-finance/OpenBBTerminal/releases/download/v3.2.1/Windows.OpenBB.Terminal.v3.2.1.exe" label="Windows Installer" />
|
||||
|
||||
<details><summary>Minimum Requirements</summary>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user