Here we merge all API Refactor related branches (#2236)

* Update api.py

* Updated forex menu

* refactor ycrv command

* refactor ycrv command black

* refactor ecocal command

* Minh changes

* Adding space to test pushing

* title fix ecocal df

* get economic calendar annotation

* fix investingcom tests

* refactor index command

* refactor overview command

* give defaults to wsj view function args

* rename date args investincom

* refacto bigmac command

* fix ecocal typo

* refactor rtps command

* alphavantage gdp

* alphavantage gdp per capita

* alphavantage cpi

* alphavantage tyld

* alphavantage inf

* refactor macro command

* refactor macro command w helpers

* refactor treasury command

* fix macro on terminal

* treasury labels

* refactor maturities

* update treasury maturities doc strings

* refactor get economic calendar finhub

* refactor map command api

* display map filter choices

* route economy api to performance map

* route economy api to performance map

* display group choices on valuation command

* refactor performance and valuation commands

* refactor spectrum model and view

* add choices to spectrum controller

* delete image after view

* fix model tests finviz

* fix finciz view tests

* refactor futures

* fix some tests

* fix more tests

* fix controller test

* refactor fred series notes

* update fred notes docstring

* refacto fred series ids

* fix pred and qa when empty datasets

* refactor fred

* uncomment stuff

* refacto get series data

* fix some tests

* set defaults on args

* refactor fred yield curve

* black

* fix spell and remove ecocal names

* fix linting

* linting

* pylint fix

* change dangerous defaults

* Working through crypto fixes (#2256)

* Working through crypto fixes

* Continued adding crypto stuff

* Added crypto overview

* Added test fixes

* Added fixtures

* Fixed tests

* Fixed charting issue

* Removed broken APIs

* Final adjustments

* Added test fixes

* map get groups and get ycrv countries into old api

* exposed econdb helper funcs

* remove helpers

* refactor search indices

* linting

* refactor arg currency

* pylint from currency

* Started switching crpyto ascending to ascend

* Merging

* Portfolio model arguements, params, and docstring

* Refactored for etf commands (#2292)

* Refactored for etf commands

* Fixed tests

* Added load command

* Fixed menu

* Portfolio logic fixes

* Added econometrics (#2260)

* Added econometrics

* Fixed tests

* Simplified API

* Added test fixes

* Added test csv

* Allowed examples to be loaded

* Fund refactor (#2291)

* Fund refactor

* Changed fund_name and fund to name

* Changed ascending to ascend

* Stock menu refactoring for easier API usage (#2194)

* Stocks  refactoring for easier API usage

* Linting

* Refactor newly added features

* Linting

* Fixing tests

* Refactor common files used by stocks menu

* Fixing flake8

* Fix linting and tests

* Linting

* Fix flake8

* refactor insider_data

* refactor mentions

* refactor watchlist

* refactor sentiment

* refactor sentiment

* fix yahoofinance tests

* refactor load and candle

* refactor get_news and display_news

* refactor stocks.ins.act

* candle default matplotlib

* fix yahoofinance_view tests

* fix ark model tests

* fix ark view tests

* fix business insider model

* fix business insider view

* refactor csimarket model

* fix tests csi market model

* update dd controller

* fix get suppliers tests

* fix dd controller tests

* fix finhub tests

* fix finviz tests

* fix fmp tests

* fix marketwatch tests

* corrected argument keywords in test_bt_model

* corrected argument keywords in test_bt_view

* refactor fa controller

* refactor marketwatch view

* refactor gov controller

* fix tests fa av

* fix tests elect

* fix dcf tests

* fix polygon tests

* fix fmp tests

* fix quiverquant tests

* fix yahoofinance fa tests

* fix more fa tests

* fix insider tests

* fix more tests

* fix more tests

* fix options tests

* fix stock gov tests

* fix tests test_ba_controller

* fix tests for test_finviz_compare_model.py

* fixed 2 tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* fix final tests

* fixed tests

* fixed tests

* Fix tests

* black

* forgot to black tests

* fixed tests

* fixed tests

* fixed tests

* fixed tests

* flakefix

* Tests + code : Stocks / Discovery

* fix tests

* added recorder

* fixed tests

* fixed tests

* black

* black

* remove unused imports

* refactor display raw

* sia dicts fix

* pylint

* linting

* remove dangerous default

* fix tests

* fix beta model test

* black

* skip screener qa test

* change sector path to sectors

* update tests readme

* fix metric defaults

* black

* substitute lost ticker

* defaults cpic

* another round on sia

* refactor cramer

* reduce default tweets on sentiment

* refactor yf hist, corr, volume

* arkorders default

* refactor income, balance, cashflow

* refacto scorr, screener, getfinnhub

* refactor stockgrid

* ibkr refactor

* another round on stockgrid

* add dividens end point

* refactor discovery endpoints

* update docstrings with similar input

* refactor messages

* refactor ba

* refactor regioons

* refactor twitter sentiment

* refactor hist

* refactor regions

* give default to timeframe

* refactor bunch of defaults and arg names

* remove leftover imports

* refactor vwap

* let tests run

* fix tests

* fix stock tests

* fix stockanalysis tests

* flake

* MYPY

* Made important changes

* added fixes

* Fixed big issue

* Added fixes to tests

* fix qa tests

* fix tests

* fix 1 more test

* last stocks failing

* fix crypto test

Co-authored-by: Chavithra PARANA <chavithra@gmail.com>
Co-authored-by: montezdesousa <montezdesousa@gmail.com>
Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt>
Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com>
Co-authored-by: colin99d <colin99delahunty@gmail.com>

* fix portfolio tests

* change period to window

* update ca docstrings

* refactor get_similar_companies func

* Fixed

* Update CI

* Update CI 2

* Update CI 3

* Update dependencies

Co-authored-by: colin99d <colin99delahunty@gmail.com>
Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com>
Co-authored-by: montezdesousa <montezdesousa@gmail.com>
Co-authored-by: James Simmons <simmonsj330@gmail.com>
Co-authored-by: Theodore Aptekarev <aptekarev@gmail.com>
Co-authored-by: minhhoang1023 <40023817+minhhoang1023@users.noreply.github.com>
Co-authored-by: jose-donato <43375532+jose-donato@users.noreply.github.com>
Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com>
Co-authored-by: northern-64bit <75195383+northern-64bit@users.noreply.github.com>
Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt>
This commit is contained in:
Chavithra
2022-08-17 16:28:54 +02:00
committed by GitHub
parent ee0e1e9822
commit 9e1a58e2db
670 changed files with 765094 additions and 51019 deletions

View File

@@ -200,7 +200,7 @@ jobs:
uses: actions/cache@v2
with:
path: ~/conda_pkgs_dir
key: conda-${{ runner.os }}-v1-${{ matrix.python }}-${{ hashFiles('build/conda/conda-3-9-env.yaml') }}
key: conda-${{ runner.os }}-v1-${{ matrix.python }}-${{ hashFiles('build/conda/conda-3-9-env-full.yaml') }}
- name: Setup Miniconda
uses: conda-incubator/setup-miniconda@v2
@@ -232,7 +232,7 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-v1-3-9-pip-${{ hashFiles('requirements.txt') }}
key: ${{ runner.os }}-v1-3-9-pip-${{ hashFiles('requirements-full.txt') }}
restore-keys: |
${{ runner.os }}-v1-pip-

View File

@@ -20,6 +20,7 @@ from openbb_terminal.helper_funcs import (
)
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)

View File

@@ -12,4 +12,5 @@ from .mutual_funds import mutual_fund_api as funds
from .portfolio import portfolio_api as portfolio
from .reports import widget_helpers as widgets
from .config_terminal import theme

View File

@@ -12,20 +12,20 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_sentiment(ticker: str) -> pd.DataFrame:
def get_sentiment(symbol: str) -> pd.DataFrame:
"""Gets Sentiment analysis provided by FinBrain's API [Source: finbrain]
Parameters
----------
ticker : str
Ticker to get the sentiment analysis from
symbol : str
Ticker symbol to get the sentiment analysis from
Returns
-------
DataFrame()
Empty if there was an issue with data retrieval
"""
result = requests.get(f"https://api.finbrain.tech/v0/sentiments/{ticker}")
result = requests.get(f"https://api.finbrain.tech/v0/sentiments/{symbol}")
sentiment = pd.DataFrame()
if result.status_code == 200:
result_json = result.json()

View File

@@ -34,7 +34,7 @@ def lambda_sentiment_coloring(val: float, last_val: float) -> str:
@log_start_end(log=logger)
def display_sentiment_analysis(
ticker: str,
symbol: str,
raw: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -43,16 +43,16 @@ def display_sentiment_analysis(
Parameters
----------
ticker : str
Ticker to get the sentiment analysis from
raw : False
symbol: str
Ticker symbol to get the sentiment analysis from
raw: False
Display raw table data
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
sentiment = finbrain_model.get_sentiment(ticker)
sentiment = finbrain_model.get_sentiment(symbol)
if sentiment.empty:
console.print("No sentiment data found.\n")
return
@@ -83,7 +83,7 @@ def display_sentiment_analysis(
ax.set_ylabel("Sentiment")
start_date = sentiment.index[-1].strftime("%Y/%m/%d")
ax.set_title(
f"FinBrain's Sentiment Analysis for {ticker.upper()} since {start_date}"
f"FinBrain's Sentiment Analysis for {symbol.upper()} since {start_date}"
)
ax.set_ylim([-1.1, 1.1])
senValues = np.array(pd.to_numeric(sentiment["Sentiment Analysis"].values))

View File

@@ -12,13 +12,13 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_mentions(ticker: str) -> pd.DataFrame:
def get_mentions(symbol: str) -> pd.DataFrame:
"""Get interest over time from google api [Source: google]
Parameters
----------
ticker : str
Stock ticker
symbol: str
Stock ticker symbol
Returns
-------
@@ -26,18 +26,18 @@ def get_mentions(ticker: str) -> pd.DataFrame:
Dataframe of interest over time
"""
pytrend = TrendReq()
pytrend.build_payload(kw_list=[ticker])
pytrend.build_payload(kw_list=[symbol])
return pytrend.interest_over_time()
@log_start_end(log=logger)
def get_regions(ticker: str) -> pd.DataFrame:
def get_regions(symbol: str) -> pd.DataFrame:
"""Get interest by region from google api [Source: google]
Parameters
----------
ticker : str
Ticker to look at
symbol: str
Ticker symbol to look at
Returns
-------
@@ -45,18 +45,18 @@ def get_regions(ticker: str) -> pd.DataFrame:
Dataframe of interest by region
"""
pytrend = TrendReq()
pytrend.build_payload(kw_list=[ticker])
return pytrend.interest_by_region()
pytrend.build_payload(kw_list=[symbol])
return pytrend.interest_by_region().sort_values([symbol], ascending=False)
@log_start_end(log=logger)
def get_queries(ticker: str) -> pd.DataFrame:
def get_queries(symbol: str) -> pd.DataFrame:
"""Get related queries from google api [Source: google]
Parameters
----------
ticker : str
Stock ticker to compare
symbol: str
Stock ticker symbol to compare
Returns
-------
@@ -64,18 +64,18 @@ def get_queries(ticker: str) -> pd.DataFrame:
Dataframe of related queries
"""
pytrend = TrendReq()
pytrend.build_payload(kw_list=[ticker])
pytrend.build_payload(kw_list=[symbol])
return pytrend.related_queries()
@log_start_end(log=logger)
def get_rise(ticker: str) -> pd.DataFrame:
def get_rise(symbol: str) -> pd.DataFrame:
"""Get top rising related queries with this stock's query [Source: google]
Parameters
----------
ticker : str
Stock ticker
symbol: str
Stock ticker symbol
Returns
-------
@@ -83,6 +83,6 @@ def get_rise(ticker: str) -> pd.DataFrame:
Dataframe containing rising related queries
"""
pytrend = TrendReq()
pytrend.build_payload(kw_list=[ticker])
pytrend.build_payload(kw_list=[symbol])
df_related_queries = pytrend.related_queries()
return df_related_queries[ticker]["rising"]
return df_related_queries[symbol]["rising"]

View File

@@ -25,8 +25,8 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_mentions(
ticker: str,
start: str,
symbol: str,
start_date: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -34,16 +34,16 @@ def display_mentions(
Parameters
----------
ticker : str
Ticker
start : str
symbol : str
Ticker symbol
start_date : str
Start date as YYYY-MM-DD string
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df_interest = google_model.get_mentions(ticker)
df_interest = google_model.get_mentions(symbol)
# This plot has 1 axis
if external_axes is None:
@@ -53,20 +53,20 @@ def display_mentions(
else:
return
ax.set_title(f"Interest over time on {ticker}")
if start:
df_interest = df_interest[start:] # type: ignore
ax.bar(df_interest.index, df_interest[ticker], width=2)
ax.set_title(f"Interest over time on {symbol}")
if start_date:
df_interest = df_interest[start_date:] # type: ignore
ax.bar(df_interest.index, df_interest[symbol], width=2)
ax.bar(
df_interest.index[-1],
df_interest[ticker].values[-1],
df_interest[symbol].values[-1],
width=theme.volume_bar_width,
)
else:
ax.bar(df_interest.index, df_interest[ticker], width=1)
ax.bar(df_interest.index, df_interest[symbol], width=1)
ax.bar(
df_interest.index[-1],
df_interest[ticker].values[-1],
df_interest[symbol].values[-1],
width=theme.volume_bar_width,
)
ax.set_ylabel("Interest [%]")
@@ -83,8 +83,8 @@ def display_mentions(
@log_start_end(log=logger)
def display_correlation_interest(
ticker: str,
df_data: pd.DataFrame,
symbol: str,
data: pd.DataFrame,
words: List[str],
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -93,9 +93,9 @@ def display_correlation_interest(
Parameters
----------
ticker : str
Ticker to check price
df_data : pd.DataFrame
symbol : str
Ticker symbol to check price
data : pd.DataFrame
Data dataframe
words : List[str]
Words to check for interest for
@@ -120,15 +120,15 @@ def display_correlation_interest(
else:
return
ax[0].set_title(
f"{ticker.upper()} stock price and interest over time on {','.join(words)}"
f"{symbol.upper()} stock price and interest over time on {','.join(words)}"
)
ax[0].plot(
df_data.index,
df_data["Adj Close"].values,
data.index,
data["Adj Close"].values,
c="#FCED00",
)
ax[0].set_ylabel("Stock Price")
ax[0].set_xlim(df_data.index[0], df_data.index[-1])
ax[0].set_xlim(data.index[0], data.index[-1])
colors = theme.get_colors()[1:]
for idx, word in enumerate(words):
@@ -136,7 +136,7 @@ def display_correlation_interest(
ax[1].plot(df_interest.index, df_interest[word], "-", color=colors[idx])
ax[1].set_ylabel("Interest [%]")
ax[1].set_xlim(df_data.index[0], df_data.index[-1])
ax[1].set_xlim(data.index[0], data.index[-1])
ax[1].legend(words)
theme.style_primary_axis(ax[0])
theme.style_primary_axis(ax[1])
@@ -151,8 +151,8 @@ def display_correlation_interest(
@log_start_end(log=logger)
def display_regions(
ticker: str,
num: int = 5,
symbol: str,
limit: int = 5,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -160,16 +160,16 @@ def display_regions(
Parameters
----------
ticker : str
Ticker
num: int
symbol : str
Ticker symbol
limit: int
Number of regions to show
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df_interest_region = google_model.get_regions(ticker)
df_interest_region = google_model.get_regions(symbol)
# This plot has 1 axis
if external_axes is None:
@@ -184,14 +184,12 @@ def display_regions(
console.print("")
return
df_interest_region = df_interest_region.sort_values([ticker], ascending=False).head(
num
)
df = df_interest_region.sort_values([ticker], ascending=True)
df_interest_region = df_interest_region.head(limit)
df = df_interest_region.sort_values([symbol], ascending=True)
ax.set_title(f"Top's regions interest on {ticker}")
ax.set_title(f"Top's regions interest on {symbol}")
ax.barh(
y=df.index, width=df[ticker], color=theme.get_colors(reverse=True), zorder=3
y=df.index, width=df[symbol], color=theme.get_colors(reverse=True), zorder=3
)
ax.set_xlabel("Interest [%]")
ax.set_ylabel("Region")
@@ -204,55 +202,55 @@ def display_regions(
@log_start_end(log=logger)
def display_queries(ticker: str, num: int = 5, export: str = ""):
def display_queries(symbol: str, limit: int = 5, export: str = ""):
"""Print top related queries with this stock's query. [Source: Google]
Parameters
----------
ticker : str
Ticker
num: int
symbol : str
Ticker symbol
limit: int
Number of regions to show
export: str
Format to export data
"""
df_related_queries = google_model.get_queries(ticker)
df_related_queries = google_model.get_queries(symbol)
df = df_related_queries.copy()
df_related_queries = df_related_queries[ticker]["top"].head(num)
df_related_queries = df_related_queries[symbol]["top"].head(limit)
df_related_queries["value"] = df_related_queries["value"].apply(
lambda x: str(x) + "%"
)
print_rich_table(
df_related_queries,
headers=list(df_related_queries.columns),
title=f"Top {ticker}'s related queries",
title=f"Top {symbol}'s related queries",
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "queries", df)
@log_start_end(log=logger)
def display_rise(ticker: str, num: int, export: str = ""):
def display_rise(symbol: str, limit: int = 10, export: str = ""):
"""Print top rising related queries with this stock's query. [Source: Google]
Parameters
----------
ticker : str
Ticker
num: int
symbol : str
Ticker symbol
limit: int
Number of regions to show
export: str
Format to export data
"""
df_related_queries = google_model.get_rise(ticker)
df = df_related_queries.copy()
df_related_queries = df_related_queries.head(num)
df_related_queries = google_model.get_rise(symbol)
print_rich_table(
df_related_queries,
df_related_queries.head(limit),
headers=list(df_related_queries.columns),
title=f"Top rising {ticker}'s related queries",
title=f"Top rising {symbol}'s related queries",
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "rise", df)
export_data(
export, os.path.dirname(os.path.abspath(__file__)), "rise", df_related_queries
)

View File

@@ -38,13 +38,13 @@ l_sub_reddits = [
@log_start_end(log=logger)
def get_watchlists(
n_to_get: int,
limit: int = 5,
) -> Tuple[List[praw.models.reddit.submission.Submission], Dict, int]:
"""Get reddit users watchlists [Source: reddit]
Parameters
----------
n_to_get : int
limit : int
Number of posts to look through
Returns
@@ -120,7 +120,7 @@ def get_watchlists(
# Increment count of valid posts found
n_flair_posts_found += 1
subs.append(submission)
if n_flair_posts_found > n_to_get - 1:
if n_flair_posts_found > limit - 1:
break
except ResponseException as e:
@@ -136,15 +136,15 @@ def get_watchlists(
@log_start_end(log=logger)
def get_popular_tickers(
n_top: int, posts_to_look_at: int, subreddits: str = ""
limit: int = 10, post_limit: int = 50, subreddits: str = ""
) -> pd.DataFrame:
"""Get popular tickers from list of subreddits [Source: reddit]
Parameters
----------
n_top : int
limit : int
Number of top tickers to get
posts_to_look_at : int
post_limit : int
How many posts to analyze in each subreddit
subreddits : str, optional
String of comma separated subreddits.
@@ -190,11 +190,11 @@ def get_popular_tickers(
for s_sub_reddit in sub_reddit_list:
console.print(
f"Search for latest tickers for {posts_to_look_at} '{s_sub_reddit}' posts"
f"Search for latest tickers for {post_limit} '{s_sub_reddit}' posts"
)
submissions = psaw_api.search_submissions(
subreddit=s_sub_reddit,
limit=posts_to_look_at,
limit=post_limit,
filter=["id"],
)
@@ -249,7 +249,7 @@ def get_popular_tickers(
# pylint: disable=redefined-outer-name
popular_tickers = []
for t_ticker in lt_watchlist_sorted:
if n_top_stocks > n_top:
if n_top_stocks > limit:
break
try:
# If try doesn't trigger exception, it means that this stock exists on finviz
@@ -295,7 +295,7 @@ def get_popular_tickers(
@log_start_end(log=logger)
def get_spac_community(
limit: int, popular: bool
limit: int = 10, popular: bool = False
) -> Tuple[List[praw.models.reddit.submission.Submission], Dict]:
"""Get top tickers from r/SPACs [Source: reddit]
@@ -680,9 +680,9 @@ def get_due_dilligence(
@log_start_end(log=logger)
def get_posts_about(
ticker: str,
symbol: str,
limit: int = 100,
sort: str = "relevance",
sortby: str = "relevance",
time_frame: str = "week",
subreddits: str = "all",
) -> List[praw.models.reddit.submission.Submission]:
@@ -690,11 +690,11 @@ def get_posts_about(
Parameters
----------
ticker: str
Ticker to search for
symbol: str
Ticker symbol to search for
limit: int
Number of posts to get per subreddit
sort: str
sortby: str
Search type
Possibilities: "relevance", "hot", "top", "new", or "comments"
time_frame: str
@@ -745,9 +745,9 @@ def get_posts_about(
console.print("Invalid subreddit name {sub_str}, skipping")
continue
submissions = subreddit.search(
query=ticker,
query=symbol,
limit=limit,
sort=sort,
sort=sortby,
time_filter=time_frame,
)
for sub in submissions:

View File

@@ -94,15 +94,15 @@ def print_and_record_reddit_post(
"API_REDDIT_PASSWORD",
]
)
def display_watchlist(num: int):
def display_watchlist(limit: int = 5):
"""Print other users watchlist. [Source: Reddit]
Parameters
----------
num: int
limit: int
Maximum number of submissions to look at
"""
subs, d_watchlist_tickers, n_flair_posts_found = reddit_model.get_watchlists(num)
subs, d_watchlist_tickers, n_flair_posts_found = reddit_model.get_watchlists(limit)
if subs:
for sub in subs:
print_and_record_reddit_post({}, sub)
@@ -141,30 +141,28 @@ def display_watchlist(num: int):
]
)
def display_popular_tickers(
n_top: int = 10, posts_to_look_at: int = 50, subreddits: str = "", export: str = ""
limit: int = 10, post_limit: int = 50, subreddits: str = "", export: str = ""
):
"""Print latest popular tickers. [Source: Reddit]
Parameters
----------
n_top : int
limit : int
Number of top tickers to get
posts_to_look_at : int
post_limit : int
How many posts to analyze in each subreddit
subreddits : str, optional
String of comma separated subreddits.
export : str
Format to export dataframe
"""
popular_tickers_df = reddit_model.get_popular_tickers(
n_top, posts_to_look_at, subreddits
)
popular_tickers_df = reddit_model.get_popular_tickers(limit, post_limit, subreddits)
if not popular_tickers_df.empty:
print_rich_table(
popular_tickers_df,
headers=list(popular_tickers_df.columns),
show_index=False,
title=f"The following TOP {n_top} tickers have been mentioned",
title=f"The following TOP {limit} tickers have been mentioned",
)
else:
console.print("No tickers found")
@@ -313,14 +311,14 @@ def display_wsb_community(limit: int = 10, new: bool = False):
]
)
def display_due_diligence(
ticker: str, limit: int = 10, n_days: int = 3, show_all_flairs: bool = False
symbol: str, limit: int = 10, n_days: int = 3, show_all_flairs: bool = False
):
"""Display Reddit due diligence data for a given ticker
Parameters
----------
ticker: str
Stock ticker
symbol: str
Stock ticker symbol
limit: int
Number of posts to get
n_days: int
@@ -328,12 +326,12 @@ def display_due_diligence(
show_all_flairs: bool
Search through all flairs (apart from Yolo and Meme)
"""
subs = reddit_model.get_due_dilligence(ticker, limit, n_days, show_all_flairs)
subs = reddit_model.get_due_dilligence(symbol, limit, n_days, show_all_flairs)
if subs:
for sub in subs:
print_and_record_reddit_post({}, sub)
if not subs:
console.print(f"No DD posts found for {ticker}\n")
console.print(f"No DD posts found for {symbol}\n")
@log_start_end(log=logger)
@@ -347,23 +345,23 @@ def display_due_diligence(
]
)
def display_reddit_sent(
ticker: str,
sort: str = "relevance",
symbol: str,
sortby: str = "relevance",
limit: int = 100,
graphic: bool = False,
time_frame: str = "week",
full_search: bool = True,
subreddits: str = "all",
export: str = "",
display: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Determine Reddit sentiment about a search term
Parameters
----------
ticker: str
The ticker being search for in Reddit
sort: str
symbol: str
The ticker symbol being search for in Reddit
sortby: str
Type of search
limit: str
Number of posts to get at most
@@ -377,16 +375,18 @@ def display_reddit_sent(
Comma-separated list of subreddits
display: bool
Enable printing of raw sentiment values for each post
export: str
Format to export data
external_axes: Optional[List[plt.Axes]]
If supplied, expect 1 external axis
"""
posts = reddit_model.get_posts_about(ticker, limit, sort, time_frame, subreddits)
posts = reddit_model.get_posts_about(symbol, limit, sortby, time_frame, subreddits)
post_data = []
polarity_scores = []
if not posts:
console.print(f"No posts for {ticker} found")
console.print(f"No posts for {symbol} found")
return
console.print("Analyzing each post...")
@@ -417,13 +417,13 @@ def display_reddit_sent(
return
sns.boxplot(x=polarity_scores, ax=ax)
ax.set_title(f"Sentiment Score of {ticker}")
ax.set_title(f"Sentiment Score of {symbol}")
ax.set_xlabel("Sentiment Score")
if not external_axes:
theme.visualize_output()
console.print(f"Sentiment Analysis for {ticker} is {avg_polarity}\n")
console.print(f"Sentiment Analysis for {symbol} is {avg_polarity}\n")
export_data(
export,

View File

@@ -16,18 +16,23 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_historical(ticker: str, start: str, end: str, number: int) -> pd.DataFrame:
"""Get hour-level sentiment data for the chosen ticker
def get_historical(
symbol: str,
start_date: str = (datetime.utcnow() - timedelta(days=7)).strftime("%Y-%m-%d"),
end_date: str = datetime.utcnow().strftime("%Y-%m-%d"),
number: int = 100,
) -> pd.DataFrame:
"""Get hour-level sentiment data for the chosen symbol
Source: [Sentiment Investor]
Parameters
----------
ticker: str
symbol: str
Ticker to view sentiment data
start: str
start_date: str
Initial date like string or unix timestamp (e.g. 12-21-2021)
end: str
end_date: str
End date like string or unix timestamp (e.g. 12-21-2021)
number : int
Number of results returned by API call
@@ -41,9 +46,9 @@ def get_historical(ticker: str, start: str, end: str, number: int) -> pd.DataFra
payload: Dict[str, Union[int, str]] = {
"token": cfg.API_SENTIMENTINVESTOR_TOKEN,
"symbol": ticker,
"start": str(start),
"end": str(end),
"symbol": symbol,
"start": str(start_date),
"end": str(end_date),
"limit": number,
}
@@ -71,15 +76,15 @@ def get_historical(ticker: str, start: str, end: str, number: int) -> pd.DataFra
return df
def check_supported_ticker(ticker: str) -> bool:
def check_supported_ticker(symbol: str) -> bool:
"""Check if the ticker is supported
Source: [Sentiment Investor]
Parameters
----------
ticker: str
Ticker to view sentiment data
symbol: str
Ticker symbol to view sentiment data
Returns
-------
@@ -89,12 +94,14 @@ def check_supported_ticker(ticker: str) -> bool:
payload: Dict[str, str] = {
"token": cfg.API_SENTIMENTINVESTOR_TOKEN,
"symbol": ticker,
"symbol": symbol,
}
response = requests.get(
"https://api.sentimentinvestor.com/v1/supported", params=payload
)
if response.status_code >= 500:
return False
response_json = response.json()
result = False
@@ -105,7 +112,7 @@ def check_supported_ticker(ticker: str) -> bool:
result = response_json["result"]
else:
console.print(
f"[red]Ticker {ticker} not supported. Please try another one![/red]\n"
f"[red]Ticker {symbol} not supported. Please try another one![/red]\n"
)
elif "error" in response_json:
@@ -117,7 +124,9 @@ def check_supported_ticker(ticker: str) -> bool:
return result
def get_trending(start: datetime, hour: int, number: int) -> pd.DataFrame:
def get_trending(
start_date: datetime = datetime.today(), hour: int = 0, number: int = 10
) -> pd.DataFrame:
"""Get sentiment data on the most talked about tickers
within the last hour
@@ -125,7 +134,7 @@ def get_trending(start: datetime, hour: int, number: int) -> pd.DataFrame:
Parameters
----------
start: datetime
start_date: datetime
Datetime object (e.g. datetime(2021, 12, 21)
hour: int
Hour of the day in 24-hour notation (e.g. 14)
@@ -140,7 +149,7 @@ def get_trending(start: datetime, hour: int, number: int) -> pd.DataFrame:
"""
# type is datetime
start_timestamp = start + timedelta(hours=hour)
start_timestamp = start_date + timedelta(hours=hour)
payload: Dict[str, Union[int, str]] = {
"token": cfg.API_SENTIMENTINVESTOR_TOKEN,
@@ -152,6 +161,9 @@ def get_trending(start: datetime, hour: int, number: int) -> pd.DataFrame:
response = requests.get(
"https://api.sentimentinvestor.com/v1/trending", params=payload
)
if response.status_code >= 500:
return pd.DataFrame()
response_json = response.json()
df = pd.DataFrame()

View File

@@ -4,7 +4,7 @@ __docformat__ = "numpy"
import logging
import os
from typing import Optional, List
from datetime import datetime
from datetime import datetime, timedelta
from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
import pandas as pd
@@ -29,13 +29,13 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
@check_api_key(["API_SENTIMENTINVESTOR_TOKEN"])
def display_historical(
ticker: str,
start: str,
end: str,
export: str = "",
symbol: str,
start_date: str = (datetime.utcnow() - timedelta(days=7)).strftime("%Y-%m-%d"),
end_date: str = datetime.utcnow().strftime("%Y-%m-%d"),
number: int = 100,
raw: bool = False,
limit: int = 10,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Display historical sentiment data of a ticker,
@@ -43,13 +43,13 @@ def display_historical(
Parameters
----------
ticker: str
Ticker to view sentiment data
start: str
symbol: str
Ticker symbol to view sentiment data
start_date: str
Initial date like string or unix timestamp (e.g. 2021-12-21)
end: str
end_date: str
End date like string or unix timestamp (e.g. 2022-01-15)
number : int
number: int
Number of results returned by API call
Maximum 250 per api call
raw: boolean
@@ -57,23 +57,25 @@ def display_historical(
limit: int
Number of results display on the terminal
Default: 10
external_axes : Optional[List[plt.Axes]], optional
export: str
Format to export data
external_axes: Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
Returns
-------
"""
supported_ticker = sentimentinvestor_model.check_supported_ticker(ticker)
supported_ticker = sentimentinvestor_model.check_supported_ticker(symbol)
# Check to see if the ticker is supported
if not supported_ticker:
logger.error("Ticker not supported")
console.print(
f"[red]Ticker {ticker} not supported. Please try another one![/red]\n"
f"[red]Ticker {symbol} not supported. Please try another one![/red]\n"
)
return
df = sentimentinvestor_model.get_historical(ticker, start, end, number)
df = sentimentinvestor_model.get_historical(symbol, start_date, end_date, number)
if df.empty:
return
@@ -144,18 +146,18 @@ def display_historical(
@log_start_end(log=logger)
@check_api_key(["API_SENTIMENTINVESTOR_TOKEN"])
def display_trending(
start: datetime,
hour: int,
export: str = "",
start_date: datetime = datetime.today(),
hour: int = 0,
number: int = 10,
limit: int = 10,
export: str = "",
):
"""Display most talked about tickers within
the last hour together with their sentiment data.
Parameters
----------
start: datetime
start_date: datetime
Datetime object (e.g. datetime(2021, 12, 21)
hour: int
Hour of the day in 24-hour notation (e.g. 14)
@@ -165,12 +167,15 @@ def display_trending(
limit: int
Number of results display on the terminal
Default: 10
-------
Returns
None
export: str
Format to export data
"""
df = sentimentinvestor_model.get_trending(start, hour, number)
# Force datetime format to be datetime(year, month, day, 0, 0)
# 0 hours and minutes to look since day starts
start_date = datetime(start_date.year, start_date.month, start_date.day)
df = sentimentinvestor_model.get_trending(start_date, hour, number)
if df.empty:
return

View File

@@ -13,13 +13,13 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_bullbear(ticker: str) -> Tuple[int, int, int, int]:
def get_bullbear(symbol: str) -> Tuple[int, int, int, int]:
"""Gets bullbear sentiment for ticker [Source: stocktwits]
Parameters
----------
ticker : str
Ticker to look at
symbol : str
Ticker symbol to look at
Returns
-------
@@ -33,7 +33,7 @@ def get_bullbear(ticker: str) -> Tuple[int, int, int, int]:
Number of bearish statements
"""
result = requests.get(
f"https://api.stocktwits.com/api/2/streams/symbol/{ticker}.json"
f"https://api.stocktwits.com/api/2/streams/symbol/{symbol}.json"
)
if result.status_code == 200:
result_json = result.json()
@@ -52,28 +52,30 @@ def get_bullbear(ticker: str) -> Tuple[int, int, int, int]:
@log_start_end(log=logger)
def get_messages(ticker: str, limit: int = 30) -> List[str]:
def get_messages(symbol: str, limit: int = 30) -> pd.DataFrame:
"""Get last messages for a given ticker [Source: stocktwits]
Parameters
----------
ticker : str
Stock ticker
symbol : str
Stock ticker symbol
limit : int
Number of messages to get
Returns
-------
List[str]
List of messages
pd.DataFrame
Dataframe of messages
"""
result = requests.get(
f"https://api.stocktwits.com/api/2/streams/symbol/{ticker}.json"
f"https://api.stocktwits.com/api/2/streams/symbol/{symbol}.json"
)
if result.status_code == 200:
return [message["body"] for message in result.json()["messages"][:limit]]
return pd.DataFrame(
[message["body"] for message in result.json()["messages"][:limit]]
)
return []
return pd.DataFrame()
@log_start_end(log=logger)

View File

@@ -3,8 +3,6 @@ __docformat__ = "numpy"
import logging
import pandas as pd
from openbb_terminal.common.behavioural_analysis import stocktwits_model
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import print_rich_table
@@ -14,17 +12,17 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_bullbear(ticker: str):
def display_bullbear(symbol: str):
"""
Print bullbear sentiment based on last 30 messages on the board.
Also prints the watchlist_count. [Source: Stocktwits]
Parameters
----------
ticker: str
Stock ticker
symbol: str
Stock ticker symbol
"""
watchlist_count, n_cases, n_bull, n_bear = stocktwits_model.get_bullbear(ticker)
watchlist_count, n_cases, n_bull, n_bear = stocktwits_model.get_bullbear(symbol)
console.print(f"Watchlist count: {watchlist_count}")
if n_cases > 0:
console.print(f"\nLast {n_cases} sentiment messages:")
@@ -36,21 +34,21 @@ def display_bullbear(ticker: str):
@log_start_end(log=logger)
def display_messages(ticker: str, limit: int = 30):
def display_messages(symbol: str, limit: int = 30):
"""Print up to 30 of the last messages on the board. [Source: Stocktwits]
Parameters
----------
ticker: str
Stock ticker
symbol: str
Stock ticker symbol
limit: int
Number of messages to get
"""
messages = stocktwits_model.get_messages(ticker, limit)
messages = stocktwits_model.get_messages(symbol, limit)
if len(messages) > 0:
if not messages.empty:
print_rich_table(
pd.DataFrame(messages),
messages,
headers=["MESSAGES"],
show_index=False,
title="Last Messages on Board",

View File

@@ -1,6 +1,7 @@
"""Twitter Model"""
__docformat__ = "numpy"
from datetime import datetime, timedelta
import logging
from typing import Optional
@@ -20,22 +21,22 @@ analyzer = SentimentIntensityAnalyzer()
@log_start_end(log=logger)
def load_analyze_tweets(
ticker: str,
count: int = 100,
start_time: Optional[str] = "",
end_time: Optional[str] = "",
symbol: str,
limit: int = 100,
start_date: Optional[str] = "",
end_date: Optional[str] = "",
) -> pd.DataFrame:
"""Load tweets from twitter API and analyzes using VADER
Parameters
----------
ticker: str
Ticker to search twitter for
count: int
symbol: str
Ticker symbol to search twitter for
limit: int
Number of tweets to analyze
start : Optional[str]
start_date: Optional[str]
If given, the start time to get tweets from
end : Optional[str]
end_date: Optional[str]
If given, the end time to get tweets from
Returns
@@ -44,16 +45,16 @@ def load_analyze_tweets(
Dataframe of tweets and sentiment
"""
params = {
"query": rf"(\${ticker}) (lang:en)",
"max_results": str(count),
"query": rf"(\${symbol}) (lang:en)",
"max_results": str(limit),
"tweet.fields": "created_at,lang",
}
if start_time:
if start_date:
# Assign from and to datetime parameters for the API
params["start_time"] = start_time
if end_time:
params["end_time"] = end_time
params["start_time"] = start_date
if end_date:
params["end_time"] = end_date
# Request Twitter API
response = requests.get(
@@ -105,7 +106,7 @@ def load_analyze_tweets(
neu = []
for s_tweet in df_tweets["text"].to_list():
tweet = clean_tweet(s_tweet, ticker)
tweet = clean_tweet(s_tweet, symbol)
sentiments.append(analyzer.polarity_scores(tweet)["compound"])
pos.append(analyzer.polarity_scores(tweet)["pos"])
neg.append(analyzer.polarity_scores(tweet)["neg"])
@@ -117,3 +118,85 @@ def load_analyze_tweets(
df_tweets["neutral"] = neu
return df_tweets
@log_start_end(log=logger)
def get_sentiment(
symbol: str,
n_tweets: int = 15,
n_days_past: int = 2,
):
"""Get sentiments from symbol
Parameters
----------
symbol: str
Stock ticker symbol to get sentiment for
n_tweets: int
Number of tweets to get per hour
n_days_past: int
Number of days to extract tweets for
"""
# Date format string required by twitter
dt_format = "%Y-%m-%dT%H:%M:%SZ"
# Algorithm to extract
dt_recent = datetime.utcnow() - timedelta(seconds=20)
dt_old = dt_recent - timedelta(days=n_days_past)
console.print(
f"From {dt_recent.date()} retrieving {n_tweets*24} tweets ({n_tweets} tweets/hour)"
)
df_tweets = pd.DataFrame(
columns=[
"created_at",
"text",
"sentiment",
"positive",
"negative",
"neutral",
]
)
while True:
# Iterate until we haven't passed the old number of days
if dt_recent < dt_old:
break
# Update past datetime
dt_past = dt_recent - timedelta(minutes=60)
temp = load_analyze_tweets(
symbol,
n_tweets,
start_date=dt_past.strftime(dt_format),
end_date=dt_recent.strftime(dt_format),
)
if temp.empty:
return pd.DataFrame()
df_tweets = pd.concat([df_tweets, temp])
if dt_past.day < dt_recent.day:
console.print(
f"From {dt_past.date()} retrieving {n_tweets*24} tweets ({n_tweets} tweets/hour)"
)
# Update recent datetime
dt_recent = dt_past
# Sort tweets per date
df_tweets.sort_index(ascending=False, inplace=True)
df_tweets["cumulative_compound"] = df_tweets["sentiment"].cumsum()
df_tweets["prob_sen"] = 1
# df_tweets.to_csv(r'notebooks/tweets.csv', index=False)
df_tweets.reset_index(inplace=True)
df_tweets["Month"] = pd.to_datetime(df_tweets["created_at"]).apply(
lambda x: x.month
)
df_tweets["Day"] = pd.to_datetime(df_tweets["created_at"]).apply(lambda x: x.day)
df_tweets["date"] = pd.to_datetime(df_tweets["created_at"])
df_tweets = df_tweets.sort_values(by="date")
df_tweets["cumulative_compound"] = df_tweets["sentiment"].cumsum()
return df_tweets

View File

@@ -4,7 +4,6 @@ __docformat__ = "numpy"
import logging
import os
from typing import Optional, List
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import numpy as np
@@ -27,19 +26,19 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_inference(ticker: str, num: int = 100, export: str = ""):
def display_inference(symbol: str, limit: int = 100, export: str = ""):
"""Infer sentiment from past n tweets
Parameters
----------
ticker: str
Stock ticker
num: int
symbol: str
Stock ticker symbol
limit: int
Number of tweets to analyze
export: str
Format to export tweet dataframe
"""
df_tweets = twitter_model.load_analyze_tweets(ticker, num)
df_tweets = twitter_model.load_analyze_tweets(symbol, limit)
if df_tweets.empty:
return
@@ -62,8 +61,8 @@ def display_inference(ticker: str, num: int = 100, export: str = ""):
percent_neg = len(np.where(pos < neg)[0]) / len(df_tweets)
total_sent = np.round(np.sum(df_tweets["sentiment"]), 2)
mean_sent = np.round(np.mean(df_tweets["sentiment"]), 2)
console.print(f"The summed compound sentiment of {ticker} is: {total_sent}")
console.print(f"The average compound sentiment of {ticker} is: {mean_sent}")
console.print(f"The summed compound sentiment of {symbol} is: {total_sent}")
console.print(f"The average compound sentiment of {symbol} is: {mean_sent}")
console.print(
f"Of the last {len(df_tweets)} tweets, {100*percent_pos:.2f} % had a higher positive sentiment"
)
@@ -76,19 +75,19 @@ def display_inference(ticker: str, num: int = 100, export: str = ""):
@log_start_end(log=logger)
def display_sentiment(
ticker: str,
symbol: str,
n_tweets: int = 15,
n_days_past: int = 6,
n_days_past: int = 2,
compare: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Plot sentiments from ticker
"""Plot sentiments from symbol
Parameters
----------
ticker: str
Stock to get sentiment for
symbol: str
Stock ticker symbol to get sentiment for
n_tweets: int
Number of tweets to get per hour
n_days_past: int
@@ -97,145 +96,90 @@ def display_sentiment(
Show corresponding change in stock price
export: str
Format to export tweet dataframe
external_axes: Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
# Date format string required by twitter
dt_format = "%Y-%m-%dT%H:%M:%SZ"
# Algorithm to extract
dt_recent = datetime.utcnow() - timedelta(seconds=20)
dt_old = dt_recent - timedelta(days=n_days_past)
console.print(
f"From {dt_recent.date()} retrieving {n_tweets*24} tweets ({n_tweets} tweets/hour)"
)
df_tweets = twitter_model.get_sentiment(symbol, n_tweets, n_days_past)
df_tweets = pd.DataFrame(
columns=[
"created_at",
"text",
"sentiment",
"positive",
"negative",
"neutral",
]
)
while True:
# Iterate until we haven't passed the old number of days
if dt_recent < dt_old:
break
# Update past datetime
dt_past = dt_recent - timedelta(minutes=60)
if not df_tweets.empty:
temp = twitter_model.load_analyze_tweets(
ticker,
n_tweets,
start_time=dt_past.strftime(dt_format),
end_time=dt_recent.strftime(dt_format),
)
ax1, ax2, ax3 = None, None, None
if temp.empty:
return
df_tweets = pd.concat([df_tweets, temp])
if dt_past.day < dt_recent.day:
console.print(
f"From {dt_past.date()} retrieving {n_tweets*24} tweets ({n_tweets} tweets/hour)"
)
# Update recent datetime
dt_recent = dt_past
# Sort tweets per date
df_tweets.sort_index(ascending=False, inplace=True)
df_tweets["cumulative_compound"] = df_tweets["sentiment"].cumsum()
df_tweets["prob_sen"] = 1
# df_tweets.to_csv(r'notebooks/tweets.csv', index=False)
df_tweets.reset_index(inplace=True)
df_tweets["Month"] = pd.to_datetime(df_tweets["created_at"]).apply(
lambda x: x.month
)
df_tweets["Day"] = pd.to_datetime(df_tweets["created_at"]).apply(lambda x: x.day)
df_tweets["date"] = pd.to_datetime(df_tweets["created_at"])
df_tweets = df_tweets.sort_values(by="date")
df_tweets["cumulative_compound"] = df_tweets["sentiment"].cumsum()
ax1, ax2, ax3 = None, None, None
if compare:
# This plot has 3 axes
if external_axes is None:
_, axes = plt.subplots(
3, 1, sharex=False, figsize=plot_autoscale(), dpi=cfg_plot.PLOT_DPI
)
ax1, ax2, ax3 = axes
elif is_valid_axes_count(external_axes, 3):
(ax1, ax2, ax3) = external_axes
if compare:
# This plot has 3 axes
if external_axes is None:
_, axes = plt.subplots(
3, 1, sharex=False, figsize=plot_autoscale(), dpi=cfg_plot.PLOT_DPI
)
ax1, ax2, ax3 = axes
elif is_valid_axes_count(external_axes, 3):
(ax1, ax2, ax3) = external_axes
else:
return
else:
return
else:
# This plot has 2 axes
if external_axes is None:
_, axes = plt.subplots(
2, 1, sharex=True, figsize=plot_autoscale(), dpi=cfg_plot.PLOT_DPI
)
ax1, ax2 = axes
elif is_valid_axes_count(external_axes, 2):
(ax1, ax2) = external_axes
else:
return
# This plot has 2 axes
if external_axes is None:
_, axes = plt.subplots(
2, 1, sharex=True, figsize=plot_autoscale(), dpi=cfg_plot.PLOT_DPI
)
ax1, ax2 = axes
elif is_valid_axes_count(external_axes, 2):
(ax1, ax2) = external_axes
else:
return
ax1.plot(
pd.to_datetime(df_tweets["created_at"]),
df_tweets["cumulative_compound"].values,
)
ax1.set_ylabel("\nCumulative\nVADER Sentiment")
for _, day_df in df_tweets.groupby(by="Day"):
day_df["time"] = pd.to_datetime(day_df["created_at"])
day_df = day_df.sort_values(by="time")
ax1.plot(
day_df["time"],
day_df["sentiment"].cumsum(),
label=pd.to_datetime(day_df["date"]).iloc[0].strftime("%Y-%m-%d"),
pd.to_datetime(df_tweets["created_at"]),
df_tweets["cumulative_compound"].values,
)
ax1.set_ylabel("\nCumulative\nVADER Sentiment")
for _, day_df in df_tweets.groupby(by="Day"):
day_df["time"] = pd.to_datetime(day_df["created_at"])
day_df = day_df.sort_values(by="time")
ax1.plot(
day_df["time"],
day_df["sentiment"].cumsum(),
label=pd.to_datetime(day_df["date"]).iloc[0].strftime("%Y-%m-%d"),
)
ax2.bar(
df_tweets["date"],
df_tweets["positive"],
color=theme.up_color,
width=theme.volume_bar_width / 100,
)
ax2.bar(
df_tweets["date"],
df_tweets["positive"],
color=theme.up_color,
-1 * df_tweets["negative"],
color=theme.down_color,
width=theme.volume_bar_width / 100,
)
ax2.bar(
df_tweets["date"],
-1 * df_tweets["negative"],
color=theme.down_color,
width=theme.volume_bar_width / 100,
)
ax1.set_title(
f"Twitter's {ticker} total compound sentiment over time is {round(np.sum(df_tweets['sentiment']), 2)}"
)
ax1.set_title(
f"Twitter's {symbol} total compound sentiment over time is {round(np.sum(df_tweets['sentiment']), 2)}"
)
theme.style_primary_axis(ax1)
theme.style_primary_axis(ax1)
ax2.set_ylabel("VADER Polarity Scores")
theme.style_primary_axis(ax2)
ax2.set_ylabel("VADER Polarity Scores")
theme.style_primary_axis(ax2)
if compare:
# get stock end price for each corresponding day if compare == True
closing_price_df = get_closing_price(ticker, n_days_past)
if ax3:
ax3.plot(
closing_price_df["Date"],
closing_price_df["Close"],
label=pd.to_datetime(closing_price_df["Date"])
.iloc[0]
.strftime("%Y-%m-%d"),
)
if compare:
# get stock end price for each corresponding day if compare == True
closing_price_df = get_closing_price(symbol, n_days_past)
if ax3:
ax3.plot(
closing_price_df["Date"],
closing_price_df["Close"],
label=pd.to_datetime(closing_price_df["Date"])
.iloc[0]
.strftime("%Y-%m-%d"),
)
ax3.set_ylabel("Stock Price")
theme.style_primary_axis(ax3)
ax3.set_ylabel("Stock Price")
theme.style_primary_axis(ax3)
if external_axes is None:
theme.visualize_output()
if external_axes is None:
theme.visualize_output()
export_data(
export, os.path.dirname(os.path.abspath(__file__)), "sentiment", df_tweets

View File

@@ -3,6 +3,7 @@ __docformat__ = "numpy"
import logging
from datetime import datetime, timedelta
from typing import Dict
import requests
from openbb_terminal import config_terminal as cfg
@@ -14,8 +15,8 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_news(
term: str,
s_from: str,
query: str,
start_date: str = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"),
show_newest: bool = True,
sources: str = "",
) -> Dict:
@@ -23,9 +24,9 @@ def get_news(
Parameters
----------
term : str
query : str
term to search on the news articles
s_from: str
start_date: str
date to start searching articles from formatted YYYY-MM-DD
show_newest: bool
flag to show newest articles first
@@ -38,7 +39,7 @@ def get_news(
term to search on the news articles
"""
link = (
f"https://newsapi.org/v2/everything?q={term}&from={s_from}&sortBy=publishedAt&language=en"
f"https://newsapi.org/v2/everything?q={query}&from={start_date}&sortBy=publishedAt&language=en"
f"&apiKey={cfg.API_NEWS_TOKEN}"
)
@@ -53,7 +54,7 @@ def get_news(
if response.status_code == 200:
response_json = response.json()
console.print(
f"{response_json['totalResults']} news articles for {term} were found since {s_from}\n"
f"{response_json['totalResults']} news articles for {query} were found since {start_date}\n"
)
if show_newest:

View File

@@ -3,6 +3,7 @@ __docformat__ = "numpy"
import logging
from datetime import datetime, timedelta
import pandas as pd
from openbb_terminal.decorators import check_api_key
@@ -16,9 +17,9 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
@check_api_key(["API_NEWS_TOKEN"])
def display_news(
term: str,
s_from: str,
num: int = 3,
query: str,
start_date: str = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"),
limit: int = 3,
show_newest: bool = True,
sources: str = "",
):
@@ -26,18 +27,18 @@ def display_news(
Parameters
----------
term : str
query : str
term to search on the news articles
s_from: str
start_date: str
date to start searching articles from formatted YYYY-MM-DD
num : int
limit : int
number of articles to display
show_newest: bool
flag to show newest articles first
sources: str
sources to exclusively show news from
"""
articles = newsapi_model.get_news(term, s_from, show_newest, sources)
articles = newsapi_model.get_news(query, start_date, show_newest, sources)
if articles:
for idx, article in enumerate(articles):
@@ -53,5 +54,5 @@ def display_news(
)
print_rich_table(table, title=article["title"])
if idx >= num - 1:
if idx >= limit - 1:
break

View File

@@ -47,7 +47,7 @@ def display_arima(
seasonal: bool,
ic: str,
results: bool,
s_end_date: str = "",
end_date: str = "",
export: str = "",
time_res: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -70,7 +70,7 @@ def display_arima(
Information Criteria for model evaluation
results : bool
Flag to display model summary
s_end_date : str, optional
end_date : str, optional
Specified end date for backtesting comparisons
export : str, optional
Format to export image
@@ -82,14 +82,14 @@ def display_arima(
if arima_order:
t_order = tuple(int(ord) for ord in arima_order.split(","))
if s_end_date:
if end_date:
if not time_res:
future_index = get_next_stock_market_days(
last_stock_day=s_end_date, n_next_days=n_predict
last_stock_day=end_date, n_next_days=n_predict
)
else:
future_index = pd.date_range(
s_end_date, periods=n_predict + 1, freq=time_res
end_date, periods=n_predict + 1, freq=time_res
)[1:]
if future_index[-1] > datetime.datetime.now():
@@ -99,7 +99,7 @@ def display_arima(
return
df_future = values[future_index[0] : future_index[-1]] # noqa: E203
values = values[:s_end_date] # type: ignore
values = values[:end_date] # type: ignore
l_predictions, model = arima_model.get_arima_model(
values, arima_order, n_predict, seasonal, ic
@@ -125,17 +125,17 @@ def display_arima(
# This plot has 1 axis
if external_axes is None:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
elif s_end_date and not is_valid_axes_count(
elif end_date and not is_valid_axes_count(
external_axes,
3,
prefix_text="If there is s_end_date",
prefix_text="If there is end_date",
suffix_text="when backtesting",
):
return
elif not s_end_date and not is_valid_axes_count(
elif not end_date and not is_valid_axes_count(
external_axes,
1,
prefix_text="If there is no s_end_date",
prefix_text="If there is no end_date",
suffix_text="when backtesting",
):
return
@@ -148,7 +148,7 @@ def display_arima(
if arima_order:
# BACKTESTING
if s_end_date:
if end_date:
ax.set_title(
f"BACKTESTING: ARIMA {str(t_order)} on {dataset} - {n_predict} step prediction"
)
@@ -158,7 +158,7 @@ def display_arima(
)
else:
# BACKTESTING
if s_end_date:
if end_date:
ax.set_title(
f"BACKTESTING: ARIMA {model.order} on {dataset} - {n_predict} step prediction"
)
@@ -178,7 +178,7 @@ def display_arima(
ax.vlines(values.index[-1], ymin, ymax, linestyle="--")
# BACKTESTING
if s_end_date:
if end_date:
ax.plot(
df_future.index,
df_future,
@@ -201,7 +201,7 @@ def display_arima(
theme.visualize_output()
# BACKTESTING
if s_end_date:
if end_date:
# This plot has 3 axes
if external_axes is None:
_, axes = plt.subplots(

View File

@@ -38,13 +38,13 @@ warnings.filterwarnings("ignore")
@log_start_end(log=logger)
def display_exponential_smoothing(
ticker: str,
values: Union[pd.DataFrame, pd.Series],
dataset: str,
data: Union[pd.DataFrame, pd.Series],
n_predict: int,
trend: str = "N",
seasonal: str = "N",
seasonal_periods: int = 7,
s_end_date: str = "",
end_date: str = "",
export: str = "",
time_res: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -53,9 +53,9 @@ def display_exponential_smoothing(
Parameters
----------
ticker : str
dataset : str
Dataset being smoothed
values : Union[pd.DataFrame, pd.Series]
data : Union[pd.DataFrame, pd.Series]
Raw data
n_predict : int
Days to predict
@@ -65,7 +65,7 @@ def display_exponential_smoothing(
Seasonal variable, by default "N"
seasonal_periods : int, optional
Number of seasonal periods, by default 5
s_end_date : str, optional
end_date : str, optional
End date for backtesting, by default ""
export : str, optional
Format to export data, by default ""
@@ -74,14 +74,14 @@ def display_exponential_smoothing(
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
if s_end_date:
if end_date:
if not time_res:
future_index = get_next_stock_market_days(
last_stock_day=s_end_date, n_next_days=n_predict
last_stock_day=end_date, n_next_days=n_predict
)
else:
future_index = pd.date_range(
s_end_date, periods=n_predict + 1, freq=time_res
end_date, periods=n_predict + 1, freq=time_res
)[1:]
if future_index[-1] > datetime.datetime.now():
@@ -91,12 +91,12 @@ def display_exponential_smoothing(
)
return
df_future = values[future_index[0] : future_index[-1]] # noqa: E203
values = values[:s_end_date] # type: ignore
df_future = data[future_index[0] : future_index[-1]] # noqa: E203
data = data[:end_date] # type: ignore
# Get ETS model
model, title, forecast = ets_model.get_exponential_smoothing_model(
values, trend, seasonal, seasonal_periods, n_predict
data, trend, seasonal, seasonal_periods, n_predict
)
if not forecast:
@@ -109,12 +109,12 @@ def display_exponential_smoothing(
if not time_res:
l_pred_days = get_next_stock_market_days(
last_stock_day=values.index[-1],
last_stock_day=data.index[-1],
n_next_days=n_predict,
)
else:
l_pred_days = pd.date_range(
values.index[-1], periods=n_predict + 1, freq=time_res
data.index[-1], periods=n_predict + 1, freq=time_res
)[1:]
df_pred = pd.Series(forecast, index=l_pred_days, name="Price")
@@ -135,52 +135,52 @@ def display_exponential_smoothing(
if external_axes is None:
_, ax1 = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
elif s_end_date and not is_valid_axes_count(
elif end_date and not is_valid_axes_count(
external_axes,
3,
prefix_text="If there is s_end_date",
prefix_text="If there is end_date",
suffix_text="when backtesting",
):
return
elif not s_end_date and not is_valid_axes_count(
elif not end_date and not is_valid_axes_count(
external_axes,
1,
prefix_text="If there is no s_end_date",
prefix_text="If there is no end_date",
suffix_text="when backtesting",
):
return
else:
ax1 = external_axes[0]
ax1.plot(values.index, values.values)
ax1.plot(data.index, data.values)
# BACKTESTING
if s_end_date:
ax1.set_title(f"BACKTESTING: {title} on {ticker}", fontsize=12)
if end_date:
ax1.set_title(f"BACKTESTING: {title} on {dataset}", fontsize=12)
else:
ax1.set_title(f"{title} on {ticker}", fontsize=12)
ax1.set_title(f"{title} on {dataset}", fontsize=12)
ax1.set_xlim(
values.index[0],
data.index[0],
get_next_stock_market_days(df_pred.index[-1], 1)[-1],
)
ax1.set_ylabel("Value")
ax1.plot(
[values.index[-1], df_pred.index[0]],
[values.values[-1], df_pred.values[0]],
[data.index[-1], df_pred.index[0]],
[data.values[-1], df_pred.values[0]],
color=theme.down_color,
linestyle="--",
)
ax1.plot(df_pred.index, df_pred, color=theme.down_color)
ax1.axvspan(
values.index[-1],
data.index[-1],
df_pred.index[-1],
facecolor=theme.down_color,
alpha=0.2,
)
_, _, ymin, ymax = plt.axis()
ax1.vlines(
values.index[-1],
data.index[-1],
ymin,
ymax,
linestyle="--",
@@ -188,7 +188,7 @@ def display_exponential_smoothing(
)
# BACKTESTING
if s_end_date:
if end_date:
ax1.plot(
df_future.index,
df_future,
@@ -196,9 +196,9 @@ def display_exponential_smoothing(
linestyle="--",
)
ax1.plot(
[values.index[-1], df_future.index[0]],
[data.index[-1], df_future.index[0]],
[
values.values[-1],
data.values[-1],
df_future.values[0],
],
color=theme.up_color,
@@ -211,7 +211,7 @@ def display_exponential_smoothing(
theme.visualize_output()
# BACKTESTING
if s_end_date:
if end_date:
# This plot has 3 axes
if external_axes is None:
_, axes = plt.subplots(
@@ -236,9 +236,9 @@ def display_exponential_smoothing(
color=theme.up_color,
)
ax2.plot(
[values.index[-1], df_future.index[0]],
[data.index[-1], df_future.index[0]],
[
values.values[-1],
data.values[-1],
df_future.values[0],
],
color=theme.up_color,
@@ -246,13 +246,13 @@ def display_exponential_smoothing(
)
ax2.scatter(df_pred.index, df_pred)
ax2.plot(
[values.index[-1], df_pred.index[0]],
[values.values[-1], df_pred.values[0]],
[data.index[-1], df_pred.index[0]],
[data.values[-1], df_pred.values[0]],
linestyle="--",
)
ax2.set_title("BACKTESTING: Values")
ax2.set_xlim(
values.index[-1],
data.index[-1],
df_pred.index[-1] + datetime.timedelta(days=1),
)
ax2.set_ylabel("Value")
@@ -272,7 +272,7 @@ def display_exponential_smoothing(
)
ax3.set_title("BACKTESTING: % Error")
ax3.plot(
[values.index[-1], df_future.index[0]],
[data.index[-1], df_future.index[0]],
[
0,
100 * (df_pred.values[0] - df_future.values[0]) / df_future.values[0],
@@ -281,7 +281,7 @@ def display_exponential_smoothing(
color=theme.down_color,
)
ax3.set_xlim(
values.index[-1],
data.index[-1],
df_pred.index[-1] + datetime.timedelta(days=1),
)
ax3.set_ylabel("Prediction Error (%)")
@@ -313,5 +313,5 @@ def display_exponential_smoothing(
else:
# Print prediction data
print_pretty_prediction(df_pred, values.values[-1])
print_pretty_prediction(df_pred, data.values[-1])
export_data(export, os.path.dirname(os.path.abspath(__file__)), "ets")

View File

@@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_k_nearest_neighbors(
ticker: str,
dataset: str,
data: Union[pd.DataFrame, pd.Series],
n_neighbors: int,
n_input_days: int,
@@ -37,8 +37,8 @@ def display_k_nearest_neighbors(
Parameters
----------
ticker : str
Stock data
dataset : str
Dataset label
data : Union[pd.DataFrame, pd.Series]
Data to use for ML
n_neighbors : int
@@ -83,7 +83,7 @@ def display_k_nearest_neighbors(
y_valid=y_valid,
y_dates_valid=y_dates_valid,
scaler=scaler,
title=f"KNN Model with {n_neighbors} Neighbors on {ticker}",
title=f"KNN Model with {n_neighbors} Neighbors on {dataset}",
forecast_data=forecast_data_df,
n_loops=1,
time_str=time_res,

View File

@@ -43,7 +43,7 @@ def display_regression(
n_input: int,
n_predict: int,
n_jumps: int,
s_end_date: str = "",
end_date: str = "",
export: str = "",
time_res: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -64,7 +64,7 @@ def display_regression(
Length of prediction sequence
n_jumps : int
Number of jumps in data
s_end_date : str, optional
end_date : str, optional
Start date for backtesting
export : str, optional
Format for exporting figures
@@ -74,18 +74,18 @@ def display_regression(
External axes (1 axis is expected in the list), by default None
"""
# BACKTESTING
if s_end_date:
if end_date:
if not time_res:
future_index = get_next_stock_market_days(
last_stock_day=s_end_date, n_next_days=n_predict
last_stock_day=end_date, n_next_days=n_predict
)
else:
future_index = pd.date_range(
s_end_date, periods=n_predict + 1, freq=time_res
end_date, periods=n_predict + 1, freq=time_res
)[1:]
df_future = values[future_index[0] : future_index[-1]] # noqa: E203
values = values[:s_end_date] # type: ignore
values = values[:end_date] # type: ignore
l_predictions, _ = regression_model.get_regression_model(
list(values.values), poly_order, n_input, n_predict, n_jumps
@@ -108,17 +108,17 @@ def display_regression(
# This plot has 1 axis
if external_axes is None:
_, ax1 = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
elif s_end_date and not is_valid_axes_count(
elif end_date and not is_valid_axes_count(
external_axes,
3,
prefix_text="If there is s_end_date",
prefix_text="If there is end_date",
suffix_text="when backtesting",
):
return
elif not s_end_date and not is_valid_axes_count(
elif not end_date and not is_valid_axes_count(
external_axes,
1,
prefix_text="If there is no s_end_date",
prefix_text="If there is no end_date",
suffix_text="when backtesting",
):
return
@@ -127,7 +127,7 @@ def display_regression(
ax1.plot(values.index, values)
# BACKTESTING
if s_end_date:
if end_date:
ax1.set_title(
f"BACKTESTING: Regression (polynomial {poly_order}) on {dataset} - {n_predict} step prediction",
fontsize=12,
@@ -150,7 +150,7 @@ def display_regression(
ax1.vlines(values.index[-1], ymin, ymax, linestyle="--")
# BACKTESTING
if s_end_date:
if end_date:
ax1.plot(
df_future.index,
df_future,
@@ -175,7 +175,7 @@ def display_regression(
console.print("")
# BACKTESTING
if s_end_date:
if end_date:
# This plot has 3 axes
if external_axes is None:
_, axes = plt.subplots(

View File

@@ -22,16 +22,16 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_summary(df: pd.DataFrame) -> pd.DataFrame:
def get_summary(data: pd.DataFrame) -> pd.DataFrame:
"""Print summary statistics
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
Dataframe to get summary statistics for
"""
df_stats = df.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9])
df_stats = data.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9])
df_stats.loc["var"] = df_stats.loc["std"] ** 2
return df_stats
@@ -39,13 +39,13 @@ def get_summary(df: pd.DataFrame) -> pd.DataFrame:
@log_start_end(log=logger)
def get_seasonal_decomposition(
df: pd.DataFrame, multiplicative: bool
data: pd.DataFrame, multiplicative: bool = False
) -> Tuple[Any, pd.DataFrame, pd.DataFrame]:
"""Perform seasonal decomposition
Parameters
----------
df_stock : pd.DataFrame
data : pd.DataFrame
Dataframe of targeted data
multiplicative : bool
Boolean to indicate multiplication instead of addition
@@ -66,7 +66,7 @@ def get_seasonal_decomposition(
model = ["additive", "multiplicative"][multiplicative]
result = seasonal_decompose(df, model=model, period=seasonal_periods)
result = seasonal_decompose(data, model=model, period=seasonal_periods)
cycle, trend = sm.tsa.filters.hpfilter(
result.trend[result.trend.notna().values], lamb=lamb
)
@@ -83,7 +83,7 @@ def get_normality(data: pd.DataFrame) -> pd.DataFrame:
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
Dataframe of targeted data
Returns
@@ -129,17 +129,19 @@ def get_normality(data: pd.DataFrame) -> pd.DataFrame:
@log_start_end(log=logger)
def get_unitroot(df: pd.DataFrame, fuller_reg: str, kpss_reg: str) -> pd.DataFrame:
def get_unitroot(
data: pd.DataFrame, fuller_reg: str = "c", kpss_reg: str = "c"
) -> pd.DataFrame:
"""Calculate test statistics for unit roots
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
DataFrame of target variable
fuller_reg : str
Type of regression of ADF test
Type of regression of ADF test. Can be ‘c’,’ct’,’ctt’,’nc’ 'c' - Constant and t - trend order
kpss_reg : str
Type of regression for KPSS test
Type of regression for KPSS test. Can be ‘c’,’ct'
Returns
-------
@@ -149,10 +151,10 @@ def get_unitroot(df: pd.DataFrame, fuller_reg: str, kpss_reg: str) -> pd.DataFra
# The Augmented Dickey-Fuller test
# Used to test for a unit root in a univariate process in the presence of serial correlation.
try:
result = adfuller(df, regression=fuller_reg)
result = adfuller(data, regression=fuller_reg)
except MissingDataError:
df = df.dropna(axis=0)
result = adfuller(df, regression=fuller_reg)
data = data.dropna(axis=0)
result = adfuller(data, regression=fuller_reg)
cols = ["Test Statistic", "P-Value", "NLags", "Nobs", "ICBest"]
vals = [result[0], result[1], result[2], result[3], result[5]]
data = pd.DataFrame(data=vals, index=cols, columns=["ADF"])
@@ -165,7 +167,7 @@ def get_unitroot(df: pd.DataFrame, fuller_reg: str, kpss_reg: str) -> pd.DataFra
# Wrap this in catch_warnings to prevent
with warnings.catch_warnings():
warnings.simplefilter("ignore")
res2 = kpss(df, regression=kpss_reg, nlags="auto")
res2 = kpss(data, regression=kpss_reg, nlags="auto")
vals2 = [res2[0], res2[1], res2[2], "", ""]
data["KPSS"] = vals2
return data
@@ -215,20 +217,20 @@ def calculate_adjusted_var(
def get_var(
data: pd.DataFrame,
use_mean: bool,
adjusted_var: bool,
student_t: bool,
percentile: Union[int, float],
portfolio: bool,
use_mean: bool = False,
adjusted_var: bool = False,
student_t: bool = False,
percentile: Union[int, float] = 0.999,
portfolio: bool = False,
):
"""Gets value at risk for specified stock dataframe
Parameters
----------
data: pd.DataFrame
Dataframe of a stock/portfolio
Data dataframe
use_mean: bool
If one should use the stocks mean for calculation
If one should use the data mean for calculation
adjusted_var: bool
If one should return VaR adjusted for skew and kurtosis
student_t: bool
@@ -323,19 +325,19 @@ def get_var(
def get_es(
data: pd.DataFrame,
use_mean: bool,
distribution: str,
percentile: Union[float, int],
portfolio: bool,
use_mean: bool = False,
distribution: str = "normal",
percentile: Union[float, int] = 0.999,
portfolio: bool = False,
) -> Tuple[List[float], List[float]]:
"""Gets Expected Shortfall for specified stock dataframe
Parameters
----------
data: pd.DataFrame
Dataframe of a stock
Data dataframe
use_mean: bool
If one should use the stocks mean for calculation
If one should use the data mean for calculation
distribution: str
Type of distribution, options: laplace, student_t, normal
percentile: Union[float,int]

View File

@@ -51,17 +51,17 @@ def lambda_color_red(val: Any) -> str:
@log_start_end(log=logger)
def display_summary(df: pd.DataFrame, export: str):
def display_summary(data: pd.DataFrame, export: str = ""):
"""Show summary statistics
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
DataFrame to get statistics of
export : str
Format to export data
"""
summary = qa_model.get_summary(df)
summary = qa_model.get_summary(data)
print_rich_table(
summary,
@@ -82,9 +82,9 @@ def display_summary(df: pd.DataFrame, export: str):
@log_start_end(log=logger)
def display_hist(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
bins: int,
bins: int = 15,
external_axes: Optional[List[plt.Axes]] = None,
):
"""Generate of histogram of data
@@ -93,7 +93,7 @@ def display_hist(
----------
name : str
Name of dataset
df : pd.DataFrame
data : pd.DataFrame
Dataframe to look at
target : str
Data column to get histogram of the dataframe
@@ -102,7 +102,7 @@ def display_hist(
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
data = df[target]
data = data[target]
# This plot has 1 axis
if external_axes is None:
@@ -126,8 +126,8 @@ def display_hist(
)
sns.rugplot(data, color=theme.down_color, ax=ax, legend=True)
if isinstance(df.index[0], datetime):
start = df.index[0]
if isinstance(data.index[0], datetime):
start = data.index[0]
ax.set_title(f"Histogram of {name} {target} from {start.strftime('%Y-%m-%d')}")
else:
ax.set_title(f"Histogram of {name} {target}")
@@ -150,9 +150,9 @@ def display_hist(
@log_start_end(log=logger)
def display_cdf(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -160,19 +160,19 @@ def display_cdf(
Parameters
----------
name : str
Name of dataset
df : pd.DataFrame
data : pd.DataFrame
Dataframe to look at
target : str
Data column
symbol : str
Name of dataset
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
data = df[target]
start = df.index[0]
data = data[target]
start = data.index[0]
cdf = data.value_counts().sort_index().div(len(data)).cumsum()
# This plot has 1 axis
@@ -188,7 +188,7 @@ def display_cdf(
cdf.plot(ax=ax)
ax.set_title(
f"Cumulative Distribution Function of {name} {target}\nfrom {start.strftime('%Y-%m-%d')}"
f"Cumulative Distribution Function of {symbol} {target}\nfrom {start.strftime('%Y-%m-%d')}"
)
ax.set_ylabel("Probability")
ax.set_xlabel(target)
@@ -255,10 +255,10 @@ def display_cdf(
@log_start_end(log=logger)
def display_bw(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
yearly: bool,
symbol: str = "",
yearly: bool = True,
external_axes: Optional[List[plt.Axes]] = None,
):
"""Show box and whisker plots
@@ -267,17 +267,19 @@ def display_bw(
----------
name : str
Name of dataset
df : pd.DataFrame
data : pd.DataFrame
Dataframe to look at
target : str
Data column to look at
symbol : str
Name of dataset
yearly : bool
Flag to indicate yearly accumulation
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
data = df[target]
start = df.index[0]
data = data[target]
start = data.index[0]
# This plot has 1 axis
if external_axes is None:
@@ -315,7 +317,7 @@ def display_bw(
box_plot.set(
xlabel=["Monthly", "Yearly"][yearly],
ylabel=target,
title=f"{['Monthly','Yearly'][yearly]} box plot of {name} {target} from {start.strftime('%Y-%m-%d')}",
title=f"{['Monthly','Yearly'][yearly]} box plot of {symbol} {target} from {start.strftime('%Y-%m-%d')}",
)
l_months = [
"Jan",
@@ -351,10 +353,10 @@ def display_bw(
@log_start_end(log=logger)
def display_acf(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
lags: int,
symbol: str = "",
lags: int = 15,
external_axes: Optional[List[plt.Axes]] = None,
):
"""Show Auto and Partial Auto Correlation of returns and change in returns
@@ -363,17 +365,19 @@ def display_acf(
----------
name : str
Name of dataset
df : pd.DataFrame
data : pd.DataFrame
Dataframe to look at
target : str
Data column to look at
symbol : str
Name of dataset
lags : int
Max number of lags to look at
external_axes : Optional[List[plt.Axes]], optional
External axes (4 axes are expected in the list), by default None
"""
df = df[target]
start = df.index[0]
data = data[target]
start = data.index[0]
# This plot has 4 axes
if external_axes is None:
@@ -389,26 +393,26 @@ def display_acf(
else:
return
# Diff Auto-correlation function for original time series
sm.graphics.tsa.plot_acf(np.diff(np.diff(df.values)), lags=lags, ax=ax1)
ax1.set_title(f"{name} Returns Auto-Correlation", fontsize=9)
# Diff Partial auto-correlation function for original time series
sm.graphics.tsa.plot_pacf(np.diff(np.diff(df.values)), lags=lags, ax=ax2)
# Diff Auto - correlation function for original time series
sm.graphics.tsa.plot_acf(np.diff(np.diff(data.values)), lags=lags, ax=ax1)
ax1.set_title(f"{symbol} Returns Auto-Correlation", fontsize=9)
# Diff Partial auto - correlation function for original time series
sm.graphics.tsa.plot_pacf(np.diff(np.diff(data.values)), lags=lags, ax=ax2)
ax2.set_title(
f"{name} Returns Partial Auto-Correlation",
f"{symbol} Returns Partial Auto-Correlation",
fontsize=9,
)
# Diff Diff Auto-correlation function for original time series
sm.graphics.tsa.plot_acf(np.diff(np.diff(df.values)), lags=lags, ax=ax3)
sm.graphics.tsa.plot_acf(np.diff(np.diff(data.values)), lags=lags, ax=ax3)
ax3.set_title(
f"Change in {name} Returns Auto-Correlation",
f"Change in {symbol} Returns Auto-Correlation",
fontsize=9,
)
# Diff Diff Partial auto-correlation function for original time series
sm.graphics.tsa.plot_pacf(np.diff(np.diff(df.values)), lags=lags, ax=ax4)
sm.graphics.tsa.plot_pacf(np.diff(np.diff(data.values)), lags=lags, ax=ax4)
ax4.set_title(
f"Change in {name} Returns Partial Auto-Correlation",
f"Change in {symbol} Returns Partial Auto-Correlation",
fontsize=9,
)
@@ -431,9 +435,9 @@ def display_acf(
@log_start_end(log=logger)
def display_qqplot(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
symbol: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Show QQ plot for data against normal quantiles
@@ -442,16 +446,18 @@ def display_qqplot(
----------
name : str
Stock ticker
df : pd.DataFrame
data : pd.DataFrame
Dataframe
target : str
Column in data to look at
name : str
Stock ticker
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
# Statsmodels has a UserWarning for marker kwarg-- which we don't use
warnings.filterwarnings(category=UserWarning, action="ignore")
data = df[target]
data = data[target]
# This plot has 1 axis
if external_axes is None:
@@ -474,7 +480,7 @@ def display_qqplot(
)
ax.get_lines()[1].set_color(theme.up_color)
ax.set_title(f"Q-Q plot for {name} {target}")
ax.set_title(f"Q-Q plot for {symbol} {target}")
ax.set_ylabel("Sample quantiles")
ax.set_xlabel("Theoretical quantiles")
@@ -486,17 +492,17 @@ def display_qqplot(
@log_start_end(log=logger)
def display_cusum(
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
threshold: float,
drift: float,
threshold: float = 5,
drift: float = 2.1,
external_axes: Optional[List[plt.Axes]] = None,
):
"""Cumulative sum algorithm (CUSUM) to detect abrupt changes in data
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
Dataframe
target : str
Column of data to look at
@@ -507,11 +513,11 @@ def display_cusum(
external_axes : Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
target_series = df[target].values
target_series = data[target].values
# The code for this plot was adapted from detecta's sources because at the
# time of writing this detect_cusum had a bug related to external axes support.
# see https://github.com/demotu/detecta/pull/3
# see https: // github.com/demotu/detecta/pull/3
tap, tan = 0, 0
ta, tai, taf, _ = detect_cusum(
x=target_series,
@@ -549,7 +555,7 @@ def display_cusum(
else:
return
target_series_indexes = range(df[target].size)
target_series_indexes = range(data[target].size)
ax1.plot(target_series_indexes, target_series)
if len(ta):
ax1.plot(
@@ -615,7 +621,7 @@ def display_cusum(
@log_start_end(log=logger)
def display_seasonal(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
multiplicative: bool = False,
export: str = "",
@@ -627,18 +633,18 @@ def display_seasonal(
----------
name : str
Name of dataset
df : pd.DataFrame
data : pd.DataFrame
DataFrame
target : str
Column of data to look at
multiplicative : bool
Boolean to indicate multiplication instead of addition
export : str
Format to export trend and cycle df
Format to export trend and cycle data
external_axes : Optional[List[plt.Axes]], optional
External axes (6 axes are expected in the list), by default None
"""
data = df[target]
data = data[target]
result, cycle, trend = qa_model.get_seasonal_decomposition(data, multiplicative)
plot_data = pd.merge(
@@ -740,7 +746,7 @@ def display_seasonal(
)
theme.visualize_output(force_tight_layout=False)
# From # https://otexts.com/fpp2/seasonal-strength.html
# From #https: // otexts.com/fpp2/seasonal-strength.html
console.print("Time-Series Level is " + str(round(data.mean(), 2)))
Ft = max(0, 1 - np.var(result.resid)) / np.var(result.trend + result.resid)
@@ -761,19 +767,19 @@ def display_seasonal(
@log_start_end(log=logger)
def display_normality(df: pd.DataFrame, target: str, export: str = ""):
def display_normality(data: pd.DataFrame, target: str, export: str = ""):
"""View normality statistics
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
DataFrame
target : str
Column in data to look at
export : str
Format to export data
"""
data = df[target]
data = data[target]
normal = qa_model.get_normality(data)
stats1 = normal.copy().T
stats1.iloc[:, 1] = stats1.iloc[:, 1].apply(lambda x: lambda_color_red(x))
@@ -796,25 +802,29 @@ def display_normality(df: pd.DataFrame, target: str, export: str = ""):
@log_start_end(log=logger)
def display_unitroot(
df: pd.DataFrame, target: str, fuller_reg: str, kpss_reg: str, export: str = ""
data: pd.DataFrame,
target: str,
fuller_reg: str = "c",
kpss_reg: str = "c",
export: str = "",
):
"""Show unit root test calculations
Parameters
----------
df : pd.DataFrame
data : pd.DataFrame
DataFrame
target : str
Column of data to look at
fuller_reg : str
Type of regression of ADF test
Type of regression of ADF test. Can be ‘c’,’ct’,’ctt’,’nc’ 'c' - Constant and t - trend order
kpss_reg : str
Type of regression for KPSS test
Type of regression for KPSS test. Can be ‘c’,’ct'
export : str
Format for exporting data
"""
df = df[target]
data = qa_model.get_unitroot(df, fuller_reg, kpss_reg)
data = data[target]
data = qa_model.get_unitroot(data, fuller_reg, kpss_reg)
print_rich_table(
data,
show_index=True,
@@ -833,19 +843,23 @@ def display_unitroot(
@log_start_end(log=logger)
def display_raw(
df: pd.DataFrame, sort: str = "", des: bool = False, num: int = 20, export: str = ""
data: pd.DataFrame,
sortby: str = "",
descend: bool = False,
limit: int = 20,
export: str = "",
) -> None:
"""Return raw stock data
Parameters
----------
df : DataFrame
data : DataFrame
DataFrame with historical information
sort : str
sortby : str
The column to sort by
des : bool
descend : bool
Whether to sort descending
num : int
limit : int
Number of rows to show
export : str
Export data as CSV, JSON, XLSX
@@ -855,22 +869,22 @@ def display_raw(
export,
os.path.dirname(os.path.abspath(__file__)),
"history",
df,
data,
)
if isinstance(df, pd.Series):
df1 = pd.DataFrame(df)
if isinstance(data, pd.Series):
df1 = pd.DataFrame(data)
else:
df1 = df.copy()
df1 = data.copy()
if sort:
df1 = df.sort_values(
by=sort if sort != "AdjClose" else "Adj Close", ascending=des
if sortby:
df1 = data.sort_values(
by=sortby if sortby != "AdjClose" else "Adj Close", ascending=descend
)
df1.index = [x.strftime("%Y-%m-%d") for x in df1.index]
print_rich_table(
df1.head(num) if sort else df1.tail(num),
df1.head(limit) if sortby else df1.tail(limit),
headers=[x.title() if x != "" else "Date" for x in df1.columns],
title="[bold]Raw Data[/bold]",
show_index=True,
@@ -990,7 +1004,7 @@ def display_line(
def display_var(
data: pd.DataFrame,
ticker: str = "",
name: str = "",
use_mean: bool = False,
adjusted_var: bool = False,
student_t: bool = False,
@@ -1003,11 +1017,11 @@ def display_var(
Parameters
----------
data: pd.Dataframe
stock dataframe
Data dataframe
use_mean: bool
if one should use the stocks mean return
ticker: str
ticker of the stock
if one should use the data mean return
name: str
name of the data
adjusted_var: bool
if one should have VaR adjusted for skew and kurtosis (Cornish-Fisher-Expansion)
student_t: bool
@@ -1041,8 +1055,8 @@ def display_var(
str_var_label = "VaR:"
str_title = ""
if ticker != "":
ticker += " "
if name != "":
name += " "
data_dictionary = {str_var_label: var_list, str_hist_label: hist_var_list}
data = pd.DataFrame(
@@ -1053,14 +1067,14 @@ def display_var(
data,
show_index=True,
headers=list(data.columns),
title=f"[bold]{ticker}{str_title}Value at Risk[/bold]",
title=f"[bold]{name}{str_title}Value at Risk[/bold]",
floatfmt=".4f",
)
def display_es(
data: pd.DataFrame,
ticker: str = "",
name: str = "",
use_mean: bool = False,
distribution: str = "normal",
percentile: float = 0.999,
@@ -1071,11 +1085,11 @@ def display_es(
Parameters
----------
data: pd.DataFrame
stock dataframe
Data dataframe
use_mean:
if one should use the stocks mean return
ticker: str
ticker of the stock
if one should use the data mean return
name: str
name of the data
distribution: str
choose distribution to use: logistic, laplace, normal
percentile: int
@@ -1102,8 +1116,8 @@ def display_es(
str_es_label = "ES:"
str_title = ""
if ticker != "":
ticker += " "
if name != "":
name += " "
data_dictionary = {str_es_label: es_list, str_hist_label: hist_es_list}
data = pd.DataFrame(
@@ -1114,12 +1128,12 @@ def display_es(
data,
show_index=True,
headers=list(data.columns),
title=f"[bold]{ticker}{str_title}Expected Shortfall[/bold]",
title=f"[bold]{name}{str_title}Expected Shortfall[/bold]",
floatfmt=".4f",
)
def display_sharpe(data: pd.DataFrame, rfr: float, window: float):
def display_sharpe(data: pd.DataFrame, rfr: float = 0, window: float = 252):
"""Calculates the sharpe ratio
Parameters
----------

View File

@@ -13,52 +13,58 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_rolling_avg(df: pd.DataFrame, length: int) -> Tuple[pd.DataFrame, pd.DataFrame]:
def get_rolling_avg(
data: pd.DataFrame, window: int = 14
) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""Return rolling mean and standard deviation
Parameters
----------
df_stock : pd.DataFrame
data: pd.DataFrame
Dataframe of target data
length : int
window: int
Length of rolling window
Returns
-------
pd.DataFrame :
pd.DataFrame:
Dataframe of rolling mean
pd.DataFrame :
pd.DataFrame:
Dataframe of rolling standard deviation
"""
rolling_mean = df.rolling(length, center=True, min_periods=1).mean()
rolling_std = df.rolling(length, center=True, min_periods=1).std()
rolling_mean = data.rolling(window, center=True, min_periods=1).mean()
rolling_std = data.rolling(window, center=True, min_periods=1).std()
return pd.DataFrame(rolling_mean), pd.DataFrame(rolling_std)
@log_start_end(log=logger)
def get_spread(df: pd.DataFrame, length: int) -> Tuple[pd.DataFrame, pd.DataFrame]:
def get_spread(
data: pd.DataFrame, window: int = 14
) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""Standard Deviation and Variance
Parameters
----------
df_stock : pd.DataFrame
data: pd.DataFrame
DataFrame of targeted data
window: int
Length of window
Returns
-------
df_sd : pd.DataFrame
df_sd: pd.DataFrame
Dataframe of rolling standard deviation
df_var : pd.DataFrame
df_var: pd.DataFrame
Dataframe of rolling standard deviation
"""
df_sd = ta.stdev(
close=df,
length=length,
close=data,
length=window,
).dropna()
df_var = ta.variance(
close=df,
length=length,
close=data,
length=window,
).dropna()
return pd.DataFrame(df_sd), pd.DataFrame(df_var)
@@ -66,17 +72,17 @@ def get_spread(df: pd.DataFrame, length: int) -> Tuple[pd.DataFrame, pd.DataFram
@log_start_end(log=logger)
def get_quantile(
df: pd.DataFrame, length: int, quantile_pct: float
data: pd.DataFrame, limit: int = 14, quantile_pct: float = 0.5
) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""Overlay Median & Quantile
Parameters
----------
df : pd.DataFrame
data: pd.DataFrame
Dataframe of targeted data
length : int
limit : int
Length of window
quantile : float
quantile_pct: float
Quantile to display
Returns
@@ -86,10 +92,10 @@ def get_quantile(
df_quantile : pd.DataFrame
Dataframe of gievn quantile prices over window
"""
df_med = ta.median(close=df, length=length).dropna()
df_med = ta.median(close=data, length=limit).dropna()
df_quantile = ta.quantile(
df,
length=length,
data,
length=limit,
q=quantile_pct,
).dropna()
@@ -97,34 +103,34 @@ def get_quantile(
@log_start_end(log=logger)
def get_skew(df: pd.DataFrame, length: int) -> pd.DataFrame:
def get_skew(data: pd.DataFrame, window: int = 14) -> pd.DataFrame:
"""Skewness Indicator
Parameters
----------
df_stock : pd.DataFrame
data: pd.DataFrame
Dataframe of targeted data
length : int
window : int
Length of window
Returns
-------
df_skew : pd.DataFrame
data_skew : pd.DataFrame
Dataframe of rolling skew
"""
df_skew = ta.skew(close=df, length=length).dropna()
df_skew = ta.skew(close=data, length=window).dropna()
return df_skew
@log_start_end(log=logger)
def get_kurtosis(df: pd.DataFrame, length: int) -> pd.DataFrame:
def get_kurtosis(data: pd.DataFrame, window: int = 14) -> pd.DataFrame:
"""Kurtosis Indicator
Parameters
----------
df_stock : pd.DataFrame
data: pd.DataFrame
Dataframe of targeted data
length : int
window: int
Length of window
Returns
@@ -132,5 +138,5 @@ def get_kurtosis(df: pd.DataFrame, length: int) -> pd.DataFrame:
df_kurt : pd.DataFrame
Dataframe of rolling kurtosis
"""
df_kurt = ta.kurtosis(close=df, length=length).dropna()
df_kurt = ta.kurtosis(close=data, length=window).dropna()
return df_kurt

View File

@@ -25,10 +25,10 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_mean_std(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
window: int,
symbol: str = "",
limit: int = 14,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -36,21 +36,21 @@ def display_mean_std(
Parameters
----------
name : str
Stock ticker
df : pd.DataFrame
data: pd.DataFrame
Dataframe
target : str
target: str
Column in data to look at
window : int
symbol : str
Stock ticker
limit : int
Length of window
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
data = df[target]
rolling_mean, rolling_std = rolling_model.get_rolling_avg(data, window)
data = data[target]
rolling_mean, rolling_std = rolling_model.get_rolling_avg(data, limit)
plot_data = pd.merge(
data,
rolling_mean,
@@ -87,7 +87,7 @@ def display_mean_std(
ax1.plot(
plot_data.index,
plot_data[target].values,
label=name,
label=symbol,
)
ax1.plot(
plot_data.index,
@@ -97,7 +97,7 @@ def display_mean_std(
"Values",
)
ax1.legend(["Real Values", "Rolling Mean"])
ax1.set_title(f"Rolling mean and std (window {str(window)}) of {name} {target}")
ax1.set_title(f"Rolling mean and std (window {str(limit)}) of {symbol} {target}")
ax1.set_xlim([plot_data.index[0], plot_data.index[-1]])
ax2.plot(
@@ -134,10 +134,10 @@ def display_mean_std(
@log_start_end(log=logger)
def display_spread(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
window: int,
symbol: str = "",
limit: int = 14,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -145,21 +145,23 @@ def display_spread(
Parameters
----------
name : str
Stock ticker
df : pd.DataFrame
data: pd.DataFrame
Dataframe
target: str
Column in data to look at
window : int
target: str
Column in data to look at
symbol : str
Stock ticker
limit : int
Length of window
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (3 axes are expected in the list), by default None
"""
data = df[target]
df_sd, df_var = rolling_model.get_spread(data, window)
data = data[target]
df_sd, df_var = rolling_model.get_spread(data, limit)
plot_data = pd.merge(
data,
@@ -197,18 +199,18 @@ def display_spread(
ax1.plot(plot_data.index, plot_data[target].values)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Value")
ax1.set_title(f"Spread of {name} {target}")
ax1.set_title(f"Spread of {symbol} {target}")
ax2.plot(
plot_data[f"STDEV_{window}"].index,
plot_data[f"STDEV_{window}"].values,
plot_data[f"STDEV_{limit}"].index,
plot_data[f"STDEV_{limit}"].values,
label="Stdev",
)
ax2.set_ylabel("Stdev")
ax3.plot(
plot_data[f"VAR_{window}"].index,
plot_data[f"VAR_{window}"].values,
plot_data[f"VAR_{limit}"].index,
plot_data[f"VAR_{limit}"].values,
label="Variance",
)
ax3.set_ylabel("Variance")
@@ -242,11 +244,11 @@ def display_spread(
@log_start_end(log=logger)
def display_quantile(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
window: int,
quantile: float,
symbol: str = "",
limit: int = 14,
quantile: float = 0.5,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -254,23 +256,23 @@ def display_quantile(
Parameters
----------
name : str
Stock ticker
df : pd.DataFrame
data: pd.DataFrame
Dataframe
target : str
target: str
Column in data to look at
window : int
symbol : str
Stock ticker
limit : int
Length of window
quantile : float
quantile: float
Quantile to get
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
data = df[target]
df_med, df_quantile = rolling_model.get_quantile(data, window, quantile)
data = data[target]
df_med, df_quantile = rolling_model.get_quantile(data, limit, quantile)
plot_data = pd.merge(
data,
@@ -301,22 +303,22 @@ def display_quantile(
else:
return
ax.set_title(f"{name} {target} Median & Quantile")
ax.set_title(f"{symbol} {target} Median & Quantile")
ax.plot(plot_data.index, plot_data[target].values, label=target)
ax.plot(
plot_data.index,
plot_data[f"MEDIAN_{window}"].values,
label=f"Median w={window}",
plot_data[f"MEDIAN_{limit}"].values,
label=f"Median w={limit}",
)
ax.plot(
plot_data.index,
plot_data[f"QTL_{window}_{quantile}"].values,
plot_data[f"QTL_{limit}_{quantile}"].values,
label=f"Quantile q={quantile}",
linestyle="--",
)
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
ax.set_ylabel(f"{name} Value")
ax.set_ylabel(f"{symbol} Value")
ax.legend()
theme.style_primary_axis(
@@ -339,9 +341,9 @@ def display_quantile(
@log_start_end(log=logger)
def display_skew(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
window: int,
window: int = 14,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -349,20 +351,20 @@ def display_skew(
Parameters
----------
name : str
name: str
Stock ticker
df : pd.DataFrame
data: pd.DataFrame
Dataframe
target : str
target: str
Column in data to look at
window : int
window: int
Length of window
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
data = df[target]
data = data[target]
df_skew = rolling_model.get_skew(data, window)
plot_data = pd.merge(
@@ -423,9 +425,9 @@ def display_skew(
@log_start_end(log=logger)
def display_kurtosis(
name: str,
df: pd.DataFrame,
data: pd.DataFrame,
target: str,
window: int,
window: int = 14,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -433,18 +435,20 @@ def display_kurtosis(
Parameters
----------
name : str
name: str
Ticker
df : pd.DataFrame
data: pd.DataFrame
Dataframe of stock prices
window : int
target: str
Column in data to look at
window: int
Length of window
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
data = df[target]
data = data[target]
df_kurt = rolling_model.get_kurtosis(data, window)
plot_data = pd.merge(

View File

@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def calculate_fib_levels(
df_stock: pd.DataFrame,
data: pd.DataFrame,
period: int = 120,
open_date: Any = None,
close_date: Any = None,
@@ -23,7 +23,7 @@ def calculate_fib_levels(
Parameters
----------
df_stock : pd.DataFrame
data : pd.DataFrame
Dataframe of prices
period : int
Days to look back for retracement
@@ -46,31 +46,31 @@ def calculate_fib_levels(
Price at max point
"""
if open_date and close_date:
if open_date not in df_stock.index:
date0 = df_stock.index[df_stock.index.get_loc(open_date, method="nearest")]
console.print(f"Start date not in df_stock. Using nearest: {date0}")
if open_date not in data.index:
date0 = data.index[data.index.get_loc(open_date, method="nearest")]
console.print(f"Start date not in data. Using nearest: {date0}")
else:
date0 = open_date
if close_date not in df_stock.index:
date1 = df_stock.index[df_stock.index.get_loc(close_date, method="nearest")]
console.print(f"End date not in df_stock. Using nearest: {date1}")
if close_date not in data.index:
date1 = data.index[data.index.get_loc(close_date, method="nearest")]
console.print(f"End date not in data. Using nearest: {date1}")
else:
date1 = close_date
df_stock0 = df_stock.loc[date0, "Adj Close"]
df_stock1 = df_stock.loc[date1, "Adj Close"]
data0 = data.loc[date0, "Adj Close"]
data1 = data.loc[date1, "Adj Close"]
min_pr = min(df_stock0, df_stock1)
max_pr = max(df_stock0, df_stock1)
min_pr = min(data0, data1)
max_pr = max(data0, data1)
if min_pr == df_stock0:
if min_pr == data0:
min_date = date0
max_date = date1
else:
min_date = date1
max_date = date0
else:
data_to_use = df_stock.iloc[period:]["Adj Close"]
data_to_use = data.iloc[period:]["Adj Close"]
min_pr = data_to_use.min()
min_date = data_to_use.idxmin()

View File

@@ -26,11 +26,11 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def fibonacci_retracement(
ohlc: pd.DataFrame,
data: pd.DataFrame,
period: int = 120,
start_date: Optional[Union[str, None]] = None,
end_date: Optional[Union[str, None]] = None,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -38,16 +38,16 @@ def fibonacci_retracement(
Parameters
----------
ohlc: pd.DataFrame
Stock data
data: pd.DataFrame
OHLC data
period: int
Days to lookback
start_date: Optional[str, None]
User picked date for starting retracement
end_date: Optional[str, None]
User picked date for ending retracement
s_ticker:str
Stock ticker
symbol: str
Ticker symbol
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
@@ -59,11 +59,11 @@ def fibonacci_retracement(
max_date,
min_pr,
max_pr,
) = custom_indicators_model.calculate_fib_levels(ohlc, period, start_date, end_date)
) = custom_indicators_model.calculate_fib_levels(data, period, start_date, end_date)
levels = df_fib.Price
plot_data = reindex_dates(ohlc)
plot_data = reindex_dates(data)
# This plot has 2 axes
if external_axes is None:
@@ -79,7 +79,7 @@ def fibonacci_retracement(
ax1.plot(plot_data["Adj Close"])
if is_intraday(ohlc):
if is_intraday(data):
date_format = "%b %d %H:%M"
else:
date_format = "%Y-%m-%d"
@@ -101,7 +101,7 @@ def fibonacci_retracement(
ax1.fill_between(plot_data.index, levels[i], levels[i + 1], alpha=0.15)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_title(f"Fibonacci Support for {s_ticker.upper()}")
ax1.set_title(f"Fibonacci Support for {symbol.upper()}")
ax1.set_yticks(levels)
ax1.set_yticklabels([0, 0.235, 0.382, 0.5, 0.618, 0.65, 1])
theme.style_primary_axis(

View File

@@ -20,7 +20,7 @@ def cci(
high_vals: pd.Series,
low_vals: pd.Series,
close_vals: pd.Series,
length: int = 14,
window: int = 14,
scalar: float = 0.0015,
) -> pd.DataFrame:
"""Commodity channel index
@@ -33,7 +33,7 @@ def cci(
Low values
close-values: pd.Series
Close values
length: int
window: int
Length of window
scalar: float
Scalar variable
@@ -48,7 +48,7 @@ def cci(
high=high_vals,
low=low_vals,
close=close_vals,
length=length,
length=window,
scalar=scalar,
).dropna()
)
@@ -85,7 +85,7 @@ def macd(
@log_start_end(log=logger)
def rsi(
values: pd.Series, length: int = 14, scalar: float = 100, drift: int = 1
values: pd.Series, window: int = 14, scalar: float = 100, drift: int = 1
) -> pd.DataFrame:
"""Relative strength index
@@ -93,7 +93,7 @@ def rsi(
----------
values: pd.Series
Dataframe of prices
length: int
window: int
Length of window
scalar: float
Scalar variable
@@ -106,7 +106,7 @@ def rsi(
Dataframe of technical indicator
"""
return pd.DataFrame(
ta.rsi(values, length=length, scalar=scalar, drift=drift).dropna()
ta.rsi(values, length=window, scalar=scalar, drift=drift).dropna()
)
@@ -153,7 +153,7 @@ def stoch(
@log_start_end(log=logger)
def fisher(high_vals: pd.Series, low_vals: pd.Series, length: int = 14) -> pd.DataFrame:
def fisher(high_vals: pd.Series, low_vals: pd.Series, window: int = 14) -> pd.DataFrame:
"""Fisher Transform
Parameters
@@ -162,7 +162,7 @@ def fisher(high_vals: pd.Series, low_vals: pd.Series, length: int = 14) -> pd.Da
High values
low_vals: pd.Series
Low values
length: int
window: int
Length for indicator window
Returns
----------
@@ -170,39 +170,39 @@ def fisher(high_vals: pd.Series, low_vals: pd.Series, length: int = 14) -> pd.Da
Dataframe of technical indicator
"""
# Daily
return pd.DataFrame(ta.fisher(high=high_vals, low=low_vals, length=length).dropna())
return pd.DataFrame(ta.fisher(high=high_vals, low=low_vals, length=window).dropna())
@log_start_end(log=logger)
def cg(values: pd.Series, length: int) -> pd.DataFrame:
def cg(values: pd.Series, window: int) -> pd.DataFrame:
"""Center of gravity
Parameters
----------
values: pd.DataFrame
Data to use with close being titled values
length: int
window: int
Length for indicator window
Returns
----------
d.DataFrame
Dataframe of technical indicator
"""
return pd.DataFrame(ta.cg(close=values, length=length).dropna())
return pd.DataFrame(ta.cg(close=values, length=window).dropna())
@log_start_end(log=logger)
def clenow_momentum(
values: pd.Series, length: int = 90
values: pd.Series, window: int = 90
) -> Tuple[float, float, pd.Series]:
"""Gets the Clenow Volatility Adjusted Momentum. this is defined as the regression coefficient on log prices
multiplied by the R^2 value of the regression
Parameters
----------
values:pd.Series
values: pd.Series
Values to perform regression for
length: int
window: int
Length of lookback period
Returns
@@ -214,13 +214,13 @@ def clenow_momentum(
pd.Series:
Values for best fit line
"""
if len(values) < length:
if len(values) < window:
console.print(
f"[red]Calculation asks for at least last {length} days of data[/red]"
f"[red]Calculation asks for at least last {window} days of data[/red]"
)
return np.nan, np.nan, pd.Series()
values = values[-length:]
values = values[-window:]
y = np.log(values)
X = np.arange(len(y)).reshape(-1, 1)

View File

@@ -29,10 +29,10 @@ register_matplotlib_converters()
@log_start_end(log=logger)
def display_cci(
ohlc: pd.DataFrame,
length: int = 14,
data: pd.DataFrame,
window: int = 14,
scalar: float = 0.0015,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -41,13 +41,13 @@ def display_cci(
Parameters
----------
ohlc : pd.DataFrame
data : pd.DataFrame
Dataframe of OHLC
length : int
window : int
Length of window
scalar : float
Scalar variable
s_ticker : str
symbol : str
Stock ticker
export : str
Format to export data
@@ -55,9 +55,9 @@ def display_cci(
External axes (2 axes are expected in the list), by default None
"""
df_ta = momentum_model.cci(
ohlc["High"], ohlc["Low"], ohlc["Adj Close"], length, scalar
data["High"], data["Low"], data["Adj Close"], window, scalar
)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 2 axes
@@ -71,7 +71,7 @@ def display_cci(
else:
return
ax1.set_title(f"{s_ticker} CCI")
ax1.set_title(f"{symbol} CCI")
ax1.plot(
plot_data.index,
plot_data["Adj Close"].values,
@@ -123,7 +123,7 @@ def display_macd(
n_fast: int = 12,
n_slow: int = 26,
n_signal: int = 9,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -139,7 +139,7 @@ def display_macd(
Slow period
n_signal : int
Signal period
s_ticker : str
symbol : str
Stock ticker
export : str
Format to export data
@@ -161,7 +161,7 @@ def display_macd(
else:
return
ax1.set_title(f"{s_ticker} MACD")
ax1.set_title(f"{symbol} MACD")
ax1.plot(plot_data.index, plot_data.iloc[:, 1].values)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Share Price ($)")
@@ -207,10 +207,10 @@ def display_macd(
@log_start_end(log=logger)
def display_rsi(
series: pd.Series,
length: int = 14,
window: int = 14,
scalar: float = 100.0,
drift: int = 1,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -220,20 +220,20 @@ def display_rsi(
----------
series : pd.Series
Values to input
length : int
window : int
Length of window
scalar : float
Scalar variable
drift : int
Drift variable
s_ticker : str
symbol : str
Stock ticker
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
df_ta = momentum_model.rsi(series, length, scalar, drift)
df_ta = momentum_model.rsi(series, window, scalar, drift)
# This plot has 2 axes
if external_axes is None:
@@ -250,7 +250,7 @@ def display_rsi(
plot_data = reindex_dates(plot_data)
ax1.plot(plot_data.index, plot_data.iloc[:, 1].values)
ax1.set_title(f"{s_ticker} RSI{length}")
ax1.set_title(f"{symbol} RSI{window}")
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Share Price ($)")
theme.style_primary_axis(
@@ -291,11 +291,11 @@ def display_rsi(
@log_start_end(log=logger)
def display_stoch(
ohlc: pd.DataFrame,
data: pd.DataFrame,
fastkperiod: int = 14,
slowdperiod: int = 3,
slowkperiod: int = 3,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -303,25 +303,25 @@ def display_stoch(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of prices
data : pd.DataFrame
Dataframe of OHLC prices
fastkperiod : int
Fast k period
slowdperiod : int
Slow d period
slowkperiod : int
Slow k period
s_ticker : str
Stock ticker
symbol : str
Stock ticker symbol
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (3 axes are expected in the list), by default None
"""
df_ta = momentum_model.stoch(
ohlc["High"],
ohlc["Low"],
ohlc["Adj Close"],
data["High"],
data["Low"],
data["Adj Close"],
fastkperiod,
slowdperiod,
slowkperiod,
@@ -338,12 +338,12 @@ def display_stoch(
else:
return
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_title(f"Stochastic Relative Strength Index (STOCH RSI) on {s_ticker}")
ax1.set_title(f"Stochastic Relative Strength Index (STOCH RSI) on {symbol}")
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Share Price ($)")
theme.style_primary_axis(
@@ -385,9 +385,9 @@ def display_stoch(
@log_start_end(log=logger)
def display_fisher(
ohlc: pd.DataFrame,
length: int = 14,
s_ticker: str = "",
data: pd.DataFrame,
window: int = 14,
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -395,19 +395,19 @@ def display_fisher(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of prices
length : int
data : pd.DataFrame
Dataframe of OHLC prices
window : int
Length of window
s_ticker : str
symbol : str
Ticker string
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (3 axes are expected in the list), by default None
"""
df_ta = momentum_model.fisher(ohlc["High"], ohlc["Low"], length)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
df_ta = momentum_model.fisher(data["High"], data["Low"], window)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 3 axes
@@ -422,7 +422,7 @@ def display_fisher(
else:
return
ax1.set_title(f"{s_ticker} Fisher Transform")
ax1.set_title(f"{symbol} Fisher Transform")
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
@@ -474,8 +474,8 @@ def display_fisher(
@log_start_end(log=logger)
def display_cg(
series: pd.Series,
length: int = 14,
s_ticker: str = "",
window: int = 14,
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -485,16 +485,16 @@ def display_cg(
----------
series : pd.Series
Series of values
length : int
window : int
Length of window
s_ticker : str
symbol : str
Stock ticker
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
df_ta = momentum_model.cg(series, length)
df_ta = momentum_model.cg(series, window)
plot_data = pd.merge(series, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
@@ -509,7 +509,7 @@ def display_cg(
else:
return
ax1.set_title(f"{s_ticker} Centre of Gravity")
ax1.set_title(f"{symbol} Centre of Gravity")
ax1.plot(plot_data.index, plot_data[series.name].values)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Share Price ($)")
@@ -545,23 +545,28 @@ def display_cg(
@log_start_end(log=logger)
def display_clenow_momentum(
series: pd.Series,
length: int = 90,
window: int = 90,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""
"""Display clenow momentum
Parameters
----------
series
length
export
series : pd.Series
Series of values
window : int
Length of window
export : str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
Returns
-------
"""
r2, coef, fit_data = momentum_model.clenow_momentum(series, length)
r2, coef, fit_data = momentum_model.clenow_momentum(series, window)
df = pd.DataFrame.from_dict(
{
@@ -589,7 +594,7 @@ def display_clenow_momentum(
return
ax1.plot(series.index, np.log(series.values))
ax1.plot(series.index[-length:], fit_data, linewidth=2)
ax1.plot(series.index[-window:], fit_data, linewidth=2)
ax1.set_title("Clenow Momentum Exponential Regression")
ax1.set_xlim(series.index[0], series.index[-1])

View File

@@ -15,12 +15,12 @@ WINDOW_LENGTHS2 = [10, 20]
@log_start_end(log=logger)
def ema(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
def ema(data: pd.DataFrame, length: int, offset: int = 0) -> pd.DataFrame:
"""Gets exponential moving average (EMA) for stock
Parameters
----------
values: pd.DataFrame
data: pd.DataFrame
Dataframe of dates and prices
length: int
Length of EMA window
@@ -32,16 +32,16 @@ def ema(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
pd.DataFrame
Dataframe containing prices and EMA
"""
return pd.DataFrame(ta.ema(values, length=length, offset=offset)).dropna()
return pd.DataFrame(ta.ema(data, length=length, offset=offset)).dropna()
@log_start_end(log=logger)
def sma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
def sma(data: pd.DataFrame, length: int, offset: int = 0) -> pd.DataFrame:
"""Gets simple moving average (EMA) for stock
Parameters
----------
values: pd.DataFrame
data: pd.DataFrame
Dataframe of dates and prices
length: int
Length of SMA window
@@ -53,16 +53,16 @@ def sma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
pd.DataFrame
Dataframe containing prices and SMA
"""
return pd.DataFrame(ta.sma(values, length=length, offset=offset)).dropna()
return pd.DataFrame(ta.sma(data, length=length, offset=offset)).dropna()
@log_start_end(log=logger)
def wma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
def wma(data: pd.DataFrame, length: int, offset: int = 0) -> pd.DataFrame:
"""Gets weighted moving average (WMA) for stock
Parameters
----------
values: pd.DataFrame
data: pd.DataFrame
Dataframe of dates and prices
length: int
Length of SMA window
@@ -74,16 +74,16 @@ def wma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
df_ta: pd.DataFrame
Dataframe containing prices and WMA
"""
return pd.DataFrame(ta.wma(values, length=length, offset=offset)).dropna()
return pd.DataFrame(ta.wma(data, length=length, offset=offset)).dropna()
@log_start_end(log=logger)
def hma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
def hma(data: pd.DataFrame, length: int, offset: int = 0) -> pd.DataFrame:
"""Gets hull moving average (HMA) for stock
Parameters
----------
values: pd.DataFrame
data: pd.DataFrame
Dataframe of dates and prices
length: int
Length of SMA window
@@ -95,11 +95,11 @@ def hma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
df_ta: pd.DataFrame
Dataframe containing prices and HMA
"""
return pd.DataFrame(ta.hma(values, length=length, offset=offset)).dropna()
return pd.DataFrame(ta.hma(data, length=length, offset=offset)).dropna()
@log_start_end(log=logger)
def zlma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
def zlma(data: pd.DataFrame, length: int, offset: int = 0) -> pd.DataFrame:
"""Gets zero-lagged exponential moving average (ZLEMA) for stock
Parameters
@@ -116,16 +116,16 @@ def zlma(values: pd.DataFrame, length: int, offset: int) -> pd.DataFrame:
df_ta: pd.DataFrame
Dataframe containing prices and EMA
"""
return pd.DataFrame(ta.zlma(values, length=length, offset=offset)).dropna()
return pd.DataFrame(ta.zlma(data, length=length, offset=offset)).dropna()
@log_start_end(log=logger)
def vwap(df: pd.DataFrame, offset: int) -> pd.DataFrame:
def vwap(data: pd.DataFrame, offset: int = 0) -> pd.DataFrame:
"""Gets volume weighted average price (VWAP)
Parameters
----------
df: pd.DataFrame
data: pd.DataFrame
Dataframe of dates and prices
offset: int
Length of offset
@@ -136,10 +136,10 @@ def vwap(df: pd.DataFrame, offset: int) -> pd.DataFrame:
"""
df_vwap = ta.vwap(
high=df["High"],
low=df["Low"],
close=df["Close"],
volume=df["Volume"],
high=data["High"],
low=data["Low"],
close=data["Close"],
volume=data["Volume"],
offset=offset,
)

View File

@@ -4,7 +4,6 @@ __docformat__ = "numpy"
import logging
import os
from typing import List, Optional
from datetime import datetime
import matplotlib.pyplot as plt
import mplfinance as mpf
@@ -35,7 +34,7 @@ def view_ma(
length: List[int] = None,
offset: int = 0,
ma_type: str = "EMA",
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -43,23 +42,25 @@ def view_ma(
Parameters
----------
series : pd.Series
series: pd.Series
Series of prices
length : List[int]
length: List[int]
Length of EMA window
offset: int
Offset variable
ma_type: str
Type of moving average. Either "EMA" "ZLMA" or "SMA"
s_ticker : str
symbol: str
Ticker
export : str
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
# Define a dataframe for adding EMA series to it
price_df = pd.DataFrame(series)
l_legend = [s_ticker]
l_legend = [symbol]
if not length:
length = [20, 50]
@@ -93,11 +94,11 @@ def view_ma(
ax.plot(plot_data.index, plot_data.iloc[:, 1].values)
ax.set_xlim([plot_data.index[0], plot_data.index[-1]])
ax.set_ylabel(f"{s_ticker} Price")
ax.set_ylabel(f"{symbol} Price")
for idx in range(2, plot_data.shape[1]):
ax.plot(plot_data.iloc[:, idx])
ax.set_title(f"{s_ticker} {ma_type.upper()}")
ax.set_title(f"{symbol} {ma_type.upper()}")
ax.legend(l_legend)
theme.style_primary_axis(
ax,
@@ -118,28 +119,28 @@ def view_ma(
@log_start_end(log=logger)
def view_vwap(
s_ticker: str,
ohlc: pd.DataFrame,
start: datetime = None,
end: datetime = None,
data: pd.DataFrame,
symbol: str = "",
start_date: str = None,
end_date: str = None,
offset: int = 0,
s_interval: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Plots EMA technical indicator
"""Plots VWMA technical indicator
Parameters
----------
s_ticker : str
data : pd.DataFrame
Dataframe of OHLC prices
symbol : str
Ticker
ohlc : pd.DataFrame
Dataframe of prices
offset : int
Offset variable
start: datetime
start_date: datetime
Start date to get data from with
end: datetime
end_date: datetime
End date to get data from with
s_interval : str
Interval of data
@@ -149,21 +150,24 @@ def view_vwap(
External axes (3 axes are expected in the list), by default None
"""
ohlc.index = ohlc.index.tz_localize(None)
data.index = data.index.tz_localize(None)
if start and end:
start_date = start.date()
end_date = end.date()
if start_date is None:
start = data.index[0].date()
console.print(f"No start date specified. Start date: {start}")
else:
start_date = end_date = ohlc.index[-1].date()
console.print(
f"No Specified date range. load most recent trading data: {start_date.strftime('%Y-%m-%d')}"
)
start = start_date
day_df = ohlc[(start_date <= ohlc.index.date) & (ohlc.index.date <= end_date)]
if end_date is None:
end = data.index[-1].date()
console.print(f"No end date specified. End date: {end}")
else:
end = end_date
day_df = data[(start <= data.index.date) & (data.index.date <= end)]
if len(day_df) == 0:
console.print(
f"[red]No data found between {start_date.strftime('%Y-%m-%d')} and {end_date.strftime('%Y-%m-%d')}\n[/red]"
f"[red]No data found between {start.strftime('%Y-%m-%d')} and {end.strftime('%Y-%m-%d')}\n[/red]"
)
return
@@ -194,7 +198,7 @@ def view_vwap(
)
fig, ax = mpf.plot(day_df, **candle_chart_kwargs)
fig.suptitle(
f"{s_ticker} {s_interval} VWAP",
f"{symbol} {s_interval} VWAP",
x=0.055,
y=0.965,
horizontalalignment="left",

View File

@@ -16,7 +16,7 @@ def adx(
high_values: pd.Series,
low_values: pd.Series,
close_values: pd.Series,
length: int = 14,
window: int = 14,
scalar: int = 100,
drift: int = 1,
):
@@ -30,7 +30,7 @@ def adx(
Low prices
close_values: pd.Series
close prices
length: int
window: int
Length of window
scalar: int
Scalar variable
@@ -47,7 +47,7 @@ def adx(
high=high_values,
low=low_values,
close=close_values,
length=length,
length=window,
scalar=scalar,
drift=drift,
).dropna()
@@ -56,7 +56,7 @@ def adx(
@log_start_end(log=logger)
def aroon(
high_values: pd.Series, low_values: pd.Series, length: int = 25, scalar: int = 100
high_values: pd.Series, low_values: pd.Series, window: int = 25, scalar: int = 100
) -> pd.DataFrame:
"""Aroon technical indicator
@@ -66,7 +66,7 @@ def aroon(
High prices
low_values: pd.Series
Low prices
length : int
window : int
Length of window
scalar : int
Scalar variable
@@ -81,7 +81,7 @@ def aroon(
ta.aroon(
high=high_values,
low=low_values,
length=length,
length=window,
scalar=scalar,
).dropna()
)

View File

@@ -27,11 +27,11 @@ register_matplotlib_converters()
@log_start_end(log=logger)
def display_adx(
ohlc: pd.DataFrame,
length: int = 14,
data: pd.DataFrame,
window: int = 14,
scalar: int = 100,
drift: int = 1,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -39,15 +39,15 @@ def display_adx(
Parameters
----------
ohlc : pd.DataFrame
data : pd.DataFrame
Dataframe with OHLC price data
length : int
window : int
Length of window
scalar : int
Scalar variable
drift : int
Drift variable
s_ticker : str
symbol : str
Ticker
export : str
Format to export data
@@ -55,14 +55,14 @@ def display_adx(
External axes (2 axes are expected in the list), by default None
"""
df_ta = trend_indicators_model.adx(
high_values=ohlc["High"],
low_values=ohlc["Low"],
close_values=ohlc["Adj Close"],
length=length,
high_values=data["High"],
low_values=data["Low"],
close_values=data["Adj Close"],
window=window,
scalar=scalar,
drift=drift,
)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 2 axes
@@ -77,7 +77,7 @@ def display_adx(
return
ax1.plot(plot_data.index, plot_data["Close"].values)
ax1.set_title(f"Average Directional Movement Index (ADX) on {s_ticker}")
ax1.set_title(f"Average Directional Movement Index (ADX) on {symbol}")
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
theme.style_primary_axis(
@@ -120,10 +120,10 @@ def display_adx(
@log_start_end(log=logger)
def display_aroon(
ohlc: pd.DataFrame,
length: int = 25,
data: pd.DataFrame,
window: int = 25,
scalar: int = 100,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -131,26 +131,26 @@ def display_aroon(
Parameters
----------
ohlc : pd.DataFrame
data: pd.DataFrame
Dataframe with OHLC price data
length:int
window: int
Length of window
s_ticker : str
symbol: str
Ticker
scalar : int
scalar: int
Scalar variable
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (3 axes are expected in the list), by default None
"""
df_ta = trend_indicators_model.aroon(
high_values=ohlc["High"],
low_values=ohlc["Low"],
length=length,
high_values=data["High"],
low_values=data["Low"],
window=window,
scalar=scalar,
)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 3 axes
@@ -165,7 +165,7 @@ def display_aroon(
return
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_title(f"Aroon on {s_ticker}")
ax1.set_title(f"Aroon on {symbol}")
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
theme.style_primary_axis(

View File

@@ -15,7 +15,7 @@ MAMODES = ["ema", "sma", "wma", "hma", "zlma"]
@log_start_end(log=logger)
def bbands(
close_values: pd.Series, length: int = 15, n_std: float = 2, mamode: str = "ema"
close_values: pd.Series, window: int = 15, n_std: float = 2, mamode: str = "ema"
) -> pd.DataFrame:
"""Calculate Bollinger Bands
@@ -23,7 +23,7 @@ def bbands(
----------
close_values : pd.DataFrame
DataFrame of sclose prices
length : int
window : int
Length of window to calculate BB
n_std : float
Number of standard deviations to show
@@ -38,7 +38,7 @@ def bbands(
return pd.DataFrame(
ta.bbands(
close=close_values,
length=length,
length=window,
std=n_std,
mamode=mamode,
)
@@ -85,7 +85,7 @@ def kc(
high_prices: pd.Series,
low_prices: pd.Series,
close_prices: pd.Series,
length: int = 20,
window: int = 20,
scalar: float = 2,
mamode: str = "ema",
offset: int = 0,
@@ -94,14 +94,16 @@ def kc(
Parameters
----------
high_values : pd.DataFrame
high_prices : pd.DataFrame
High prices
low_values : pd.DataFrame
low_prices : pd.DataFrame
Low prices
close_values : pd.DataFrame
close_prices : pd.DataFrame
Close prices
length : int
window : int
Length of window
scalar: float
Scalar value
mamode: str
Type of filter
offset : int
@@ -118,7 +120,7 @@ def kc(
high=high_prices,
low=low_prices,
close=close_prices,
length=length,
length=window,
scalar=scalar,
mamode=mamode,
offset=offset,

View File

@@ -24,9 +24,9 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_bbands(
ohlc: pd.DataFrame,
ticker: str = "",
length: int = 15,
data: pd.DataFrame,
symbol: str = "",
limit: int = 15,
n_std: float = 2,
mamode: str = "sma",
export: str = "",
@@ -36,11 +36,11 @@ def display_bbands(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of stock prices
ticker : str
Ticker
length : int
data : pd.DataFrame
Dataframe of ohlc prices
symbol : str
Ticker symbol
limit : int
Length of window to calculate BB
n_std : float
Number of standard deviations to show
@@ -51,8 +51,8 @@ def display_bbands(
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df_ta = volatility_model.bbands(ohlc["Adj Close"], length, n_std, mamode)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
df_ta = volatility_model.bbands(data["Adj Close"], limit, n_std, mamode)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 1 axis
@@ -80,10 +80,10 @@ def display_bbands(
theme.up_color,
linewidth=0.7,
)
ax.set_title(f"{ticker} Bollinger Bands")
ax.set_title(f"{symbol} Bollinger Bands")
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
ax.set_ylabel("Share Price ($)")
ax.legend([ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
ax.fill_between(
df_ta.index, df_ta.iloc[:, 0].values, df_ta.iloc[:, 2].values, alpha=0.1
)
@@ -106,8 +106,8 @@ def display_bbands(
@log_start_end(log=logger)
def display_donchian(
ohlc: pd.DataFrame,
ticker: str = "",
data: pd.DataFrame,
symbol: str = "",
upper_length: int = 20,
lower_length: int = 20,
export: str = "",
@@ -117,10 +117,10 @@ def display_donchian(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of stock prices
ticker : str
Ticker
data : pd.DataFrame
Dataframe of ohlc prices
symbol : str
Ticker symbol
upper_length : int
Length of window to calculate upper channel
lower_length : int
@@ -131,9 +131,9 @@ def display_donchian(
External axes (1 axis is expected in the list), by default None
"""
df_ta = volatility_model.donchian(
ohlc["High"], ohlc["Low"], upper_length, lower_length
data["High"], data["Low"], upper_length, lower_length
)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 1 axis
@@ -164,10 +164,10 @@ def display_donchian(
plot_data[df_ta.columns[2]].values,
alpha=0.1,
)
ax.set_title(f"{ticker} donchian")
ax.set_title(f"{symbol} donchian")
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
ax.set_ylabel("Price ($)")
ax.legend([ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
theme.style_primary_axis(
ax,
data_index=plot_data.index.to_list(),
@@ -187,12 +187,12 @@ def display_donchian(
@log_start_end(log=logger)
def view_kc(
ohlc: pd.DataFrame,
length: int = 20,
data: pd.DataFrame,
limit: int = 20,
scalar: float = 2,
mamode: str = "ema",
offset: int = 0,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -201,31 +201,33 @@ def view_kc(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of stock prices
length : int
data: pd.DataFrame
Dataframe of ohlc prices
limit: int
Length of window
scalar: float
Scalar value
mamode: str
Type of filter
offset : int
offset: int
Offset value
s_ticker : str
Ticker
export : str
symbol: str
Ticker symbol
export: str
Format to export data
external_axes : Optional[List[plt.Axes]], optional
external_axes: Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
df_ta = volatility_model.kc(
ohlc["High"],
ohlc["Low"],
ohlc["Adj Close"],
length,
data["High"],
data["Low"],
data["Adj Close"],
limit,
scalar,
mamode,
offset,
)
plot_data = pd.merge(ohlc, df_ta, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_ta, how="outer", left_index=True, right_index=True)
plot_data = reindex_dates(plot_data)
# This plot has 1 axis
@@ -256,10 +258,10 @@ def view_kc(
plot_data[df_ta.columns[2]].values,
alpha=0.1,
)
ax.set_title(f"{s_ticker} Keltner Channels")
ax.set_title(f"{symbol} Keltner Channels")
ax.set_xlim(plot_data.index[0], plot_data.index[-1])
ax.set_ylabel("Price")
ax.legend([s_ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
ax.legend([symbol, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]])
theme.style_primary_axis(
ax,
data_index=plot_data.index.to_list(),

View File

@@ -12,12 +12,12 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def ad(df_stock: pd.DataFrame, use_open: bool = False) -> pd.DataFrame:
def ad(data: pd.DataFrame, use_open: bool = False) -> pd.DataFrame:
"""Calculate AD technical indicator
Parameters
----------
df_stock : pd.DataFrame
data : pd.DataFrame
Dataframe of prices with OHLC and Volume
use_open : bool
Whether to use open prices
@@ -29,35 +29,39 @@ def ad(df_stock: pd.DataFrame, use_open: bool = False) -> pd.DataFrame:
"""
if use_open:
df_ta = ta.ad(
high=df_stock["High"],
low=df_stock["Low"],
close=df_stock["Close"],
volume=df_stock["Volume"],
open_=df_stock["Open"],
high=data["High"],
low=data["Low"],
close=data["Close"],
volume=data["Volume"],
open_=data["Open"],
).dropna()
# Do not use open stock values
else:
df_ta = ta.ad(
high=df_stock["High"],
low=df_stock["Low"],
close=df_stock["Close"],
volume=df_stock["Volume"],
high=data["High"],
low=data["Low"],
close=data["Close"],
volume=data["Volume"],
).dropna()
return pd.DataFrame(df_ta)
@log_start_end(log=logger)
def adosc(
df_stock: pd.DataFrame, use_open: bool = False, fast: int = 3, slow: int = 10
data: pd.DataFrame, use_open: bool = False, fast: int = 3, slow: int = 10
) -> pd.DataFrame:
"""Calculate AD oscillator technical indicator
Parameters
----------
df_stock : pd.DataFrame
Dataframe of prices
data : pd.DataFrame
Dataframe of OHLC prices
use_open : bool
Whether to use open prices
fast: int
Fast value
slow: int
Slow value
Returns
-------
@@ -66,20 +70,20 @@ def adosc(
"""
if use_open:
df_ta = ta.adosc(
high=df_stock["High"],
low=df_stock["Low"],
close=df_stock["Close"],
volume=df_stock["Volume"],
open_=df_stock["Open"],
high=data["High"],
low=data["Low"],
close=data["Close"],
volume=data["Volume"],
open_=data["Open"],
fast=fast,
slow=slow,
).dropna()
else:
df_ta = ta.adosc(
high=df_stock["High"],
low=df_stock["Low"],
close=df_stock["Close"],
volume=df_stock["Volume"],
high=data["High"],
low=data["Low"],
close=data["Close"],
volume=data["Volume"],
fast=fast,
slow=slow,
).dropna()
@@ -87,19 +91,17 @@ def adosc(
@log_start_end(log=logger)
def obv(df_stock: pd.DataFrame) -> pd.DataFrame:
def obv(data: pd.DataFrame) -> pd.DataFrame:
"""On Balance Volume
Parameters
----------
df_stock: pd.DataFrame
Dataframe of stock prices
data: pd.DataFrame
Dataframe of OHLC prices
Returns
-------
pd.DataFrame
Dataframe with technical indicator
"""
return pd.DataFrame(
ta.obv(close=df_stock["Adj Close"], volume=df_stock["Volume"]).dropna()
)
return pd.DataFrame(ta.obv(close=data["Adj Close"], volume=data["Volume"]).dropna())

View File

@@ -24,9 +24,9 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_ad(
ohlc: pd.DataFrame,
data: pd.DataFrame,
use_open: bool = False,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -34,25 +34,25 @@ def display_ad(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of prices
data : pd.DataFrame
Dataframe of ohlc prices
use_open : bool
Whether to use open prices in calculation
s_ticker : str
Ticker
symbol : str
Ticker symbol
export: str
Format to export data as
external_axes : Optional[List[plt.Axes]], optional
External axes (3 axes are expected in the list), by default None
"""
divisor = 1_000_000
df_vol = ohlc["Volume"] / divisor
df_vol = data["Volume"] / divisor
df_vol.name = "Adj Volume"
df_ta = volume_model.ad(ohlc, use_open)
df_ta = volume_model.ad(data, use_open)
df_cal = df_ta["AD"] / divisor
df_cal.name = "Adj AD"
plot_data = pd.merge(ohlc, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(
plot_data, df_ta, how="outer", left_index=True, right_index=True
)
@@ -77,7 +77,7 @@ def display_ad(
return
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_title(f"{s_ticker} AD", x=0.08, y=1)
ax1.set_title(f"{symbol} AD", x=0.08, y=1)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
theme.style_primary_axis(
@@ -127,11 +127,11 @@ def display_ad(
@log_start_end(log=logger)
def display_adosc(
ohlc: pd.DataFrame,
data: pd.DataFrame,
fast: int = 3,
slow: int = 10,
use_open: bool = False,
s_ticker: str = "",
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -139,15 +139,15 @@ def display_adosc(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of prices
data : pd.DataFrame
Dataframe of ohlc prices
use_open : bool
Whether to use open prices in calculation
fast: int
Length of fast window
slow : int
Length of slow window
s_ticker : str
symbol : str
Stock ticker
export : str
Format to export data
@@ -155,13 +155,13 @@ def display_adosc(
External axes (3 axes are expected in the list), by default None
"""
divisor = 1_000_000
df_vol = ohlc["Volume"] / divisor
df_vol = data["Volume"] / divisor
df_vol.name = "Adj Volume"
df_ta = volume_model.adosc(ohlc, use_open, fast, slow)
df_ta = volume_model.adosc(data, use_open, fast, slow)
df_cal = df_ta[df_ta.columns[0]] / divisor
df_cal.name = "Adj ADOSC"
plot_data = pd.merge(ohlc, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(
plot_data, df_ta, how="outer", left_index=True, right_index=True
)
@@ -185,7 +185,7 @@ def display_adosc(
else:
return
ax1.set_title(f"{s_ticker} AD Oscillator")
ax1.set_title(f"{symbol} AD Oscillator")
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
@@ -235,8 +235,8 @@ def display_adosc(
@log_start_end(log=logger)
def display_obv(
ohlc: pd.DataFrame,
s_ticker: str = "",
data: pd.DataFrame,
symbol: str = "",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -244,9 +244,9 @@ def display_obv(
Parameters
----------
ohlc : pd.DataFrame
Dataframe of prices
s_ticker : str
data : pd.DataFrame
Dataframe of ohlc prices
symbol : str
Ticker
export: str
Format to export data as
@@ -254,13 +254,13 @@ def display_obv(
External axes (1 axis is expected in the list), by default None
"""
divisor = 1_000_000
df_vol = ohlc["Volume"] / divisor
df_vol = data["Volume"] / divisor
df_vol.name = "Adj Volume"
df_ta = volume_model.obv(ohlc)
df_ta = volume_model.obv(data)
df_cal = df_ta[df_ta.columns[0]] / divisor
df_cal.name = "Adj OBV"
plot_data = pd.merge(ohlc, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(data, df_vol, how="outer", left_index=True, right_index=True)
plot_data = pd.merge(
plot_data, df_ta, how="outer", left_index=True, right_index=True
)
@@ -285,7 +285,7 @@ def display_obv(
return
ax1.plot(plot_data.index, plot_data["Adj Close"].values)
ax1.set_title(f"{s_ticker} OBV")
ax1.set_title(f"{symbol} OBV")
ax1.set_xlim(plot_data.index[0], plot_data.index[-1])
ax1.set_ylabel("Price")
theme.style_primary_axis(

View File

@@ -301,7 +301,7 @@ class CryptoController(CryptoBaseController):
if ns_parser:
finbrain_crypto_view.display_crypto_sentiment_analysis(
coin=ns_parser.coin, export=ns_parser.export
symbol=ns_parser.coin, export=ns_parser.export
)
@log_start_end(log=logger)
@@ -469,16 +469,16 @@ class CryptoController(CryptoBaseController):
# TODO: merge find + display_all_coins
if ns_parser.coin:
find(
coin=ns_parser.coin,
query=ns_parser.coin,
source=ns_parser.source,
key=ns_parser.key,
top=ns_parser.limit,
limit=ns_parser.limit,
export=ns_parser.export,
)
display_all_coins(
coin=ns_parser.coin,
symbol=ns_parser.coin,
source=ns_parser.source,
top=ns_parser.limit,
limit=ns_parser.limit,
skip=ns_parser.skip,
show_all=bool("ALL" in other_args),
export=ns_parser.export,

View File

@@ -22,6 +22,7 @@ from openbb_terminal.helper_funcs import (
plot_autoscale,
export_data,
print_rich_table,
lambda_long_number_format_y_axis,
is_valid_axes_count,
)
from openbb_terminal.config_plot import PLOT_DPI
@@ -288,15 +289,16 @@ def get_coinpaprika_id(symbol: str):
def load(
symbol_search: str,
symbol: str,
vs: str = "usd",
days: int = 365,
):
"""Load crypto currency to perform analysis on CoinGecko is used as source for price and YahooFinance for volume.
"""Load crypto currency to perform analysis on CoinGecko is used as source for price and
YahooFinance for volume.
Parameters
----------
symbol_search: str
symbol: str
Coin to get
vs: str
Quote Currency (usd or eur), by default usd
@@ -308,7 +310,7 @@ def load(
pd.DataFrame
Dataframe consisting of price and volume data
"""
coingecko_id = get_coingecko_id(symbol_search)
coingecko_id = get_coingecko_id(symbol)
if not coingecko_id:
return pd.DataFrame()
@@ -316,7 +318,7 @@ def load(
start_date = datetime.now() - timedelta(days=days)
df = yf.download(
f"{symbol_search}-{vs}",
f"{symbol}-{vs}",
end=datetime.now(),
start=start_date,
progress=False,
@@ -328,7 +330,7 @@ def load(
df.index.name = "date"
if not df.empty:
console.print(
f"\nLoading Daily {symbol_search.upper()} crypto "
f"\nLoading Daily {symbol.upper()} crypto "
f"with starting period {start_date.strftime('%Y-%m-%d')} for analysis.",
)
return df
@@ -757,13 +759,17 @@ FIND_KEYS = ["id", "symbol", "name"]
def find(
coin: str, source: str = "cg", key: str = "symbol", top: int = 10, export: str = ""
query: str,
source: str = "cg",
key: str = "symbol",
limit: int = 10,
export: str = "",
) -> None:
"""Find similar coin by coin name,symbol or id.
If you don't remember exact name or id of the Coin at CoinGecko CoinPaprika, Binance or Coinbase
you can use this command to display coins with similar name, symbol or id to your search query.
Example of usage: coin name is something like "polka". So I can try: find -c polka -k name -t 25
If you don't know exact name or id of the Coin at CoinGecko CoinPaprika, Binance or Coinbase
you use this command to display coins with similar name, symbol or id to your search query.
Example: coin name is something like "polka". So I can try: find -c polka -k name -t 25
It will search for coin that has similar name to polka and display top 25 matches.
-c, --coin stands for coin - you provide here your search query
@@ -772,14 +778,14 @@ def find(
Parameters
----------
top: int
Number of records to display
coin: str
query: str
Cryptocurrency
key: str
Searching key (symbol, id, name)
source: str
Data source of coins. CoinGecko (cg) or CoinPaprika (cp) or Binance (bin), Coinbase (cb)
key: str
Searching key (symbol, id, name)
limit: int
Number of records to display
export : str
Export dataframe data to csv,json,xlsx file
"""
@@ -788,8 +794,8 @@ def find(
coins_df = get_coin_list()
coins_list = coins_df[key].to_list()
if key in ["symbol", "id"]:
coin = coin.lower()
sim = difflib.get_close_matches(coin, coins_list, top)
coin = query.lower()
sim = difflib.get_close_matches(coin, coins_list, limit)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
coins_df.drop("index", axis=1, inplace=True)
@@ -803,7 +809,7 @@ def find(
func_key = keys[key]
coin = getattr(coin, str(func_key))()
sim = difflib.get_close_matches(coin, coins_list, top)
sim = difflib.get_close_matches(coin, coins_list, limit)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins_df, on=key)
@@ -821,7 +827,7 @@ def find(
)
coins_list = coins[key].to_list()
sim = difflib.get_close_matches(coin, coins_list, top)
sim = difflib.get_close_matches(coin, coins_list, limit)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins, on=key)
@@ -837,7 +843,7 @@ def find(
)
coins_list = coins[key].to_list()
sim = difflib.get_close_matches(coin, coins_list, top)
sim = difflib.get_close_matches(coin, coins_list, limit)
df = pd.Series(sim).to_frame().reset_index()
df.columns = ["index", key]
df = df.merge(coins, on=key)
@@ -993,7 +999,7 @@ def load_ta_data(
# console.print(f"{coin} loaded vs {currency}")
df = coinbase_model.get_candles(
product_id=pair,
symbol=pair,
interval=interval or "24hour",
).head(limit)
@@ -1062,7 +1068,7 @@ def load_yf_data(symbol: str, currency: str, interval: str, days: int):
def display_all_coins(
source: str, coin: str, top: int, skip: int, show_all: bool, export: str
source: str, symbol: str, limit: int, skip: int, show_all: bool, export: str
) -> None:
"""Find similar coin by coin name,symbol or id.
If you don't remember exact name or id of the Coin at CoinGecko, CoinPaprika, Coinbase, Binance
@@ -1073,9 +1079,9 @@ def display_all_coins(
-t, --top it displays top N number of records.
Parameters
----------
top: int
limit: int
Number of records to display
coin: str
symbol: str
Cryptocurrency
source: str
Data source of coins. CoinGecko (cg) or CoinPaprika (cp) or Binance (bin), Coinbase (cb)
@@ -1105,7 +1111,7 @@ def display_all_coins(
elif not source or source not in sources:
df = prepare_all_coins_df()
cg_coins_list = df["CoinGecko"].to_list()
sim = difflib.get_close_matches(coin.lower(), cg_coins_list, limit, cutoff)
sim = difflib.get_close_matches(symbol.lower(), cg_coins_list, limit, cutoff)
df_matched = pd.Series(sim).to_frame().reset_index()
df_matched.columns = ["index", "CoinGecko"]
df = df.merge(df_matched, on="CoinGecko")
@@ -1115,12 +1121,12 @@ def display_all_coins(
if source == "cg":
coins_df = get_coin_list().drop("index", axis=1)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = _create_closest_match_df(symbol.lower(), coins_df, limit, cutoff)
df = df[["index", "id", "name"]]
elif source == "cp":
coins_df = get_list_of_coins()
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = _create_closest_match_df(symbol.lower(), coins_df, limit, cutoff)
df = df[["index", "id", "name"]]
elif source == "bin":
@@ -1130,7 +1136,7 @@ def display_all_coins(
coins_df = pd.merge(
coins_df_bin, coins_df_gecko[["id", "name"]], how="left", on="id"
)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = _create_closest_match_df(symbol.lower(), coins_df, limit, cutoff)
df = df[["index", "symbol", "name"]]
df.columns = ["index", "id", "name"]
@@ -1141,7 +1147,7 @@ def display_all_coins(
coins_df = pd.merge(
coins_df_cb, coins_df_gecko[["id", "name"]], how="left", on="id"
)
df = _create_closest_match_df(coin.lower(), coins_df, limit, cutoff)
df = _create_closest_match_df(symbol.lower(), coins_df, limit, cutoff)
df = df[["index", "symbol", "name"]]
df.columns = ["index", "id", "name"]
@@ -1151,7 +1157,7 @@ def display_all_coins(
console.print("")
try:
df = df[skip : skip + top] # noqa
df = df[skip : skip + limit] # noqa
except Exception as e:
logger.exception(str(e))
console.print(e)
@@ -1240,39 +1246,22 @@ def plot_candles(
"warn_too_much_data": 10000,
}
maximum_value = candles_df.max().max()
if maximum_value > 1_000_000_000_000:
df_rounded = candles_df / 1_000_000_000_000
denomination = " in Trillions"
elif maximum_value > 1_000_000_000:
df_rounded = candles_df / 1_000_000_000
denomination = " in Billions"
elif maximum_value > 1_000_000:
df_rounded = candles_df / 1_000_000
denomination = " in Millions"
elif maximum_value > 1_000:
df_rounded = candles_df / 1_000
denomination = " in Thousands"
else:
df_rounded = candles_df
denomination = ""
# This plot has 2 axes
if external_axes is None:
candle_chart_kwargs["returnfig"] = True
candle_chart_kwargs["figratio"] = (10, 7)
candle_chart_kwargs["figscale"] = 1.10
candle_chart_kwargs["figsize"] = plot_autoscale()
fig, _ = mpf.plot(df_rounded, **candle_chart_kwargs)
fig, ax = mpf.plot(candles_df, **candle_chart_kwargs)
fig.suptitle(
f"\n{title} [{denomination}]",
f"\n{title}",
horizontalalignment="left",
verticalalignment="top",
x=0.05,
y=1,
)
lambda_long_number_format_y_axis(candles_df, "Volume", ax)
theme.visualize_output(force_tight_layout=False)
else:
nr_external_axes = 2 if volume else 1
@@ -1287,9 +1276,7 @@ def plot_candles(
candle_chart_kwargs["ax"] = ax
console.print(f"Data {denomination}")
mpf.plot(df_rounded, **candle_chart_kwargs)
mpf.plot(candles_df, **candle_chart_kwargs)
def plot_order_book(

View File

@@ -9,7 +9,7 @@ import pandas as pd
import requests
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import get_user_agent
from openbb_terminal.helper_funcs import get_user_agent, lambda_long_number_format
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -108,6 +108,8 @@ def get_defi_vaults(
chain: Optional[str] = None,
protocol: Optional[str] = None,
kind: Optional[str] = None,
ascend: bool = True,
sortby: str = "apy",
) -> pd.DataFrame:
"""Get DeFi Vaults Information. DeFi Vaults are pools of funds with an assigned strategy which main goal is to
maximize returns of its crypto assets. [Source: https://coindix.com/]
@@ -148,7 +150,16 @@ def get_defi_vaults(
data = response.json()["data"]
if len(data) == 0:
return pd.DataFrame()
return pd.DataFrame(data)[VAULTS_FILTERS]
df = pd.DataFrame(data)[VAULTS_FILTERS]
except Exception as e:
logger.exception(e)
raise ValueError(f"Invalid Response: {response.text}") from e
df = df.sort_values(by=sortby, ascending=ascend).fillna("NA")
df["tvl"] = df["tvl"].apply(lambda x: lambda_long_number_format(x))
df["apy"] = df["apy"].apply(
lambda x: f"{str(round(x * 100, 2))} %" if isinstance(x, (int, float)) else x
)
df.columns = [x.title() for x in df.columns]
df.rename(columns={"Apy": "APY (%)", "Tvl": "TVL ($)"}, inplace=True)
return df

View File

@@ -9,7 +9,6 @@ from openbb_terminal.cryptocurrency.defi import coindix_model
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import (
export_data,
lambda_long_number_format,
print_rich_table,
)
@@ -23,7 +22,7 @@ def display_defi_vaults(
kind: Optional[str] = None,
top: int = 10,
sortby: str = "apy",
descend: bool = False,
ascend: bool = True,
link: bool = False,
export: str = "",
) -> None:
@@ -51,7 +50,7 @@ def display_defi_vaults(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
ascend: bool
Flag to sort data descending
link: bool
Flag to show links
@@ -59,24 +58,18 @@ def display_defi_vaults(
Export dataframe data to csv,json,xlsx file
"""
df = coindix_model.get_defi_vaults(chain=chain, protocol=protocol, kind=kind)
df_data = df.copy()
df = coindix_model.get_defi_vaults(
chain=chain, protocol=protocol, kind=kind, sortby=sortby, ascend=ascend
)
if df.empty:
print(
f"Couldn't find any vaults for "
f"{'' if not chain else 'chain: ' + chain}{'' if not protocol else ', protocol: ' + protocol}"
f"{'' if not chain else 'chain: ' + chain}"
f"{'' if not protocol else ', protocol: ' + protocol}"
f"{'' if not kind else ', kind:' + kind}"
)
return
df = df.sort_values(by=sortby, ascending=descend).fillna("NA")
df["tvl"] = df["tvl"].apply(lambda x: lambda_long_number_format(x))
df["apy"] = df["apy"].apply(
lambda x: f"{str(round(x * 100, 2))} %" if isinstance(x, (int, float)) else x
)
df.columns = [x.title() for x in df.columns]
df.rename(columns={"Apy": "APY (%)", "Tvl": "TVL ($)"}, inplace=True)
if link is True:
df.drop("Link", axis=1, inplace=True)
@@ -91,5 +84,5 @@ def display_defi_vaults(
export,
os.path.dirname(os.path.abspath(__file__)),
"vaults",
df_data,
df,
)

View File

@@ -38,7 +38,7 @@ def display_anchor_data(
address : str
Terra address. Valid terra addresses start with 'terra'
show_transactions : bool
Flag to show history of transactions in Anchor protocol for address specified. Default False
Flag to show history of transactions in Anchor protocol for address. Default False
export : str
Export dataframe data to csv,json,xlsx file
external_axes : Optional[List[plt.Axes]], optional
@@ -54,9 +54,7 @@ def display_anchor_data(
(ax,) = external_axes
else:
return
print("")
console.print(stats_str)
print("")
console.print(f"\n{stats_str}\n")
if show_transactions:
print_rich_table(

View File

@@ -6,8 +6,6 @@ from openbb_terminal.helper_classes import ModelsNamespace as _models
# pylint: disable=unused-import
# Menu commands
from .terraengineer_view import display_terra_asset_history as aterra
from .terraengineer_view import display_anchor_yield_reserve as ayr
from .terramoney_fcd_view import display_account_staking_info as sinfo
from .terramoney_fcd_view import display_validators as validators
from .terramoney_fcd_view import display_account_growth as gacc

View File

@@ -21,7 +21,6 @@ from openbb_terminal.cryptocurrency.defi import (
llama_view,
substack_view,
terraengineer_model,
terraengineer_view,
terramoney_fcd_model,
terramoney_fcd_view,
smartstake_view,
@@ -160,71 +159,6 @@ class DefiController(BaseController):
address=ns_parser.address,
)
@log_start_end(log=logger)
def call_aterra(self, other_args: List[str]):
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="aterra",
description="""
Displays the 30-day history of an asset in a certain terra address.
[Source: https://terra.engineer/]
""",
)
parser.add_argument(
"--asset",
dest="asset",
type=str,
help="Terra asset {ust,luna,sdt} Default: ust",
default=terraengineer_model.ASSETS[0],
choices=terraengineer_model.ASSETS,
)
parser.add_argument(
"--address",
dest="address",
type=check_terra_address_format,
help="Terra address. Valid terra addresses start with 'terra'",
required="-h" not in other_args,
)
if other_args and not other_args[0][0] == "-":
other_args.insert(0, "--asset")
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
)
if ns_parser:
terraengineer_view.display_terra_asset_history(
export=ns_parser.export,
address=ns_parser.address,
asset=ns_parser.asset,
)
@log_start_end(log=logger)
def call_ayr(self, other_args: List[str]):
"""Process ayr command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="ayr",
description="""
Displays the 30-day history of the Anchor Yield Reserve.
An increasing yield reserve indicates that the return on collateral staked by borrowers in Anchor
is greater than the yield paid to depositors. A decreasing yield reserve means yield paid
to depositors is outpacing the staking returns of borrower's collateral.
TLDR: Shows the address that contains UST that is paid on anchor interest earn.
[Source: https://terra.engineer/]
""",
)
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
)
if ns_parser:
terraengineer_view.display_anchor_yield_reserve(export=ns_parser.export)
@log_start_end(log=logger)
def call_sinfo(self, other_args: List[str]):
parser = argparse.ArgumentParser(
@@ -466,11 +400,11 @@ class DefiController(BaseController):
)
parser.add_argument(
"--descend",
action="store_false",
help="Flag to sort in descending order (lowest first)",
dest="descend",
default=True,
"--ascend",
action="store_true",
help="Flag to sort in ascending order (highest first)",
dest="ascending",
default=False,
)
ns_parser = self.parse_known_args_and_warn(
@@ -481,7 +415,7 @@ class DefiController(BaseController):
defipulse_view.display_defipulse(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=ns_parser.ascending,
export=ns_parser.export,
)
@@ -720,7 +654,7 @@ class DefiController(BaseController):
skip=ns_parser.skip,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1022,7 +956,7 @@ class DefiController(BaseController):
protocol=ns_parser.protocol,
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
descend=not ns_parser.descend,
link=ns_parser.link,
export=ns_parser.export,
)

View File

@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_defipulse_index() -> pd.DataFrame:
def get_defipulse_index(sortby: str = "TVL", ascend: bool = False) -> pd.DataFrame:
"""Scrapes data from DeFi Pulse with all DeFi Pulse crypto protocols.
[Source: https://defipulse.com/]
@@ -48,5 +48,6 @@ def get_defipulse_index() -> pd.DataFrame:
],
)
df["Rank"] = df.index
df = df.sort_values(by=sortby, ascending=ascend)
return df

View File

@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_defipulse(
top: int = 10, sortby: str = "TVL", descend: bool = True, export: str = ""
top: int = 10, sortby: str = "TVL", ascend: bool = False, export: str = ""
) -> None:
"""Displays all DeFi Pulse crypto protocols.
[Source: https://defipulse.com/]
@@ -25,16 +25,13 @@ def display_defipulse(
sortby: str
Key by which to sort data (Possible values are: "Rank", "Name", "Chain", "Sector",
"TVL", "1 Day (%)"), by default TVL
descend: bool
Flag to sort data descending, by default True
ascend: bool
Flag to sort data ascending, by default False
export : str
Export dataframe data to csv,json,xlsx file, by default False
"""
df = defipulse_model.get_defipulse_index()
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df = defipulse_model.get_defipulse_index(sortby, ascend)
print_rich_table(
df.head(top),
@@ -43,9 +40,4 @@ def display_defipulse(
title="DeFi Pulse Crypto Protocols",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"dpi",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "dpi", df)

View File

@@ -74,7 +74,9 @@ def query_graph(url: str, query: str) -> dict:
@log_start_end(log=logger)
def get_uni_tokens(skip: int = 0, limit: int = 100) -> pd.DataFrame:
def get_uni_tokens(
skip: int = 0, limit: int = 100, sortby: str = "index", ascend: bool = False
) -> pd.DataFrame:
"""Get list of tokens trade-able on Uniswap DEX. [Source: https://thegraph.com/en/]
Parameters
@@ -83,6 +85,10 @@ def get_uni_tokens(skip: int = 0, limit: int = 100) -> pd.DataFrame:
Skip n number of records.
limit: int
Show n number of records.
sortby: str
The column to sort by
ascend: bool
Whether to sort in ascending order
Returns
-------
@@ -106,8 +112,8 @@ def get_uni_tokens(skip: int = 0, limit: int = 100) -> pd.DataFrame:
data = query_graph(UNI_URL, query)
if not data:
return pd.DataFrame()
return pd.DataFrame(data["tokens"]).reset_index()
df = pd.DataFrame(data["tokens"]).reset_index()
return df.sort_values(by=sortby, ascending=ascend)
@log_start_end(log=logger)

View File

@@ -19,7 +19,7 @@ def display_uni_tokens(
skip: int = 0,
limit: int = 20,
sortby: str = "index",
descend: bool = True,
ascend: bool = False,
export: str = "",
) -> None:
"""Displays tokens trade-able on Uniswap DEX.
@@ -33,17 +33,15 @@ def display_uni_tokens(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
ascend: bool
Flag to sort data descending
export : str
Export dataframe data to csv,json,xlsx file
"""
df = graph_model.get_uni_tokens(skip=skip)
df = graph_model.get_uni_tokens(skip=skip, sortby=sortby, ascend=ascend)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df[["totalLiquidity", "tradeVolumeUSD"]] = df[
["totalLiquidity", "tradeVolumeUSD"]
].applymap(lambda x: lambda_very_long_number_formatter(x))
@@ -158,7 +156,7 @@ def display_recently_added(
@log_start_end(log=logger)
def display_uni_pools(
top: int = 20, sortby: str = "volumeUSD", descend: bool = False, export: str = ""
top: int = 20, sortby: str = "volumeUSD", ascend: bool = False, export: str = ""
) -> None:
"""Displays uniswap pools by volume.
[Source: https://thegraph.com/en/]
@@ -170,13 +168,13 @@ def display_uni_pools(
sortby: str
Key by which to sort data. The table can be sorted by every of its columns
(see https://bit.ly/3ORagr1 then press ctrl-enter or execute the query).
descend: bool
ascend: bool
Flag to sort data descending
export : str
Export dataframe data to csv,json,xlsx file
"""
df = graph_model.get_uni_pools_by_volume().sort_values(by=sortby, ascending=descend)
df = graph_model.get_uni_pools_by_volume().sort_values(by=sortby, ascending=ascend)
df["volumeUSD"] = df["volumeUSD"].apply(
lambda x: lambda_very_long_number_formatter(x)
)

View File

@@ -28,10 +28,15 @@ LLAMA_FILTERS = [
@log_start_end(log=logger)
def get_defi_protocols() -> pd.DataFrame:
def get_defi_protocols(num: int = 100) -> pd.DataFrame:
"""Returns information about listed DeFi protocols, their current TVL and changes to it in the last hour/day/week.
[Source: https://docs.llama.fi/api]
Parameters
----------
num: int
The number of dApps to display
Returns
-------
pd.DataFrame
@@ -63,12 +68,16 @@ def get_defi_protocols() -> pd.DataFrame:
df["description"] = df["description"].apply(
lambda x: "\n".join(textwrap.wrap(x, width=70)) if isinstance(x, str) else x
)
return df[columns]
df = df[columns]
except Exception as e:
logger.exception("Wrong response type: %s", str(e))
raise ValueError("Wrong response type\n") from e
df = df.sort_values("tvl", ascending=False).head(num)
df = df.set_index("name")
return df
@log_start_end(log=logger)
def get_defi_protocol(protocol: str) -> pd.DataFrame:

View File

@@ -43,10 +43,7 @@ def display_grouped_defi_protocols(
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df = llama_model.get_defi_protocols()
df = df.sort_values("tvl", ascending=False).head(num)
df = df.set_index("name")
df = llama_model.get_defi_protocols(num)
chains = df.groupby("chain").size().index.values.tolist()
# This plot has 1 axis
@@ -97,10 +94,14 @@ def display_grouped_defi_protocols(
@log_start_end(log=logger)
def display_defi_protocols(
top: int, sortby: str, descend: bool, description: bool, export: str = ""
top: int,
sortby: str,
ascend: bool = False,
description: bool = False,
export: str = "",
) -> None:
"""Display information about listed DeFi protocols, their current TVL and changes to it in the last hour/day/week.
[Source: https://docs.llama.fi/api]
"""Display information about listed DeFi protocols, their current TVL and changes to it in
the last hour/day/week. [Source: https://docs.llama.fi/api]
Parameters
----------
@@ -108,7 +109,7 @@ def display_defi_protocols(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
ascend: bool
Flag to sort data descending
description: bool
Flag to display description of protocol
@@ -119,7 +120,7 @@ def display_defi_protocols(
df = llama_model.get_defi_protocols()
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df = df.sort_values(by=sortby, ascending=ascend)
df = df.drop(columns="chain")
df["tvl"] = df["tvl"].apply(lambda x: lambda_long_number_format(x))

View File

@@ -9,17 +9,19 @@ from openbb_terminal import config_terminal as cfg
from openbb_terminal.rich_config import console
def get_luna_supply_stats(supply_type: str, days: int) -> pd.DataFrame:
def get_luna_supply_stats(
supply_type: str = "lunaSupplyChallengeStats", days: int = 30
) -> pd.DataFrame:
"""Get supply history of the Terra ecosystem
Source: [Smartstake.io]
Parameters
----------
days: int
Day count to fetch data
supply_type: str
Supply type to unpack json
days: int
Day count to fetch data
Returns
-------

View File

@@ -24,15 +24,13 @@ from openbb_terminal.decorators import log_start_end
logger = logging.getLogger(__name__)
LUNA_CIR_SUPPLY_CHANGE = "lunaSupplyChallengeStats"
@log_start_end(log=logger)
@check_api_key(["API_SMARTSTAKE_KEY", "API_SMARTSTAKE_TOKEN"])
def display_luna_circ_supply_change(
days: int,
days: int = 30,
export: str = "",
supply_type: str = LUNA_CIR_SUPPLY_CHANGE,
supply_type: str = "lunaSupplyChallengeStats",
limit: int = 5,
external_axes: Optional[List[plt.Axes]] = None,
):

View File

@@ -26,7 +26,6 @@ def display_newsletters(top: int = 10, export: str = "") -> None:
"""
df = substack_model.get_newsletters()
df_data = df.copy()
print_rich_table(
df.head(top),
@@ -35,9 +34,4 @@ def display_newsletters(top: int = 10, export: str = "") -> None:
title="Substack Newsletters",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"newsletter",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "newsletter", df)

View File

@@ -17,7 +17,7 @@ ASSETS = ["ust", "luna", "sdt"]
@log_start_end(log=logger)
def get_history_asset_from_terra_address(
asset: str = "ust", address: str = ""
asset: str = "ust", address: str = "terra1tmnqgvg567ypvsvk6rwsga3srp7e3lg6u0elp8"
) -> pd.DataFrame:
"""Returns historical data of an asset in a certain terra address
[Source: https://terra.engineer/]
@@ -49,7 +49,10 @@ def get_history_asset_from_terra_address(
raise Exception(f"Status code: {response.status_code}. Reason: {response.text}")
data = response.json()
df = pd.DataFrame(data[0]["data"])
df["x"] = pd.to_datetime(df["x"])
if data[0]["data"]:
df = pd.DataFrame(data[0]["data"])
df["x"] = pd.to_datetime(df["x"])
else:
df = pd.DataFrame()
return df

View File

@@ -19,6 +19,7 @@ from openbb_terminal.helper_funcs import (
plot_autoscale,
is_valid_axes_count,
)
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
@@ -49,6 +50,8 @@ def display_terra_asset_history(
df = terraengineer_model.get_history_asset_from_terra_address(
address=address, asset=asset
)
if df.empty:
console.print("[red]No data in the provided dataframe[/red]\n")
# This plot has 1 axis
if not external_axes:
@@ -96,6 +99,9 @@ def display_anchor_yield_reserve(
df = terraengineer_model.get_history_asset_from_terra_address(
address="terra1tmnqgvg567ypvsvk6rwsga3srp7e3lg6u0elp8"
)
if df.empty:
console.print("[red]No data was found[/red]\n")
return
# This plot has 1 axis
if not external_axes:

View File

@@ -144,9 +144,17 @@ def get_staking_account_info(address: str = "") -> Tuple[pd.DataFrame, str]:
@log_start_end(log=logger)
def get_validators() -> pd.DataFrame:
def get_validators(sortby: str = "votingPower", ascend: bool = True) -> pd.DataFrame:
"""Get information about terra validators [Source: https://fcd.terra.dev/swagger]
Parameters
-----------
sortby: str
Key by which to sort data. Choose from:
validatorName, tokensAmount, votingPower, commissionRate, status, uptime
ascend: bool
Flag to sort data descending
Returns
-------
pd.DataFrame
@@ -172,17 +180,28 @@ def get_validators() -> pd.DataFrame:
}
)
return pd.DataFrame(results).sort_values(by="votingPower")
df = pd.DataFrame(results)
if not df.empty:
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_proposals(status: str = "") -> pd.DataFrame:
def get_proposals(
status: str = "", sortby: str = "id", ascend: bool = True, top: int = 10
) -> pd.DataFrame:
"""Get terra blockchain governance proposals list [Source: https://fcd.terra.dev/swagger]
Parameters
----------
status: str
status of proposal, one from list: ['Voting','Deposit','Passed','Rejected']
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
top: int
Number of records to display
Returns
-------
@@ -228,6 +247,8 @@ def get_proposals(status: str = "") -> pd.DataFrame:
if status.title() in statuses:
df = df[df["status"] == status.title()]
df = df.sort_values(by=sortby, ascending=ascend).head(top)
df.columns = prettify_column_names(df.columns)
return df
@@ -255,9 +276,14 @@ def get_account_growth(cumulative: bool = True) -> pd.DataFrame:
@log_start_end(log=logger)
def get_staking_ratio_history():
def get_staking_ratio_history(top: int = 200):
"""Get terra blockchain staking ratio history [Source: https://fcd.terra.dev/swagger]
Parameters
----------
top: int
The number of ratios to show
Returns
-------
pd.DataFrame
@@ -268,13 +294,21 @@ def get_staking_ratio_history():
df = pd.DataFrame(response)
df["date"] = df["datetime"].apply(lambda x: datetime.fromtimestamp(x / 1000).date())
df["stakingRatio"] = df["stakingRatio"].apply(lambda x: round(float(x) * 100, 2))
return df[["date", "stakingRatio"]]
df = df[["date", "stakingRatio"]]
df = df.sort_values("date", ascending=False).head(top)
df = df.set_index("date")
return df
@log_start_end(log=logger)
def get_staking_returns_history():
def get_staking_returns_history(top: int = 200):
"""Get terra blockchain staking returns history [Source: https://fcd.terra.dev/v1]
Parameters
----------
top: int
The number of returns to show
Returns
-------
pd.DataFrame
@@ -287,4 +321,8 @@ def get_staking_returns_history():
df["annualizedReturn"] = df["annualizedReturn"].apply(
lambda x: round(float(x) * 100, 2)
)
return df[["date", "annualizedReturn"]]
df = df[["date", "annualizedReturn"]]
df = df.sort_values("date", ascending=False).head(top)
df = df.set_index("date")
return df

View File

@@ -59,7 +59,7 @@ def display_account_staking_info(
@log_start_end(log=logger)
def display_validators(
top: int = 10, sortby: str = "votingPower", descend: bool = False, export: str = ""
top: int = 10, sortby: str = "votingPower", ascend: bool = True, export: str = ""
) -> None:
"""Display information about terra validators [Source: https://fcd.terra.dev/swagger]
@@ -68,16 +68,16 @@ def display_validators(
top: int
Number of records to display
sortby: str
Key by which to sort data
descend: bool
Key by which to sort data. Choose from:
validatorName, tokensAmount, votingPower, commissionRate, status, uptime
ascend: bool
Flag to sort data descending
export : str
Export dataframe data to csv,json,xlsx file
"""
df = terramoney_fcd_model.get_validators()
df = terramoney_fcd_model.get_validators(sortby, ascend)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df["tokensAmount"] = df["tokensAmount"].apply(
lambda x: lambda_very_long_number_formatter(x)
)
@@ -106,7 +106,7 @@ def display_gov_proposals(
top: int = 10,
status: str = "all",
sortby: str = "id",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display terra blockchain governance proposals list [Source: https://fcd.terra.dev/swagger]
@@ -119,30 +119,17 @@ def display_gov_proposals(
status of proposal, one from list: ['Voting','Deposit','Passed','Rejected']
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascend
export : str
Export dataframe data to csv,json,xlsx file
"""
df = terramoney_fcd_model.get_proposals(status)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend).head(top)
df.columns = prettify_column_names(df.columns)
df = terramoney_fcd_model.get_proposals(status, sortby, ascend, top)
print_rich_table(
df,
headers=list(df.columns),
floatfmt=".2f",
show_index=False,
)
print_rich_table(df, headers=list(df.columns), floatfmt=".2f", show_index=False)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"govp",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "govp", df)
@log_start_end(log=logger)
@@ -229,12 +216,9 @@ def display_staking_ratio_history(
Export dataframe data to csv,json,xlsx file
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df = terramoney_fcd_model.get_staking_ratio_history()
df = df.sort_values("date", ascending=False).head(top)
df = df.set_index("date")
df = terramoney_fcd_model.get_staking_ratio_history(top)
start, end = df.index[-1], df.index[0]
@@ -289,10 +273,7 @@ def display_staking_returns_history(
else:
return
df = terramoney_fcd_model.get_staking_returns_history()
df = df.sort_values("date", ascending=False).head(top)
df = df.set_index("date")
df = terramoney_fcd_model.get_staking_returns_history(top)
start, end = df.index[-1], df.index[0]

View File

@@ -14,11 +14,28 @@ logger = logging.getLogger(__name__)
FILTERS = ["Symbol", "CMC_Rank", "LastPrice", "DayPctChange", "MarketCap"]
sort_map = {
"Symbol": "Symbol",
"CMC_Rank": "CMC_Rank",
"LastPrice": "Last Price",
"DayPctChange": "1 Day Pct Change",
"MarketCap": "Market Cap ($B)",
}
@log_start_end(log=logger)
def get_cmc_top_n() -> pd.DataFrame:
def get_cmc_top_n(sortby: str = "CMC_Rank", ascend: bool = True) -> pd.DataFrame:
"""Shows top n coins. [Source: CoinMarketCap]
Parameters
----------
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
Coin Market Cap:s API documentation, see:
https://coinmarketcap.com/api/documentation/v1/#operation/getV1CryptocurrencyListingsLatest
ascend: bool
Whether to sort ascending or descending
Returns
-------
pd.DataFrame
@@ -54,4 +71,5 @@ def get_cmc_top_n() -> pd.DataFrame:
else:
console.print(e)
df = df.sort_values(by=sort_map[sortby], ascending=ascend)
return df

View File

@@ -12,21 +12,13 @@ from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
sort_map = {
"Symbol": "Symbol",
"CMC_Rank": "CMC_Rank",
"LastPrice": "Last Price",
"DayPctChange": "1 Day Pct Change",
"MarketCap": "Market Cap ($B)",
}
@log_start_end(log=logger)
@check_api_key(["API_CMC_KEY"])
def display_cmc_top_coins(
top: int = 15,
sortby: str = "CMC_Rank",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Shows top n coins. [Source: CoinMarketCap]
@@ -37,23 +29,21 @@ def display_cmc_top_coins(
Number of records to display
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
Coin Market Cap:s API documentation
(see https://coinmarketcap.com/api/documentation/v1/#operation/getV1CryptocurrencyListingsLatest)
descend: bool
Flag to sort data descending
Coin Market Cap:s API documentation, see:
https://coinmarketcap.com/api/documentation/v1/#operation/getV1CryptocurrencyListingsLatest
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
"""
df = coinmarketcap_model.get_cmc_top_n()
df = coinmarketcap_model.get_cmc_top_n(sortby, ascend)
if df.empty:
console.print("No Data Found\n")
return
df = df.sort_values(by=sort_map[sortby], ascending=descend)
print_rich_table(
df.iloc[:top, :], headers=list(df.columns), show_index=False, title="Top Coins"
)

View File

@@ -25,7 +25,11 @@ FILTERS = ["category", "id", "name"]
@log_start_end(log=logger)
def get_search_results(
query: str, category: Optional[Any] = None, modifier: Optional[Any] = None
query: str,
category: Optional[Any] = None,
modifier: Optional[Any] = None,
sortby: str = "id",
ascend: bool = True,
) -> pd.DataFrame:
"""Search CoinPaprika. [Source: CoinPaprika]
@@ -40,6 +44,11 @@ def get_search_results(
modifier: Optional[Any]
set modifier for search results. Available options: symbol_search -
search only by symbol (works for currencies only)
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
API documentation (see https://api.coinpaprika.com/docs#tag/Tools/paths/~1search/get)
ascend: bool
Flag to sort data descending
Returns
-------
@@ -65,4 +74,6 @@ def get_search_results(
"category": item,
}
)
return pd.DataFrame(results)
df = pd.DataFrame(results)
df = df.sort_values(by=sortby, ascending=ascend)
return df

View File

@@ -18,7 +18,7 @@ def display_search_results(
category: str = "all",
top: int = 10,
sortby: str = "id",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Search over CoinPaprika. [Source: CoinPaprika]
@@ -33,8 +33,8 @@ def display_search_results(
Number of records to display
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
CoinPaprikas API documentation (see https://api.coinpaprika.com/docs#tag/Tools/paths/~1search/get)
descend: bool
API documentation (see https://api.coinpaprika.com/docs#tag/Tools/paths/~1search/get)
ascend: bool
Flag to sort data descending
export : str
Export dataframe data to csv,json,xlsx file
@@ -43,7 +43,9 @@ def display_search_results(
if category.lower() == "all":
category = "currencies,exchanges,icos,people,tags"
df = paprika.get_search_results(query=query, category=category)
df = paprika.get_search_results(
query=query, category=category, sortby=sortby, ascend=ascend
)
if df.empty:
console.print(
@@ -51,8 +53,6 @@ def display_search_results(
)
return
df = df.sort_values(by=sortby, ascending=descend)
print_rich_table(
df.head(top),
headers=list(df.columns),

View File

@@ -70,20 +70,23 @@ def _make_request(url: str) -> Optional[dict]:
@log_start_end(log=logger)
def get_top_nfts() -> pd.DataFrame:
def get_top_nfts(sortby: str = "") -> pd.DataFrame:
"""Get top nft collections [Source: https://dappradar.com/]
Parameters
----------
sortby: str
Key by which to sort data
Returns
-------
pd.DataFrame
NFT collections. Columns: Name, Protocols, Floor Price [$], Avg Price [$], Market Cap [$], Volume [$]
NFTs Columns: Name, Protocols, Floor Price [$], Avg Price [$], Market Cap [$], Volume [$]
"""
response = _make_request(
"https://nft-sales-service.dappradar.com/v2/collection/day?limit=20&page=1&currency=USD&sort=marketCapInFiat&order=desc" # noqa
"https://nft-sales-service.dappradar.com/v2/collection/day?limit=20&p"
"age=1&currency=USD&sort=marketCapInFiat&order=desc"
)
if response:
data = response.get("results")
@@ -106,15 +109,19 @@ def get_top_nfts() -> pd.DataFrame:
)
df["Protocols"] = df["Protocols"].apply(lambda x: ",".join(x))
return df
if sortby in NFT_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
return pd.DataFrame()
@log_start_end(log=logger)
def get_top_dexes() -> pd.DataFrame:
def get_top_dexes(sortby: str = "") -> pd.DataFrame:
"""Get top dexes by daily volume and users [Source: https://dappradar.com/]
Parameters
----------
sortby: str
Key by which to sort data
Returns
-------
@@ -122,7 +129,9 @@ def get_top_dexes() -> pd.DataFrame:
Top decentralized exchanges. Columns: Name, Daily Users, Daily Volume [$]
"""
data = _make_request(
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMXRZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbU5oZEdWbmIzSjVQV1Y0WTJoaGJtZGxjeVp6YjNKMFBYUnZkR0ZzVm05c2RXMWxTVzVHYVdGMEptOXlaR1Z5UFdSbGMyTW1iR2x0YVhROU1qWT0=" # noqa
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMXR"
"ZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbU5oZEdWbmIzSjVQV1Y0WTJ"
"oaGJtZGxjeVp6YjNKMFBYUnZkR0ZzVm05c2RXMWxTVzVHYVdGMEptOXlaR1Z5UFdSbGMyTW1iR2x0YVhROU1qWT0="
)
if data:
arr = []
@@ -135,6 +144,8 @@ def get_top_dexes() -> pd.DataFrame:
]
)
df = pd.DataFrame(arr, columns=DEX_COLUMNS)
if sortby in DEX_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
return df
return pd.DataFrame()
@@ -152,7 +163,9 @@ def get_top_games() -> pd.DataFrame:
Top blockchain games. Columns: Name, Daily Users, Daily Volume [$]
"""
data = _make_request(
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMXRZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbU5oZEdWbmIzSjVQV2RoYldWekpuTnZjblE5ZFhObGNpWnZjbVJsY2oxa1pYTmpKbXhwYldsMFBUSTI=" # noqa
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMX"
"RZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbU5oZEdWbmIzSjVQV2R"
"oYldWekpuTnZjblE5ZFhObGNpWnZjbVJsY2oxa1pYTmpKbXhwYldsMFBUSTI="
)
if data:
arr = []
@@ -173,19 +186,24 @@ def get_top_games() -> pd.DataFrame:
@log_start_end(log=logger)
def get_top_dapps() -> pd.DataFrame:
def get_top_dapps(sortby: str = "") -> pd.DataFrame:
"""Get top decentralized applications by daily volume and users [Source: https://dappradar.com/]
Parameters
----------
sortby: str
Key by which to sort data
Returns
-------
pd.DataFrame
Top decentralized exchanges. Columns: Name, Category, Protocols, Daily Users, Daily Volume [$]
Top decentralized exchanges.
Columns: Name, Category, Protocols, Daily Users, Daily Volume [$]
"""
data = _make_request(
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMXRZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbk52Y25ROWRYTmxjaVp2Y21SbGNqMWtaWE5qSm14cGJXbDBQVEky" # noqa
"https://dappradar.com/v2/api/dapps?params=WkdGd2NISmhaR0Z5Y0dGblpUMHhKbk5uY205MWNEMX"
"RZWGdtWTNWeWNtVnVZM2s5VlZORUptWmxZWFIxY21Wa1BURW1jbUZ1WjJVOVpHRjVKbk52Y25ROWRYTmxjaVp"
"2Y21SbGNqMWtaWE5qSm14cGJXbDBQVEky"
)
if data:
arr = []
@@ -204,5 +222,7 @@ def get_top_dapps() -> pd.DataFrame:
columns=DAPPS_COLUMNS,
).sort_values("Daily Users", ascending=False)
df["Protocols"] = df["Protocols"].apply(lambda x: ",".join(x))
if sortby in DAPPS_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
return df
return pd.DataFrame()

View File

@@ -30,33 +30,31 @@ def display_top_nfts(top: int = 10, sortby: str = "", export: str = "") -> None:
Export dataframe data to csv,json,xlsx file
"""
df = dappradar_model.get_top_nfts()
df = dappradar_model.get_top_nfts(sortby)
if df.empty:
console.print("Failed to fetch data from DappRadar\n")
else:
if sortby in dappradar_model.NFT_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
for col in ["Floor Price [$]", "Avg Price [$]", "Market Cap [$]", "Volume [$]"]:
if col in df.columns:
df[col] = (
df[col]
.fillna(-1)
.apply(lambda x: lambda_very_long_number_formatter(x))
.replace(-1, np.nan)
)
print_rich_table(
df.head(top),
headers=list(df.columns),
show_index=False,
title="Top NFT collections",
)
return
for col in ["Floor Price [$]", "Avg Price [$]", "Market Cap [$]", "Volume [$]"]:
if col in df.columns:
df[col] = (
df[col]
.fillna(-1)
.apply(lambda x: lambda_very_long_number_formatter(x))
.replace(-1, np.nan)
)
print_rich_table(
df.head(top),
headers=list(df.columns),
show_index=False,
title="Top NFT collections",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"drnft",
df,
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"drnft",
df,
)
@log_start_end(log=logger)
@@ -111,12 +109,10 @@ def display_top_dexes(top: int = 10, export: str = "", sortby: str = "") -> None
Export dataframe data to csv,json,xlsx file
"""
df = dappradar_model.get_top_dexes()
df = dappradar_model.get_top_dexes(sortby)
if df.empty:
console.print("Failed to fetch data from DappRadar\n")
return
if sortby in dappradar_model.DEX_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
for col in ["Daily Users", "Daily Volume [$]"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))
@@ -149,12 +145,10 @@ def display_top_dapps(top: int = 10, export: str = "", sortby: str = "") -> None
Export dataframe data to csv,json,xlsx file
"""
df = dappradar_model.get_top_dapps()
df = dappradar_model.get_top_dapps(sortby)
if df.empty:
console.print("Failed to fetch data from DappRadar\n")
return
if sortby in dappradar_model.DAPPS_COLUMNS:
df = df.sort_values(by=sortby, ascending=False)
for col in ["Daily Users", "Daily Volume [$]"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))

View File

@@ -359,7 +359,7 @@ class DiscoveryController(BaseController):
dest="sortby",
nargs="+",
help="Sort by given column. Default: Market Cap Rank",
default=["Market Cap"],
default=["market_cap"],
)
ns_parser = self.parse_known_args_and_warn(
@@ -493,7 +493,7 @@ class DiscoveryController(BaseController):
coinmarketcap_view.display_cmc_top_coins(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
descend=not ns_parser.descend,
export=ns_parser.export,
)

View File

@@ -11,6 +11,16 @@ from openbb_terminal.decorators import log_start_end
logger = logging.getLogger(__name__)
COINS_COLUMNS = [
"Symbol",
"Name",
"total_volume",
"market_cap Cap",
"market_cap Cap Rank",
"7D Change [%]",
"24H Change [%]",
]
PERIODS = {
"1h": "?time=h1",
"24h": "?time=h24",
@@ -99,7 +109,7 @@ def get_categories_keys() -> List[str]:
@log_start_end(log=logger)
def get_coins(top: int = 250, category: str = "") -> pd.DataFrame:
def get_coins(top: int = 250, category: str = "", sortby="Symbol") -> pd.DataFrame:
"""Get N coins from CoinGecko [Source: CoinGecko]
@@ -107,6 +117,9 @@ def get_coins(top: int = 250, category: str = "") -> pd.DataFrame:
----------
top: int
Number of top coins to grab from CoinGecko
sortby: str
Key to sort data
Returns
-------
pandas.DataFrame
@@ -146,6 +159,9 @@ def get_coins(top: int = 250, category: str = "") -> pd.DataFrame:
# df = df.append(pd.DataFrame(data), ignore_index=True)
top -= 250
p += 1
if sortby in COINS_COLUMNS:
df = df[(df["total_volume"].notna()) & (df["market_cap"].notna())]
df = df.sort_values(by=sortby.lower(), ascending=False)
return df.head(top)
@@ -153,15 +169,18 @@ GAINERS_LOSERS_COLUMNS = [
"Symbol",
"Name",
"Price [$]",
"Market Cap",
"Market Cap Rank",
"Volume [$]",
"market_cap",
"market_cap_rank",
"total_volume",
]
@log_start_end(log=logger)
def get_gainers_or_losers(
top: int = 20, period: str = "1h", typ: str = "gainers"
top: int = 20,
period: str = "1h",
typ: str = "gainers",
sortby: str = "market_cap",
) -> pd.DataFrame:
"""Returns data about top gainers - coins which gain the most in given period and
top losers - coins that lost the most in given period of time. [Source: CoinGecko]
@@ -170,6 +189,9 @@ def get_gainers_or_losers(
----------
top: int
Num of coins to get
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
API documentation (see /coins/markets in https://www.coingecko.com/en/api/documentation)
period: str
One from {14d,1h,1y,200d,24h,30d,7d}
typ: str
@@ -206,6 +228,9 @@ def get_gainers_or_losers(
axis=1,
inplace=False,
)
if sortby in COINS_COLUMNS:
df = df[(df["total_volume"].notna()) & (df["market_cap"].notna())]
df = df.sort_values(by=sortby, ascending=True)
return sorted_df
@@ -224,7 +249,7 @@ def get_trending_coins() -> pd.DataFrame:
client = CoinGeckoAPI()
data = client.get_search_trending()
coins = data["coins"]
df = pd.DataFrame(columns=["Symbol", "Name", "Market Cap Rank"])
df = pd.DataFrame(columns=["Symbol", "Name", "market_cap Cap Rank"])
for i, coin in enumerate(coins):
coin = coin["item"]
df.loc[i] = [coin["id"], coin["name"], coin["market_cap_rank"]]

View File

@@ -18,7 +18,6 @@ logger = logging.getLogger(__name__)
register_matplotlib_converters()
# pylint: disable=inconsistent-return-statements
# pylint: disable=R0904, C0302
COINS_COLUMNS = [
@@ -41,7 +40,7 @@ def display_coins(
Parameters
----------
category: str
Coingecko category. If no category is passed it will search for all coins. (E.g., smart-contract-platform)
If no category is passed it will search for all coins. (E.g., smart-contract-platform)
top: int
Number of records to display
sortby: str
@@ -49,7 +48,7 @@ def display_coins(
export : str
Export dataframe data to csv,json,xlsx file
"""
df = pycoingecko_model.get_coins(top=top, category=category)
df = pycoingecko_model.get_coins(top=top, category=category, sortby=sortby)
if not df.empty:
df = df[
[
@@ -67,10 +66,6 @@ def display_coins(
axis=1,
inplace=False,
)
if sortby in COINS_COLUMNS:
df = df[
(df["Volume [$]"].notna()) & (df["Market Cap"].notna())
].sort_values(by=sortby, ascending=False)
for col in ["Volume [$]", "Market Cap"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))
@@ -92,7 +87,7 @@ def display_coins(
@log_start_end(log=logger)
def display_gainers(
period: str = "1h", top: int = 20, sortby: str = "Market Cap Rank", export: str = ""
period: str = "1h", top: int = 20, sortby: str = "market_cap_rank", export: str = ""
) -> None:
"""Shows Largest Gainers - coins which gain the most in given period. [Source: CoinGecko]
@@ -104,18 +99,20 @@ def display_gainers(
Number of records to display
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
Coin Geckos API documentation (see /coins/markets part in https://www.coingecko.com/en/api/documentation)
API documentation (see /coins/markets in https://www.coingecko.com/en/api/documentation)
export : str
Export dataframe data to csv,json,xlsx file
"""
df = pycoingecko_model.get_gainers_or_losers(top=top, period=period, typ="gainers")
df = pycoingecko_model.get_gainers_or_losers(
top=top, period=period, typ="gainers", sortby=sortby
)
if not df.empty:
if sortby in COINS_COLUMNS:
df = df[
(df["Volume [$]"].notna()) & (df["Market Cap"].notna())
(df["total_volume"].notna()) & (df["market_cap"].notna())
].sort_values(by=sortby, ascending=True)
for col in ["Volume [$]", "Market Cap"]:
for col in ["total_volume", "market_cap"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))
print_rich_table(
@@ -148,17 +145,15 @@ def display_losers(
Number of records to display
sortby: str
Key to sort data. The table can be sorted by every of its columns. Refer to
Coin Geckos API documentation (see /coins/markets part in https://www.coingecko.com/en/api/documentation)
API documentation (see /coins/markets in https://www.coingecko.com/en/api/documentation)
export : str
Export dataframe data to csv,json,xlsx file
"""
df = pycoingecko_model.get_gainers_or_losers(top=top, period=period, typ="losers")
df = pycoingecko_model.get_gainers_or_losers(
top=top, period=period, typ="losers", sortby=sortby
)
if not df.empty:
if sortby in COINS_COLUMNS:
df = df[
(df["Volume [$]"].notna()) & (df["Market Cap"].notna())
].sort_values(by=sortby, ascending=True)
for col in ["Volume [$]", "Market Cap"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))

View File

@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def _get_trading_pairs() -> List[dict]:
"""Helper method that return all trading pairs on binance. Other methods are use this data as an input for e.g
"""Helper method that return all trading pairs on binance. Methods ause this data for input for e.g
building dataframe with all coins, or to build dict of all trading pairs. [Source: Binance]
Returns
@@ -27,8 +27,8 @@ def _get_trading_pairs() -> List[dict]:
list of dictionaries in format:
[
{'symbol': 'ETHBTC', 'status': 'TRADING', 'baseAsset': 'ETH', 'baseAssetPrecision': 8,
'quoteAsset': 'BTC', 'quotePrecision': 8, 'quoteAssetPrecision': 8, 'baseCommissionPrecision': 8,
'quoteCommissionPrecision': 8,
'quoteAsset': 'BTC', 'quotePrecision': 8, 'quoteAssetPrecision': 8,
'baseCommissionPrecision': 8, 'quoteCommissionPrecision': 8,
'orderTypes': ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'],
'icebergAllowed': True,
'ocoAllowed': True,

View File

@@ -22,9 +22,9 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_order_book(
coin: str,
from_symbol: str,
limit: int = 100,
currency: str = "USDT",
to_symbol: str = "USDT",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -33,11 +33,11 @@ def display_order_book(
Parameters
----------
coin: str
from_symbol: str
Cryptocurrency symbol
limit: int
Limit parameter. Adjusts the weight
currency: str
to_symbol: str
Quote currency (what to view coin vs)
export: str
Export dataframe data to csv,json,xlsx
@@ -45,7 +45,7 @@ def display_order_book(
External axes (1 axis is expected in the list), by default None
"""
pair = coin + currency
pair = from_symbol + to_symbol
client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET)
@@ -55,7 +55,7 @@ def display_order_book(
asks = np.asarray(market_book["asks"], dtype=float)
bids = np.insert(bids, 2, bids[:, 1].cumsum(), axis=1)
asks = np.insert(asks, 2, np.flipud(asks[:, 1]).cumsum(), axis=1)
plot_order_book(bids, asks, coin, external_axes)
plot_order_book(bids, asks, to_symbol, external_axes)
export_data(
export,
@@ -64,16 +64,20 @@ def display_order_book(
pd.DataFrame(market_book),
)
except BinanceAPIException:
console.print(f"{coin} is not a valid binance symbol")
console.print(f"{to_symbol} is not a valid binance symbol")
@log_start_end(log=logger)
def display_balance(coin: str, currency: str = "USDT", export: str = "") -> None:
def display_balance(
from_symbol: str, to_symbol: str = "USDT", export: str = ""
) -> None:
"""Get account holdings for asset. [Source: Binance]
Parameters
----------
coin: str
from_symbol: str
Cryptocurrency
to_symbol: str
Cryptocurrency
currency: str
Quote currency (what to view coin vs)
@@ -83,20 +87,19 @@ def display_balance(coin: str, currency: str = "USDT", export: str = "") -> None
client = Client(cfg.API_BINANCE_KEY, cfg.API_BINANCE_SECRET)
pair = coin + currency
pair = from_symbol + to_symbol
current_balance = client.get_asset_balance(asset=pair)
if current_balance is None:
console.print("Check loaded coin")
console.print("Check loaded coin\n")
return
console.print("")
amounts = [float(current_balance["free"]), float(current_balance["locked"])]
total = np.sum(amounts)
df = pd.DataFrame(amounts).apply(lambda x: str(float(x)))
df.columns = ["Amount"]
df.index = ["Free", "Locked"]
df["Percent"] = df.div(df.sum(axis=0), axis=1).round(3)
console.print(f"You currently have {total} coins and the breakdown is:")
console.print(f"\nYou currently have {total} coins and the breakdown is:")
print_rich_table(
df, headers=df.columns, show_index=True, title="Account Holdings for Assets"

View File

@@ -4,6 +4,7 @@ __docformat__ = "numpy"
from typing import Dict
import ccxt
import pandas as pd
from openbb_terminal.cryptocurrency.dataframe_helpers import prettify_column_names
def get_exchanges():
@@ -21,7 +22,7 @@ def get_exchanges():
return ccxt.exchanges
def get_orderbook(exchange_id: str, coin: str, vs: str) -> Dict:
def get_orderbook(exchange_id: str, symbol: str, vs: str) -> Dict:
"""Returns orderbook for a coin in a given exchange
[Source: https://docs.ccxt.com/en/latest/manual.html]
@@ -29,7 +30,7 @@ def get_orderbook(exchange_id: str, coin: str, vs: str) -> Dict:
----------
exchange_id : str
exchange id
coin : str
symbol : str
coin symbol
vs : str
currency to compare coin against
@@ -40,11 +41,11 @@ def get_orderbook(exchange_id: str, coin: str, vs: str) -> Dict:
"""
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class()
ob = exchange.fetch_order_book(f"{coin.upper()}/{vs.upper()}")
ob = exchange.fetch_order_book(f"{symbol.upper()}/{vs.upper()}")
return ob
def get_trades(exchange_id: str, coin: str, vs: str) -> pd.DataFrame:
def get_trades(exchange_id: str, symbol: str, vs: str) -> pd.DataFrame:
"""Returns trades for a coin in a given exchange
[Source: https://docs.ccxt.com/en/latest/manual.html]
@@ -52,7 +53,7 @@ def get_trades(exchange_id: str, coin: str, vs: str) -> pd.DataFrame:
----------
exchange_id : str
exchange id
coin : str
symbol : str
coin symbol
vs : str
currency to compare coin against
@@ -64,7 +65,9 @@ def get_trades(exchange_id: str, coin: str, vs: str) -> pd.DataFrame:
"""
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class()
trades = exchange.fetch_trades(f"{coin.upper()}/{vs.upper()}")
trades = exchange.fetch_trades(f"{symbol.upper()}/{vs.upper()}")
df = pd.DataFrame(trades, columns=["datetime", "price", "amount", "cost", "side"])
df["datetime"] = pd.to_datetime(df["datetime"])
df.rename(columns={"datetime": "date"}, inplace=True)
df.columns = prettify_column_names(df.columns)
return df

View File

@@ -7,14 +7,13 @@ from typing import List, Optional
from matplotlib import pyplot as plt
import numpy as np
from openbb_terminal.cryptocurrency.cryptocurrency_helpers import plot_order_book
from openbb_terminal.cryptocurrency.dataframe_helpers import prettify_column_names
from openbb_terminal.cryptocurrency.due_diligence import ccxt_model
from openbb_terminal.helper_funcs import export_data, print_rich_table
def display_order_book(
exchange: str,
coin: str,
symbol: str,
vs: str,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -26,20 +25,20 @@ def display_order_book(
----------
exchange : str
exchange id
coin : str
symbol : str
coin symbol
vs : str
currency to compare coin against
export : str
Export dataframe data to csv,json,xlsx file
"""
market_book = ccxt_model.get_orderbook(exchange_id=exchange, coin=coin, vs=vs)
market_book = ccxt_model.get_orderbook(exchange_id=exchange, symbol=symbol, vs=vs)
bids = np.asarray(market_book["bids"], dtype=float)
asks = np.asarray(market_book["asks"], dtype=float)
bids = np.insert(bids, 2, bids[:, 1].cumsum(), axis=1)
asks = np.insert(asks, 2, np.flipud(asks[:, 1]).cumsum(), axis=1)
plot_order_book(
bids, asks, f"{exchange.upper()}:{coin.upper()}/{vs.upper()}", external_axes
bids, asks, f"{exchange.upper()}:{symbol.upper()}/{vs.upper()}", external_axes
)
export_data(
@@ -50,7 +49,9 @@ def display_order_book(
)
def display_trades(exchange: str, coin: str, vs: str, top: int = 10, export: str = ""):
def display_trades(
exchange: str, symbol: str, vs: str, limit: int = 10, export: str = ""
):
"""Displays trades for a coin in a given exchange
[Source: https://docs.ccxt.com/en/latest/manual.html]
@@ -58,24 +59,21 @@ def display_trades(exchange: str, coin: str, vs: str, top: int = 10, export: str
----------
exchange : str
exchange id
coin : str
symbol : str
coin symbol
vs : str
currency to compare coin against
top : int
limit : int
number of trades to display
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ccxt_model.get_trades(exchange_id=exchange, coin=coin, vs=vs)
df.rename(columns={"datetime": "date"}, inplace=True)
df.columns = prettify_column_names(df.columns)
df = ccxt_model.get_trades(exchange_id=exchange, symbol=symbol, vs=vs)
print_rich_table(
df.head(top),
df.head(limit),
headers=list(df.columns),
show_index=False,
title=f"Trades for {exchange.upper()}:{coin.upper()}/{vs.upper()}",
title=f"Trades for {exchange.upper()}:{symbol.upper()}/{vs.upper()}",
)
export_data(

View File

@@ -33,12 +33,12 @@ def show_available_pairs_for_given_symbol(symbol: str = "ETH") -> Tuple[str, lis
@log_start_end(log=logger)
def get_trading_pair_info(product_id: str) -> pd.DataFrame:
def get_trading_pair_info(symbol: str) -> pd.DataFrame:
"""Get information about chosen trading pair. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
Returns
@@ -47,7 +47,7 @@ def get_trading_pair_info(product_id: str) -> pd.DataFrame:
Basic information about given trading pair
"""
product_id = check_validity_of_product(product_id)
product_id = check_validity_of_product(symbol)
pair = make_coinbase_request(f"/products/{product_id}")
df = pd.Series(pair).to_frame().reset_index()
df.columns = ["Metric", "Value"]
@@ -56,12 +56,12 @@ def get_trading_pair_info(product_id: str) -> pd.DataFrame:
@log_start_end(log=logger)
def get_order_book(product_id: str) -> Tuple[np.ndarray, np.ndarray, str, dict]:
def get_order_book(symbol: str) -> Tuple[np.ndarray, np.ndarray, str, dict]:
"""Get orders book for chosen trading pair. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
Returns
@@ -73,10 +73,10 @@ def get_order_book(product_id: str) -> Tuple[np.ndarray, np.ndarray, str, dict]:
dict with raw data
"""
# TODO: Order with price much higher then current price. E.g current price 200 USD, sell order with 10000 USD
# TODO: Order price > current price. E.g current price 200 USD, sell order with 10000 USD
# makes chart look very ugly (bad scaling). Think about removing outliers or add log scale ?
product_id = check_validity_of_product(product_id)
product_id = check_validity_of_product(symbol)
market_book = make_coinbase_request(f"/products/{product_id}/book?level=2")
size = min(
@@ -99,13 +99,13 @@ def get_order_book(product_id: str) -> Tuple[np.ndarray, np.ndarray, str, dict]:
@log_start_end(log=logger)
def get_trades(
product_id: str, limit: int = 1000, side: Optional[Any] = None
symbol: str, limit: int = 1000, side: Optional[Any] = None
) -> pd.DataFrame:
"""Get last N trades for chosen trading pair. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
limit: int
Last <limit> of trades. Maximum is 1000.
@@ -121,18 +121,18 @@ def get_trades(
if side is not None and side in ["buy", "sell"]:
params["side"] = side
product_id = check_validity_of_product(product_id)
product_id = check_validity_of_product(symbol)
product = make_coinbase_request(f"/products/{product_id}/trades", params=params)
return pd.DataFrame(product)[["time", "price", "size", "side"]]
@log_start_end(log=logger)
def get_candles(product_id: str, interval: str = "24h") -> pd.DataFrame:
def get_candles(symbol: str, interval: str = "24h") -> pd.DataFrame:
"""Get candles for chosen trading pair and time interval. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
interval: str
Time interval. One from 1min, 5min ,15min, 1hour, 6hour, 24hour
@@ -160,7 +160,7 @@ def get_candles(product_id: str, interval: str = "24h") -> pd.DataFrame:
granularity: int = interval_map[interval]
product_id = check_validity_of_product(product_id)
product_id = check_validity_of_product(symbol)
candles = make_coinbase_request(
f"/products/{product_id}/candles", params={"granularity": granularity}
)
@@ -186,13 +186,13 @@ def get_candles(product_id: str, interval: str = "24h") -> pd.DataFrame:
@log_start_end(log=logger)
def get_product_stats(product_id: str) -> pd.DataFrame:
def get_product_stats(symbol: str) -> pd.DataFrame:
"""Get 24 hr stats for the product. Volume is in base currency units.
Open, high and low are in quote currency units. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
Returns
@@ -201,7 +201,7 @@ def get_product_stats(product_id: str) -> pd.DataFrame:
24h stats for chosen trading pair
"""
product_id = check_validity_of_product(product_id)
product_id = check_validity_of_product(symbol)
product = make_coinbase_request(f"/products/{product_id}/stats")
df = pd.Series(product).reset_index()
df.columns = ["Metric", "Value"]

View File

@@ -21,7 +21,7 @@ register_matplotlib_converters()
@log_start_end(log=logger)
def display_order_book(
product_id: str,
symbol: str,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -29,14 +29,14 @@ def display_order_book(
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
export : str
Export dataframe data to csv,json,xlsx file
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
bids, asks, pair, market_book = coinbase_model.get_order_book(product_id)
bids, asks, pair, market_book = coinbase_model.get_order_book(symbol)
plot_order_book(bids, asks, pair, external_axes)
export_data(
@@ -49,13 +49,13 @@ def display_order_book(
@log_start_end(log=logger)
def display_trades(
product_id: str, limit: int = 20, side: Optional[str] = None, export: str = ""
symbol: str, limit: int = 20, side: Optional[str] = None, export: str = ""
) -> None:
"""Display last N trades for chosen trading pair. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
limit: int
Last <limit> of trades. Maximum is 1000.
@@ -65,30 +65,20 @@ def display_trades(
Export dataframe data to csv,json,xlsx file
"""
df = coinbase_model.get_trades(product_id, limit, side)
df_data = df.copy()
df = coinbase_model.get_trades(symbol, limit, side)
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
)
print_rich_table(df, headers=list(df.columns), show_index=False)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"trades",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "trades", df)
@log_start_end(log=logger)
def display_candles(product_id: str, interval: str = "24h", export: str = "") -> None:
def display_candles(symbol: str, interval: str = "24h", export: str = "") -> None:
"""Get candles for chosen trading pair and time interval. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
interval: str
Time interval. One from 1m, 5m ,15m, 1h, 6h, 24h
@@ -96,44 +86,32 @@ def display_candles(product_id: str, interval: str = "24h", export: str = "") ->
Export dataframe data to csv,json,xlsx file
"""
df = coinbase_model.get_candles(product_id, interval)
df_data = df.copy()
df = coinbase_model.get_candles(symbol, interval)
print_rich_table(
df, headers=list(df.columns), show_index=True, title="Trading Pair Candles"
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"candles",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "candles", df)
@log_start_end(log=logger)
def display_stats(product_id: str, export: str = "") -> None:
def display_stats(symbol: str, export: str = "") -> None:
"""Get 24 hr stats for the product. Volume is in base currency units.
Open, high and low are in quote currency units. [Source: Coinbase]
Parameters
----------
product_id: str
symbol: str
Trading pair of coins on Coinbase e.g ETH-USDT or UNI-ETH
export : str
Export dataframe data to csv,json,xlsx file
"""
df = coinbase_model.get_product_stats(product_id)
df_data = df.copy()
df = coinbase_model.get_product_stats(symbol)
print_rich_table(
df, headers=list(df.columns), show_index=False, title="24 hr Product Stats"
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"stats",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "stats", df)

View File

@@ -79,7 +79,7 @@ def get_funding_rate(symbol: str) -> pd.DataFrame:
@log_start_end(log=logger)
def get_open_interest_per_exchange(symbol: str, interval: int) -> pd.DataFrame:
def get_open_interest_per_exchange(symbol: str, interval: int = 0) -> pd.DataFrame:
"""Returns open interest by exchange for a certain symbol
[Source: https://coinglass.github.io/API-Reference/]
@@ -88,7 +88,7 @@ def get_open_interest_per_exchange(symbol: str, interval: int) -> pd.DataFrame:
symbol : str
Crypto Symbol to search open interest futures (e.g., BTC)
interval : int
Interval frequency (e.g., 0)
Frequency (possible values are: 0 for ALL, 2 for 1H, 1 for 4H, 4 for 12H), by default 0
Returns
-------

View File

@@ -63,7 +63,7 @@ def display_open_interest(symbol: str, interval: int = 0, export: str = "") -> N
symbol : str
Crypto symbol to search open interest (e.g., BTC)
interval : int
Interval frequency (possible values are: 0 for ALL, 2 for 1H, 1 for 4H, 4 for 12H), by default 0
Frequency (possible values are: 0 for ALL, 2 for 1H, 1 for 4H, 4 for 12H), by default 0
export : str
Export dataframe data to csv,json,xlsx file"""
df = get_open_interest_per_exchange(symbol, interval)
@@ -89,9 +89,9 @@ def display_open_interest(symbol: str, interval: int = 0, export: str = "") -> N
@log_start_end(log=logger)
def plot_data(
df: pd.DataFrame,
symbol: str,
title: str,
ylabel: str,
symbol: str = "",
title: str = "",
ylabel: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -119,12 +119,15 @@ def plot_data(
ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x))
)
ax1.legend(df_without_price.columns, fontsize="x-small", ncol=2)
ax1.set_title(title)
ax1.set_ylabel(ylabel)
if title:
ax1.set_title(title)
if ylabel:
ax1.set_ylabel(ylabel)
ax2.plot(df_price.index, df_price)
ax2.legend([f"{symbol} price"])
ax2.set_ylabel(f"{symbol} Price [$]")
if symbol:
ax2.legend([f"{symbol} price"])
ax2.set_ylabel(f"{symbol} Price [$]")
ax2.set_xlim([df_price.index[0], df_price.index[-1]])
ax2.set_ylim(bottom=0.0)

View File

@@ -17,12 +17,12 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_coin(coin_id: str = "eth-ethereum") -> dict:
def get_coin(symbol: str = "eth-ethereum") -> dict:
"""Get coin by id [Source: CoinPaprika]
Parameters
----------
coin_id: str
symbol: str
id of coin from coinpaprika e.g. Ethereum - > 'eth-ethereum'
Returns
-------
@@ -31,18 +31,26 @@ def get_coin(coin_id: str = "eth-ethereum") -> dict:
"""
session = PaprikaSession()
coin = session.make_request(session.ENDPOINTS["coin"].format(coin_id))
coin = session.make_request(session.ENDPOINTS["coin"].format(symbol))
return coin
@log_start_end(log=logger)
def get_coin_twitter_timeline(coin_id: str = "eth-ethereum") -> pd.DataFrame:
def get_coin_twitter_timeline(
symbol: str = "eth-ethereum", sortby: str = "date", ascend: bool = True
) -> pd.DataFrame:
"""Get twitter timeline for given coin id. Not more than last 50 tweets [Source: CoinPaprika]
Parameters
----------
coin_id: str
symbol: str
id of coin from coinpaprika e.g. Ethereum - > 'eth-ethereum'
sortby: str
Key by which to sort data. Every column name is valid
(see for possible values:
https://api.coinpaprika.com/docs#tag/Coins/paths/~1coins~1%7Bcoin_id%7D~1twitter/get).
ascend: bool
Flag to sort data descending
Returns
-------
pandas.DataFrame
@@ -51,7 +59,7 @@ def get_coin_twitter_timeline(coin_id: str = "eth-ethereum") -> pd.DataFrame:
"""
session = PaprikaSession()
res = session.make_request(session.ENDPOINTS["coin_tweeter"].format(coin_id))
res = session.make_request(session.ENDPOINTS["coin_tweeter"].format(symbol))
if "error" in res:
console.print(res)
return pd.DataFrame()
@@ -67,34 +75,46 @@ def get_coin_twitter_timeline(coin_id: str = "eth-ethereum") -> pd.DataFrame:
df["status"] = df["status"].apply(lambda x: x.replace(" ", ""))
df["date"] = df["date"].apply(lambda x: x.replace("T", "\n"))
df["date"] = df["date"].apply(lambda x: x.replace("Z", ""))
df = df.sort_values(by=sortby, ascending=ascend)
# Remove unicode chars (it breaks pretty tables)
df["status"] = df["status"].apply(
lambda text: "".join(i if ord(i) < 128 else "" for i in text)
)
return df
@log_start_end(log=logger)
def get_coin_events_by_id(coin_id: str = "eth-ethereum") -> pd.DataFrame:
"""Get all events related to given coin like conferences, start date of futures trading etc. [Source: CoinPaprika]
def get_coin_events_by_id(
symbol: str = "eth-ethereum", sortby="date", ascend: bool = False
) -> pd.DataFrame:
"""Get all events related to given coin like conferences, start date of futures trading etc.
[Source: CoinPaprika]
Example of response from API:
.. code-block:: json
{
"id": "17398-cme-april-first-trade",
"date": "2018-04-02T00:00:00Z",
"date_to": "string",
"name": "CME: April First Trade",
"description": "First trade of Bitcoin futures contract for April 2018.",
"is_conference": false,
"link": "http://www.cmegroup.com/trading/equity-index/us-index/bitcoin_product_calendar_futures.html",
"proof_image_link": "https://static.coinpaprika.com/storage/cdn/event_images/16635.jpg"
}
.
{
"id": "17398-cme-april-first-trade",
"date": "2018-04-02T00:00:00Z",
"date_to": "string",
"name": "CME: April First Trade",
"description": "First trade of Bitcoin futures contract for April 2018.",
"is_conference": false,
"link": "http://www.cmegroup.com/trading/equity-index/us-index/bitcoin_product_calendar_futures.html",
"proof_image_link": "https://static.coinpaprika.com/storage/cdn/event_images/16635.jpg"
}
Parameters
----------
coin_id: str
symbol: str
id of coin from coinpaprika e.g. Ethereum - > 'eth-ethereum'
sortby: str
Key by which to sort data. Every column name is valid
(see for possible values:
https://api.coinpaprika.com/docs#tag/Coins/paths/~1coins~1%7Bcoin_id%7D~1events/get).
ascend: bool
Flag to sort data ascending
Returns
-------
pandas.DataFrame
@@ -103,7 +123,7 @@ def get_coin_events_by_id(coin_id: str = "eth-ethereum") -> pd.DataFrame:
"""
session = PaprikaSession()
res = session.make_request(session.ENDPOINTS["coin_events"].format(coin_id))
res = session.make_request(session.ENDPOINTS["coin_events"].format(symbol))
if not res or "error" in res:
return pd.DataFrame()
data = pd.DataFrame(res)
@@ -118,17 +138,28 @@ def get_coin_events_by_id(coin_id: str = "eth-ethereum") -> pd.DataFrame:
data[col] = data[col].apply(
lambda x: x.replace("Z", "") if isinstance(x, str) else x
)
data = data.sort_values(by=sortby, ascending=ascend)
return data
@log_start_end(log=logger)
def get_coin_exchanges_by_id(coin_id: str = "eth-ethereum") -> pd.DataFrame:
def get_coin_exchanges_by_id(
symbol: str = "eth-ethereum",
sortby: str = "adjusted_volume_24h_share",
ascend: bool = True,
) -> pd.DataFrame:
"""Get all exchanges for given coin id. [Source: CoinPaprika]
Parameters
----------
coin_id: str
symbol: str
Identifier of Coin from CoinPaprika
sortby: str
Key by which to sort data. Every column name is valid (see for possible values:
https://api.coinpaprika.com/v1).
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -138,32 +169,42 @@ def get_coin_exchanges_by_id(coin_id: str = "eth-ethereum") -> pd.DataFrame:
"""
session = PaprikaSession()
res = session.make_request(session.ENDPOINTS["coin_exchanges"].format(coin_id))
res = session.make_request(session.ENDPOINTS["coin_exchanges"].format(symbol))
df = pd.DataFrame(res)
if "fiats" in df.columns.tolist():
df["fiats"] = (
df["fiats"].copy().apply(lambda x: len([i["symbol"] for i in x if x]))
)
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_coin_markets_by_id(
coin_id: str = "eth-ethereum", quotes: str = "USD"
symbol: str = "eth-ethereum",
quotes: str = "USD",
sortby: str = "pct_volume_share",
ascend: bool = True,
) -> pd.DataFrame:
"""All markets for given coin and currency [Source: CoinPaprika]
Parameters
----------
coin_id: str
symbol: str
Coin Parpika identifier of coin e.g. eth-ethereum
quotes: str
Comma separated list of quotes to return.
Example: quotes=USD,BTC
Allowed values:
BTC, ETH, USD, EUR, PLN, KRW, GBP, CAD, JPY, RUB, TRY, NZD, AUD, CHF, UAH, HKD, SGD, NGN, PHP, MXN, BRL,
THB, CLP, CNY, CZK, DKK, HUF, IDR, ILS, INR, MYR, NOK, PKR, SEK, TWD, ZAR, VND, BOB, COP, PEN, ARS, ISK
BTC, ETH, USD, EUR, PLN, KRW, GBP, CAD, JPY, RUB, TRY, NZD, AUD, CHF, UAH, HKD, SGD, NGN,
PHP, MXN, BRL, THB, CLP, CNY, CZK, DKK, HUF, IDR, ILS, INR, MYR, NOK, PKR, SEK, TWD, ZAR,
VND, BOB, COP, PEN, ARS, ISK
sortby: str
Key by which to sort data. Every column name is valid (see for possible values:
https://api.coinpaprika.com/v1).
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -173,7 +214,7 @@ def get_coin_markets_by_id(
session = PaprikaSession()
markets = session.make_request(
session.ENDPOINTS["coin_markets"].format(coin_id), quotes=quotes
session.ENDPOINTS["coin_markets"].format(symbol), quotes=quotes
)
if "error" in markets:
console.print(markets)
@@ -194,12 +235,14 @@ def get_coin_markets_by_id(
dct["market_url"] = r.get("market_url")
data.append(dct)
return pd.DataFrame(data)
df = pd.DataFrame(data)
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_ohlc_historical(
coin_id: str = "eth-ethereum", quotes: str = "USD", days: int = 90
symbol: str = "eth-ethereum", quotes: str = "USD", days: int = 90
) -> pd.DataFrame:
"""
Open/High/Low/Close values with volume and market_cap. [Source: CoinPaprika]
@@ -209,7 +252,7 @@ def get_ohlc_historical(
Parameters
----------
coin_id: str
symbol: str
Paprika coin identifier e.g. eth-ethereum
quotes: str
returned data quote (available values: usd btc)
@@ -233,7 +276,7 @@ def get_ohlc_historical(
session = PaprikaSession()
data = session.make_request(
session.ENDPOINTS["ohlcv_hist"].format(coin_id),
session.ENDPOINTS["ohlcv_hist"].format(symbol),
quotes=quotes,
start=start,
end=end,
@@ -248,7 +291,7 @@ def get_ohlc_historical(
@log_start_end(log=logger)
def get_tickers_info_for_coin(
coin_id: str = "btc-bitcoin", quotes: str = "USD"
symbol: str = "btc-bitcoin", quotes: str = "USD"
) -> pd.DataFrame:
"""Get all most important ticker related information for given coin id [Source: CoinPaprika]
@@ -290,7 +333,7 @@ def get_tickers_info_for_coin(
Parameters
----------
coin_id: str
symbol: str
Id of coin from CoinPaprika
quotes: str
Comma separated quotes to return e.g quotes = USD, BTC
@@ -304,7 +347,7 @@ def get_tickers_info_for_coin(
session = PaprikaSession()
tickers = session.make_request(
session.ENDPOINTS["ticker_info"].format(coin_id), quotes=quotes
session.ENDPOINTS["ticker_info"].format(symbol), quotes=quotes
)
for key, date in tickers.items():
@@ -336,12 +379,12 @@ def get_tickers_info_for_coin(
@log_start_end(log=logger)
def validate_coin(coin: str, coins_dct: dict) -> Tuple[Optional[Any], Optional[Any]]:
def validate_coin(symbol: str, coins_dct: dict) -> Tuple[Optional[Any], Optional[Any]]:
"""Helper method that validates if proper coin id or symbol was provided [Source: CoinPaprika]
Parameters
----------
coin: str
symbol: str
id or symbol of coin for CoinPaprika
coins_dct: dict
dictionary of coins
@@ -353,18 +396,18 @@ def validate_coin(coin: str, coins_dct: dict) -> Tuple[Optional[Any], Optional[A
"""
for key, value in coins_dct.items():
if coin == value:
if symbol == value:
return key, value.lower()
return None, None
@log_start_end(log=logger)
def basic_coin_info(coin_id: str = "btc-bitcoin") -> pd.DataFrame:
def basic_coin_info(symbol: str = "btc-bitcoin") -> pd.DataFrame:
"""Basic coin information [Source: CoinPaprika]
Parameters
----------
coin_id: str
symbol: str
Coin id
Returns
@@ -373,7 +416,7 @@ def basic_coin_info(coin_id: str = "btc-bitcoin") -> pd.DataFrame:
Metric, Value
"""
coin = get_coin(coin_id)
coin = get_coin(symbol)
tags = coin.get("tags") or []
keys = [
"id",

View File

@@ -86,9 +86,9 @@ CURRENCIES = [
@log_start_end(log=logger)
def display_twitter(
symbol: str = "BTC",
top: int = 10,
limit: int = 10,
sortby: str = "date",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Get twitter timeline for given coin id. Not more than last 50 tweets [Source: CoinPaprika]
@@ -97,14 +97,14 @@ def display_twitter(
----------
symbol: str
Cryptocurrency symbol (e.g. BTC)
top: int
limit: int
Number of records to display
sortby: str
Key by which to sort data. Every column name is valid
(see for possible values:
https://api.coinpaprika.com/docs#tag/Coins/paths/~1coins~1%7Bcoin_id%7D~1twitter/get).
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
"""
@@ -112,19 +112,14 @@ def display_twitter(
# get coinpaprika id using crypto symbol
cp_id = cryptocurrency_helpers.get_coinpaprika_id(symbol)
df = coinpaprika_model.get_coin_twitter_timeline(cp_id)
df = coinpaprika_model.get_coin_twitter_timeline(cp_id, sortby, ascend)
if df.empty:
console.print(f"Couldn't find any tweets for coin {symbol}", "\n")
return
df = df.sort_values(by=sortby, ascending=descend)
# Remove unicode chars (it breaks pretty tables)
df["status"] = df["status"].apply(
lambda text: "".join(i if ord(i) < 128 else "" for i in text)
)
print_rich_table(
df.head(top),
df.head(limit),
headers=list(df.columns),
show_index=False,
title="Twitter Timeline",
@@ -141,9 +136,9 @@ def display_twitter(
@log_start_end(log=logger)
def display_events(
symbol: str = "BTC",
top: int = 10,
limit: int = 10,
sortby: str = "date",
descend: bool = False,
ascend: bool = False,
links: bool = False,
export: str = "",
) -> None:
@@ -153,14 +148,14 @@ def display_events(
----------
symbol: str
Cryptocurrency symbol (e.g. BTC)
top: int
limit: int
Number of records to display
sortby: str
Key by which to sort data. Every column name is valid
(see for possible values:
https://api.coinpaprika.com/docs#tag/Coins/paths/~1coins~1%7Bcoin_id%7D~1events/get).
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
links: bool
Flag to display urls
export : str
@@ -169,14 +164,12 @@ def display_events(
# get coinpaprika id using crypto symbol
cp_id = cryptocurrency_helpers.get_coinpaprika_id(symbol)
df = coinpaprika_model.get_coin_events_by_id(cp_id)
df = coinpaprika_model.get_coin_events_by_id(cp_id, sortby, ascend)
if df.empty:
console.print(f"Couldn't find any events for coin {symbol}\n")
return
df = df.sort_values(by=sortby, ascending=descend)
df_data = df.copy()
if links is True:
@@ -185,7 +178,7 @@ def display_events(
df.drop("link", axis=1, inplace=True)
print_rich_table(
df.head(top), headers=list(df.columns), show_index=False, title="All Events"
df.head(limit), headers=list(df.columns), show_index=False, title="All Events"
)
export_data(
@@ -199,9 +192,9 @@ def display_events(
@log_start_end(log=logger)
def display_exchanges(
symbol: str = "btc",
top: int = 10,
limit: int = 10,
sortby: str = "adjusted_volume_24h_share",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Get all exchanges for given coin id. [Source: CoinPaprika]
@@ -210,12 +203,13 @@ def display_exchanges(
----------
symbol: str
Cryptocurrency symbol (e.g. BTC)
top: int
limit: int
Number of records to display
sortby: str
Key by which to sort data. Every column name is valid (see for possible values: https://api.coinpaprika.com/v1).
descend: bool
Flag to sort data descending
Key by which to sort data. Every column name is valid (see for possible values:
https://api.coinpaprika.com/v1).
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
"""
@@ -223,16 +217,17 @@ def display_exchanges(
# get coinpaprika id using crypto symbol
cp_id = cryptocurrency_helpers.get_coinpaprika_id(symbol)
df = coinpaprika_model.get_coin_exchanges_by_id(cp_id)
df = coinpaprika_model.get_coin_exchanges_by_id(cp_id, sortby, ascend)
if df.empty:
console.print("No data found", "\n")
return
df = df.sort_values(by=sortby, ascending=descend)
print_rich_table(
df.head(top), headers=list(df.columns), show_index=False, title="All Exchanges"
df.head(limit),
headers=list(df.columns),
show_index=False,
title="All Exchanges",
)
export_data(
@@ -245,11 +240,11 @@ def display_exchanges(
@log_start_end(log=logger)
def display_markets(
symbol: str = "BTC",
currency: str = "USD",
top: int = 20,
from_symbol: str = "BTC",
to_symbol: str = "USD",
limit: int = 20,
sortby: str = "pct_volume_share",
descend: bool = False,
ascend: bool = True,
links: bool = False,
export: str = "",
) -> None:
@@ -257,16 +252,17 @@ def display_markets(
Parameters
----------
symbol: str
from_symbol: str
Cryptocurrency symbol (e.g. BTC)
currency: str
to_symbol: str
Quoted currency
top: int
limit: int
Number of records to display
sortby: str
Key by which to sort data. Every column name is valid (see for possible values: https://api.coinpaprika.com/v1).
descend: bool
Flag to sort data descending
Key by which to sort data. Every column name is valid (see for possible values:
https://api.coinpaprika.com/v1).
ascend: bool
Flag to sort data ascending
links: bool
Flag to display urls
export : str
@@ -274,19 +270,17 @@ def display_markets(
"""
if sortby in ["volume", "price"]:
sortby = f"{str(currency).lower()}_{sortby}"
sortby = f"{str(to_symbol).lower()}_{sortby}"
# get coinpaprika id using crypto symbol
cp_id = cryptocurrency_helpers.get_coinpaprika_id(symbol)
cp_id = cryptocurrency_helpers.get_coinpaprika_id(from_symbol)
df = coinpaprika_model.get_coin_markets_by_id(cp_id, currency)
df = coinpaprika_model.get_coin_markets_by_id(cp_id, to_symbol, sortby, ascend)
if df.empty:
console.print("There is no data \n")
return
df = df.sort_values(by=sortby, ascending=descend)
df_data = df.copy()
if links is True:
@@ -295,7 +289,7 @@ def display_markets(
df.drop("market_url", axis=1, inplace=True)
print_rich_table(
df.head(top), headers=list(df.columns), show_index=False, title="All Markets"
df.head(limit), headers=list(df.columns), show_index=False, title="All Markets"
)
export_data(
@@ -308,26 +302,26 @@ def display_markets(
@log_start_end(log=logger)
def display_price_supply(
symbol: str = "BTC",
currency: str = "USD",
from_symbol: str = "BTC",
to_symbol: str = "USD",
export: str = "",
) -> None:
"""Get ticker information for single coin [Source: CoinPaprika]
Parameters
----------
symbol: str
from_symbol: str
Cryptocurrency symbol (e.g. BTC)
currency: str
to_symbol: str
Quoted currency
export: str
Export dataframe data to csv,json,xlsx
"""
# get coinpaprika id using crypto symbol
cp_id = cryptocurrency_helpers.get_coinpaprika_id(symbol)
cp_id = cryptocurrency_helpers.get_coinpaprika_id(from_symbol)
df = coinpaprika_model.get_tickers_info_for_coin(cp_id, currency)
df = coinpaprika_model.get_tickers_info_for_coin(cp_id, to_symbol)
if df.empty:
console.print("No data found", "\n")
@@ -353,7 +347,8 @@ def display_basic(
export: str = "",
) -> None:
"""Get basic information for coin. Like:
name, symbol, rank, type, description, platform, proof_type, contract, tags, parent. [Source: CoinPaprika]
name, symbol, rank, type, description, platform, proof_type, contract, tags, parent.
[Source: CoinPaprika]
Parameters
----------

View File

@@ -4,7 +4,6 @@ __docformat__ = "numpy"
import logging
import os
from typing import Optional
import pandas as pd
from openbb_terminal.cryptocurrency.overview import cryptopanic_model
from openbb_terminal.decorators import log_start_end
@@ -23,8 +22,8 @@ def display_news(
filter_: Optional[str] = None,
source: str = "cp",
currency: Optional[str] = None,
top: int = 25,
descend: bool = False,
limit: int = 25,
ascend: bool = True,
export: str = "",
) -> None:
"""Display recent posts from CryptoPanic news aggregator platform.
@@ -32,7 +31,7 @@ def display_news(
Parameters
----------
top: int
limit: int
number of news to display
post_kind: str
Filter by category of news. Available values: news or media.
@@ -41,30 +40,29 @@ def display_news(
region: str
Filter news by regions. Available regions are: en (English), de (Deutsch), nl (Dutch),
es (Español), fr (Français), it (Italiano), pt (Português), ru (Русский)
descend: bool
Sort in descending order.
ascend: bool
Sort in ascending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = cryptopanic_model.get_news(
limit=top,
limit=limit,
post_kind=post_kind,
filter_=filter_,
region=region,
currency=currency,
source=source,
ascend=ascend,
)
if not df.empty:
df = df.sort_values(by="published_at", ascending=descend)
df["published_at"] = pd.to_datetime(df["published_at"]).dt.date
df.drop(["negative_votes", "positive_votes", "domain"], axis=1, inplace=True)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df.head(top),
df.head(limit),
headers=list(df.columns),
show_index=False,
title="Most Recent News",

View File

@@ -267,9 +267,9 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
glassnode_view.display_non_zero_addresses(
asset=self.symbol.upper(),
since=int(datetime.timestamp(ns_parser.since)),
until=int(datetime.timestamp(ns_parser.until)),
symbol=self.symbol.upper(),
start_date=int(datetime.timestamp(ns_parser.since)),
end_date=int(datetime.timestamp(ns_parser.until)),
export=ns_parser.export,
)
@@ -355,10 +355,10 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
glassnode_view.display_active_addresses(
asset=self.symbol.upper(),
symbol=self.symbol.upper(),
interval=ns_parser.interval,
since=int(datetime.timestamp(ns_parser.since)),
until=int(datetime.timestamp(ns_parser.until)),
start_date=int(datetime.timestamp(ns_parser.since)),
end_date=int(datetime.timestamp(ns_parser.until)),
export=ns_parser.export,
)
@@ -419,10 +419,10 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
glassnode_view.display_exchange_net_position_change(
asset=self.symbol.upper(),
symbol=self.symbol.upper(),
exchange=ns_parser.exchange,
since=int(datetime.timestamp(ns_parser.since)),
until=int(datetime.timestamp(ns_parser.until)),
start_date=int(datetime.timestamp(ns_parser.since)),
end_date=int(datetime.timestamp(ns_parser.until)),
export=ns_parser.export,
)
else:
@@ -489,10 +489,10 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
glassnode_view.display_exchange_balances(
asset=self.symbol.upper(),
symbol=self.symbol.upper(),
exchange=ns_parser.exchange,
since=int(datetime.timestamp(ns_parser.since)),
until=int(datetime.timestamp(ns_parser.until)),
start_date=int(datetime.timestamp(ns_parser.since)),
end_date=int(datetime.timestamp(ns_parser.until)),
percentage=ns_parser.percentage,
export=ns_parser.export,
)
@@ -801,7 +801,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
ccxt_view.display_order_book(
ns_parser.exchange,
coin=self.symbol,
symbol=self.symbol,
vs=ns_parser.vs,
export=ns_parser.export,
)
@@ -845,10 +845,10 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
ccxt_view.display_trades(
ns_parser.exchange,
coin=self.symbol,
symbol=self.symbol,
vs=ns_parser.vs,
export=ns_parser.export,
top=ns_parser.limit,
limit=ns_parser.limit,
)
@log_start_end(log=logger)
@@ -879,7 +879,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
binance_view.display_balance(
coin=coin, currency=ns_parser.vs, export=ns_parser.export
to_symbol=coin, from_symbol=ns_parser.vs, export=ns_parser.export
)
@log_start_end(log=logger)
@@ -1001,9 +1001,9 @@ class DueDiligenceController(CryptoBaseController):
coinpaprika_view.display_markets(
symbol=self.symbol,
currency=ns_parser.vs,
top=ns_parser.limit,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
links=ns_parser.urls,
export=ns_parser.export,
)
@@ -1057,9 +1057,9 @@ class DueDiligenceController(CryptoBaseController):
if self.symbol:
coinpaprika_view.display_exchanges(
symbol=self.symbol,
top=ns_parser.limit,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1123,9 +1123,9 @@ class DueDiligenceController(CryptoBaseController):
if self.symbol:
coinpaprika_view.display_events(
symbol=self.symbol,
top=ns_parser.limit,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
links=ns_parser.urls,
export=ns_parser.export,
)
@@ -1180,9 +1180,9 @@ class DueDiligenceController(CryptoBaseController):
if self.symbol:
coinpaprika_view.display_twitter(
symbol=self.symbol,
top=ns_parser.limit,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1234,10 +1234,10 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_marketcap_dominance(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
interval=ns_parser.interval,
start=ns_parser.start,
end=ns_parser.end,
start_date=ns_parser.start,
end_date=ns_parser.end,
export=ns_parser.export,
)
@@ -1260,7 +1260,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_links(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1323,7 +1323,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
santiment_view.display_github_activity(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
interval=ns_parser.interval,
dev_activity=ns_parser.dev,
start=ns_parser.start.strftime("%Y-%m-%dT%H:%M:%SZ"),
@@ -1357,8 +1357,8 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_roadmap(
descend=ns_parser.descend,
coin=self.symbol.upper(),
ascend=not ns_parser.descend,
symbol=self.symbol.upper(),
limit=ns_parser.limit,
export=ns_parser.export,
)
@@ -1384,7 +1384,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
if self.symbol:
messari_view.display_tokenomics(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1408,7 +1408,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_project_info(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1432,7 +1432,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_team(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1456,7 +1456,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_investors(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1480,7 +1480,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_fundraising(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1504,7 +1504,7 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
messari_view.display_governance(
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
export=ns_parser.export,
)
@@ -1607,10 +1607,10 @@ class DueDiligenceController(CryptoBaseController):
else:
messari_view.display_messari_timeseries(
timeseries_id=ns_parser.timeseries,
coin=self.symbol.upper(),
symbol=self.symbol.upper(),
interval=ns_parser.interval,
start=ns_parser.start,
end=ns_parser.end,
start_date=ns_parser.start,
end_date=ns_parser.end,
export=ns_parser.export,
)
@@ -1648,7 +1648,7 @@ class DueDiligenceController(CryptoBaseController):
"--filter",
dest="filter",
type=str,
help="Filter by kind of news. One from list: rising|hot|bullish|bearish|important|saved|lol",
help="Filter by kind of news. From: rising|hot|bullish|bearish|important|saved|lol",
default=None,
required=False,
choices=cryptopanic_model.FILTERS,
@@ -1659,8 +1659,11 @@ class DueDiligenceController(CryptoBaseController):
"--region",
dest="region",
type=str,
help="Filter news by regions. Available regions are: en (English), de (Deutsch), nl (Dutch), es (Español), "
"fr (Français), it (Italiano), pt (Português), ru (Русский)",
help=(
"Filter news by regions. Available regions are: en (English), de (Deutsch), nl"
" (Dutch), es (Español), fr (Français), it (Italiano), pt (Português), ru "
"(Русский)"
),
default="en",
choices=cryptopanic_model.REGIONS,
)
@@ -1688,7 +1691,7 @@ class DueDiligenceController(CryptoBaseController):
"--urls",
dest="urls",
action="store_false",
help="Flag to disable urls. If you will use the flag you will hide the column with urls",
help="Flag to disable urls. Hides column with URL.",
default=True,
)
@@ -1698,11 +1701,11 @@ class DueDiligenceController(CryptoBaseController):
if ns_parser:
cryptopanic_view.display_news(
top=ns_parser.limit,
limit=ns_parser.limit,
source=self.source,
currency=self.symbol,
export=ns_parser.export,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
post_kind=ns_parser.kind,
filter_=ns_parser.filter,
region=ns_parser.region,

View File

@@ -37,7 +37,7 @@ except ValueError:
@log_start_end(log=logger)
def display_crypto_sentiment_analysis(
coin: str,
symbol: str,
raw: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -53,7 +53,7 @@ def display_crypto_sentiment_analysis(
Parameters
----------
coin: str
symbol: str
Cryptocurrency
raw : False
Display raw table data
@@ -63,10 +63,10 @@ def display_crypto_sentiment_analysis(
External axes (1 axis is expected in the list), by default None
"""
sentiment = get_sentiment(f"{coin}-USD") # Currently only USD pairs are available
sentiment = get_sentiment(f"{symbol}-USD") # Currently only USD pairs are available
if sentiment.empty:
console.print(f"Couldn't find Sentiment Data for {coin}\n")
console.print(f"Couldn't find Sentiment Data for {symbol}\n")
return
if not raw:
@@ -85,7 +85,9 @@ def display_crypto_sentiment_analysis(
ax.set_xlabel("Time")
ax.set_ylabel("Finbrain's Sentiment Score")
start_date = sentiment.index[0].strftime("%Y/%m/%d")
ax.set_title(f"FinBrain's Sentiment Analysis for {coin}-USD since {start_date}")
ax.set_title(
f"FinBrain's Sentiment Analysis for {symbol}-USD since {start_date}"
)
ax.set_ylim([-1.1, 1.1])
senValues = np.array(pd.to_numeric(sentiment["Sentiment Analysis"].values))
senNone = np.array(0 * len(sentiment))

View File

@@ -1,5 +1,6 @@
import json
import logging
from datetime import datetime
import pandas as pd
import requests
@@ -173,18 +174,21 @@ INTERVALS_ACTIVE_ADDRESSES = ["24h", "1w", "1month"]
@log_start_end(log=logger)
def get_close_price(
asset: str, since: int, until: int, print_errors: bool = True
symbol: str,
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
print_errors: bool = True,
) -> pd.DataFrame:
"""Returns the price of a cryptocurrency
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Crypto to check close price (BTC or ETH)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_641_227_783_561)
print_errors: bool
Flag to print errors. Default: True
@@ -199,10 +203,10 @@ def get_close_price(
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": "24h",
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
r = requests.get(url, params=parameters)
@@ -214,7 +218,7 @@ def get_close_price(
if df.empty:
if print_errors:
console.print(f"No data found for {asset} price.\n")
console.print(f"No data found for {symbol} price.\n")
else:
df = df.set_index("t")
df.index = pd.to_datetime(df.index, unit="s")
@@ -230,17 +234,21 @@ def get_close_price(
@log_start_end(log=logger)
def get_non_zero_addresses(asset: str, since: int, until: int) -> pd.DataFrame:
"""Returns addresses with non-zero balance of a certain asset
def get_non_zero_addresses(
symbol: str,
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Returns addresses with non-zero balance of a certain symbol
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Asset to search (e.g., BTC)
since : int
start_date : int
Initial date timestamp (e.g., 1_577_836_800)
until : int
end_date : int
End date timestamp (e.g., 1_609_459_200)
Returns
@@ -253,10 +261,10 @@ def get_non_zero_addresses(asset: str, since: int, until: int) -> pd.DataFrame:
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": "24h",
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
r = requests.get(url, params=parameters)
@@ -267,7 +275,7 @@ def get_non_zero_addresses(asset: str, since: int, until: int) -> pd.DataFrame:
df = pd.DataFrame(json.loads(r.text))
if df.empty:
console.print(f"No data found for {asset}'s non-zero addresses.\n")
console.print(f"No data found for {symbol}'s non-zero addresses.\n")
else:
df["t"] = pd.to_datetime(df["t"], unit="s")
df = df.set_index("t")
@@ -282,18 +290,21 @@ def get_non_zero_addresses(asset: str, since: int, until: int) -> pd.DataFrame:
@log_start_end(log=logger)
def get_active_addresses(
asset: str, interval: str, since: int, until: int
symbol: str,
interval: str = "24h",
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Returns active addresses of a certain asset
"""Returns active addresses of a certain symbol
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Asset to search active addresses (e.g., BTC)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
interval : str
Interval frequency (e.g., 24h)
@@ -308,10 +319,10 @@ def get_active_addresses(
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": interval,
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
r = requests.get(url, params=parameters)
@@ -321,7 +332,7 @@ def get_active_addresses(
df = pd.DataFrame(json.loads(r.text))
if df.empty:
console.print(f"No data found for {asset}'s active addresses.\n")
console.print(f"No data found for {symbol}'s active addresses.\n")
else:
df["t"] = pd.to_datetime(df["t"], unit="s")
df = df.set_index("t")
@@ -335,17 +346,22 @@ def get_active_addresses(
@log_start_end(log=logger)
def get_hashrate(asset: str, interval: str, since: int, until: int) -> pd.DataFrame:
"""Returns dataframe with mean hashrate of btc or eth blockchain and asset price
def get_hashrate(
symbol: str,
interval: str = "24h",
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Returns dataframe with mean hashrate of btc or eth blockchain and symbol price
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Blockchain to check hashrate (BTC or ETH)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
interval : str
Interval frequency (e.g., 24h)
@@ -353,7 +369,7 @@ def get_hashrate(asset: str, interval: str, since: int, until: int) -> pd.DataFr
Returns
-------
pd.DataFrame
mean hashrate and asset price over time
mean hashrate and symbol price over time
"""
url = api_url + "mining/hash_rate_mean"
@@ -361,10 +377,10 @@ def get_hashrate(asset: str, interval: str, since: int, until: int) -> pd.DataFr
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": interval,
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
df = pd.DataFrame()
@@ -377,7 +393,7 @@ def get_hashrate(asset: str, interval: str, since: int, until: int) -> pd.DataFr
df2 = pd.DataFrame(json.loads(r2.text))
if df.empty or df2.empty:
console.print(f"No data found for {asset}'s hashrate or price.\n")
console.print(f"No data found for {symbol}'s hashrate or price.\n")
else:
df = df.set_index("t")
df.index = pd.to_datetime(df.index, unit="s")
@@ -392,33 +408,36 @@ def get_hashrate(asset: str, interval: str, since: int, until: int) -> pd.DataFr
console.print(f"Error getting hashrate: {r.text}")
if r2.status_code != 200:
console.print(f"Error getting {asset} price: {r2.text}")
console.print(f"Error getting {symbol} price: {r2.text}")
return df
@log_start_end(log=logger)
def get_exchange_balances(
asset: str, exchange: str, since: int, until: int
symbol: str,
exchange: str = "binance",
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Returns the total amount of coins held on exchange addresses in units and percentage.
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Asset to search active addresses (e.g., BTC)
exchange : str
Exchange to check net position change (e.g., binance)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
Returns
-------
pd.DataFrame
total amount of coins in units/percentage and asset price over time
total amount of coins in units/percentage and symbol price over time
"""
url = api_url + "distribution/balance_exchanges"
@@ -427,11 +446,11 @@ def get_exchange_balances(
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": "24h",
"e": exchange,
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
df = pd.DataFrame()
@@ -454,41 +473,44 @@ def get_exchange_balances(
df.rename(columns={"v": "stacked"}, inplace=True)
if df.empty or df2.empty or df3.empty:
console.print(f"No data found for {asset}'s exchange balance or price.\n")
console.print(f"No data found for {symbol}'s exchange balance or price.\n")
elif r.status_code == 401 or r2.status_code == 401 or r3.status_code == 401:
console.print("[red]Invalid API Key[/red]\n")
else:
if r.status_code != 200:
console.print(f"Error getting {asset}'s exchange balance: {r.text}")
console.print(f"Error getting {symbol}'s exchange balance: {r.text}")
if r2.status_code != 200:
console.print(
f"Error getting {asset}'s exchange balance relatives: {r2.text}"
f"Error getting {symbol}'s exchange balance relatives: {r2.text}"
)
if r3.status_code != 200:
console.print(f"Error getting {asset} price: {r3.text}")
console.print(f"Error getting {symbol} price: {r3.text}")
return df
@log_start_end(log=logger)
def get_exchange_net_position_change(
asset: str, exchange: str, since: int, until: int
symbol: str,
exchange: str = "binance",
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Returns 30d change of the supply held in exchange wallets of a certain asset.
"""Returns 30d change of the supply held in exchange wallets of a certain symbol.
[Source: https://glassnode.com]
Parameters
----------
asset : str
symbol : str
Asset symbol to search supply (e.g., BTC)
exchange : str
Exchange to check net position change (e.g., binance)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
Returns
@@ -501,11 +523,11 @@ def get_exchange_net_position_change(
parameters = {
"api_key": cfg.API_GLASSNODE_KEY,
"a": asset,
"a": symbol,
"i": "24h",
"e": exchange,
"s": str(since),
"u": str(until),
"s": str(start_date),
"u": str(end_date),
}
r = requests.get(url, params=parameters)
@@ -515,7 +537,7 @@ def get_exchange_net_position_change(
df = pd.DataFrame(json.loads(r.text))
if df.empty:
console.print(f"No data found for {asset}'s net position change.\n")
console.print(f"No data found for {symbol}'s net position change.\n")
else:
df["t"] = pd.to_datetime(df["t"], unit="s")
df = df.set_index("t")

View File

@@ -35,8 +35,8 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_btc_rainbow(
since: int = int(datetime(2010, 1, 1).timestamp()),
until: int = int(datetime.now().timestamp()),
start_date: int = int(datetime(2010, 1, 1).timestamp()),
end_date: int = int(datetime.now().timestamp()),
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
@@ -46,16 +46,16 @@ def display_btc_rainbow(
Parameters
----------
since : int
start_date : int
Initial date timestamp. Default is initial BTC timestamp: 1_325_376_000
until : int
end_date : int
Final date timestamp. Default is current BTC timestamp
export : str
Export dataframe data to csv,json,xlsx file
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df_data = get_close_price("BTC", since, until)
df_data = get_close_price("BTC", start_date, end_date)
if df_data.empty:
return
@@ -69,7 +69,7 @@ def display_btc_rainbow(
return
d0 = datetime.strptime("2012-01-01", "%Y-%m-%d")
dend = datetime.fromtimestamp(until)
dend = datetime.fromtimestamp(end_date)
x = range((df_data.index[0] - d0).days, (dend - d0).days + 1)
@@ -155,23 +155,23 @@ def display_btc_rainbow(
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_active_addresses(
asset: str,
since: int = 1577836800,
until: int = 1609459200,
symbol: str,
start_date: int = 1577836800,
end_date: int = 1609459200,
interval: str = "24h",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
"""Display active addresses of a certain asset over time
"""Display active addresses of a certain symbol over time
[Source: https://glassnode.org]
Parameters
----------
asset : str
symbol : str
Asset to search active addresses (e.g., BTC)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
interval : str
Interval frequency (possible values are: 24h, 1w, 1month)
@@ -181,7 +181,7 @@ def display_active_addresses(
External axes (1 axis is expected in the list), by default None
"""
df_addresses = get_active_addresses(asset, interval, since, until)
df_addresses = get_active_addresses(symbol, interval, start_date, end_date)
if df_addresses.empty:
return
@@ -196,7 +196,7 @@ def display_active_addresses(
ax.plot(df_addresses.index, df_addresses["v"] / 1_000, linewidth=1.5)
ax.set_title(f"Active {asset} addresses over time")
ax.set_title(f"Active {symbol} addresses over time")
ax.set_ylabel("Addresses [thousands]")
ax.set_xlim(df_addresses.index[0], df_addresses.index[-1])
@@ -216,22 +216,22 @@ def display_active_addresses(
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_non_zero_addresses(
asset: str,
since: int = 1577836800,
until: int = 1609459200,
symbol: str,
start_date: int = 1577836800,
end_date: int = 1609459200,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
"""Display addresses with non-zero balance of a certain asset
"""Display addresses with non-zero balance of a certain symbol
[Source: https://glassnode.org]
Parameters
----------
asset : str
symbol : str
Asset to search (e.g., BTC)
since : int
start_date : int
Initial date timestamp (e.g., 1_577_836_800)
until : int
end_date : int
End date timestamp (e.g., 1_609_459_200)
export : str
Export dataframe data to csv,json,xlsx file
@@ -239,7 +239,7 @@ def display_non_zero_addresses(
External axes (1 axis is expected in the list), by default None
"""
df_addresses = get_non_zero_addresses(asset, since, until)
df_addresses = get_non_zero_addresses(symbol, start_date, end_date)
if df_addresses.empty:
return
@@ -254,7 +254,7 @@ def display_non_zero_addresses(
ax.plot(df_addresses.index, df_addresses["v"] / 1_000, linewidth=1.5)
ax.set_title(f"{asset} Addresses with non-zero balances")
ax.set_title(f"{symbol} Addresses with non-zero balances")
ax.set_ylabel("Number of Addresses")
ax.set_xlim(df_addresses.index[0], df_addresses.index[-1])
@@ -274,10 +274,10 @@ def display_non_zero_addresses(
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_exchange_net_position_change(
asset: str,
symbol: str,
exchange: str = "binance",
since: int = 1577836800,
until: int = 1609459200,
start_date: int = 1577836800,
end_date: int = 1609459200,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -286,15 +286,15 @@ def display_exchange_net_position_change(
Parameters
----------
asset : str
symbol : str
Asset to search active addresses (e.g., BTC)
exchange : str
Exchange to check net position change (possible values are: aggregated, binance,
bittrex, coinex, gate.io, gemini, huobi, kucoin, poloniex, bibox, bigone, bitfinex,
hitbtc, kraken, okex, bithumb, zb.com, cobinhood, bitmex, bitstamp, coinbase, coincheck, luno)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
export : str
Export dataframe data to csv,json,xlsx file
@@ -302,7 +302,9 @@ def display_exchange_net_position_change(
External axes (1 axis is expected in the list), by default None
"""
df_addresses = get_exchange_net_position_change(asset, exchange, since, until)
df_addresses = get_exchange_net_position_change(
symbol, exchange, start_date, end_date
)
if df_addresses.empty:
return
@@ -328,9 +330,9 @@ def display_exchange_net_position_change(
facecolor=theme.up_color,
)
ax.set_ylabel(f"30d change of {asset} supply held in exchange wallets [thousands]")
ax.set_ylabel(f"30d change of {symbol} supply held in exchange wallets [thousands]")
ax.set_title(
f"{asset}: Exchange Net Position Change - {'all exchanges' if exchange == 'aggregated' else exchange}"
f"{symbol}: Exchange Net Position Change - {'all exchanges' if exchange == 'aggregated' else exchange}"
)
ax.set_xlim(df_addresses.index[0], df_addresses.index[-1])
@@ -350,10 +352,10 @@ def display_exchange_net_position_change(
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_exchange_balances(
asset: str,
symbol: str,
exchange: str = "binance",
since: int = 1577836800,
until: int = 1609459200,
start_date: int = 1577836800,
end_date: int = 1609459200,
percentage: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -363,15 +365,15 @@ def display_exchange_balances(
Parameters
----------
asset : str
symbol : str
Asset to search active addresses (e.g., BTC)
exchange : str
Exchange to check net position change (possible values are: aggregated, binance, bittrex,
coinex, gate.io, gemini, huobi, kucoin, poloniex, bibox, bigone, bitfinex, hitbtc, kraken,
okex, bithumb, zb.com, cobinhood, bitmex, bitstamp, coinbase, coincheck, luno)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
percentage : bool
Show percentage instead of stacked value.
@@ -381,7 +383,7 @@ def display_exchange_balances(
External axes (2 axes are expected in the list), by default None
"""
df_balance = get_exchange_balances(asset, exchange, since, until)
df_balance = get_exchange_balances(symbol, exchange, start_date, end_date)
if df_balance.empty:
return
@@ -401,17 +403,17 @@ def display_exchange_balances(
else:
ax1.plot(df_balance.index, df_balance["stacked"] / 1000)
ax1.set_ylabel(f"{asset} units [{'%' if percentage else 'thousands'}]")
ax1.set_ylabel(f"{symbol} units [{'%' if percentage else 'thousands'}]")
ax1.set_title(
f"{asset}: Total Balance in {'all exchanges' if exchange == 'aggregated' else exchange}"
f"{symbol}: Total Balance in {'all exchanges' if exchange == 'aggregated' else exchange}"
)
ax1.tick_params(axis="x", labelrotation=10)
ax1.legend([f"{asset} Unit"], loc="upper right")
ax1.legend([f"{symbol} Unit"], loc="upper right")
ax2.grid(visible=False)
ax2.plot(df_balance.index, df_balance["price"], color="orange")
ax2.set_ylabel(f"{asset} price [$]")
ax2.legend([f"{asset} Price"], loc="upper left")
ax2.set_ylabel(f"{symbol} price [$]")
ax2.legend([f"{symbol} Price"], loc="upper left")
if not external_axes:
theme.visualize_output()
@@ -427,23 +429,23 @@ def display_exchange_balances(
@log_start_end(log=logger)
@check_api_key(["API_GLASSNODE_KEY"])
def display_hashrate(
asset: str,
since: int = int((datetime.now() - timedelta(days=365)).timestamp()),
until: int = int(datetime.now().timestamp()),
symbol: str,
start_date: int = int((datetime.now() - timedelta(days=365)).timestamp()),
end_date: int = int(datetime.now().timestamp()),
interval: str = "24h",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
"""Display dataframe with mean hashrate of btc or eth blockchain and asset price.
"""Display dataframe with mean hashrate of btc or eth blockchain and symbol price.
[Source: https://glassnode.org]
Parameters
----------
asset : str
symbol : str
Blockchain to check mean hashrate (BTC or ETH)
since : int
start_date : int
Initial date timestamp (e.g., 1_614_556_800)
until : int
end_date : int
End date timestamp (e.g., 1_614_556_800)
interval : str
Interval frequency (possible values are: 24, 1w, 1month)
@@ -453,7 +455,7 @@ def display_hashrate(
External axes (2 axes are expected in the list), by default None
"""
df = get_hashrate(asset, interval, since, until)
df = get_hashrate(symbol, interval, start_date, end_date)
if df.empty:
return
@@ -472,15 +474,15 @@ def display_hashrate(
df.index, df["hashrate"] / 1_000_000_000_000, color=theme.down_color, lw=0.8
)
ax1.yaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.0f}T"))
ax1.set_ylabel(f"{asset} hashrate (Terahashes/second)")
ax1.set_title(f"{asset}: Mean hashrate")
ax1.set_ylabel(f"{symbol} hashrate (Terahashes/second)")
ax1.set_title(f"{symbol}: Mean hashrate")
ax1.tick_params(axis="x", labelrotation=10)
ax2.set_xlim(left=df.index[0])
ax2.grid(visible=False)
ax2.plot(df.index, df["price"] / 1_000, color=theme.up_color, lw=0.8)
ax2.yaxis.set_major_formatter(ticker.StrMethodFormatter("${x:.1f}k"))
ax2.set_ylabel(f"{asset} price [$]")
ax2.set_ylabel(f"{symbol} price [$]")
# Manually construct the chart legend
lines = [

View File

@@ -5,6 +5,7 @@ __docformat__ = "numpy"
import logging
from typing import Any, Tuple
from datetime import datetime, timedelta
import re
import pandas as pd
import requests
@@ -27,10 +28,15 @@ INTERVALS_TIMESERIES = ["5m", "15m", "30m", "1h", "1d", "1w"]
@log_start_end(log=logger)
def get_available_timeseries() -> pd.DataFrame:
def get_available_timeseries(only_free: bool = True) -> pd.DataFrame:
"""Returns available messari timeseries
[Source: https://messari.io/]
Parameters
----------
only_free : bool
Display only timeseries available for free
Returns
-------
pd.DataFrame
@@ -58,6 +64,8 @@ def get_available_timeseries() -> pd.DataFrame:
)
df = pd.DataFrame(arr)
df.set_index("id", inplace=True)
if only_free:
df = df.drop(df[df["Requires Paid Key"]].index)
return df
return pd.DataFrame()
@@ -68,21 +76,24 @@ base_url2 = "https://data.messari.io/api/v2/"
@log_start_end(log=logger)
def get_marketcap_dominance(
coin: str, interval: str, start: str, end: str
symbol: str,
interval: str = "1d",
start_date: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end_date: str = datetime.now().strftime("%Y-%m-%d"),
) -> pd.DataFrame:
"""Returns market dominance of a coin over time
[Source: https://messari.io/]
Parameters
----------
coin : str
symbol : str
Crypto symbol to check market cap dominance
start : int
Initial date like string (e.g., 2021-10-01)
end : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (e.g., 1d)
Interval frequency (possible values are: 5m, 15m, 30m, 1h, 1d, 1w)
start_date : int
Initial date like string (e.g., 2021-10-01)
end_date : int
End date like string (e.g., 2021-10-01)
Returns
-------
@@ -91,30 +102,38 @@ def get_marketcap_dominance(
"""
df, _ = get_messari_timeseries(
coin=coin, end=end, start=start, interval=interval, timeseries_id="mcap.dom"
symbol=symbol,
end_date=end_date,
start_date=start_date,
interval=interval,
timeseries_id="mcap.dom",
)
return df
@log_start_end(log=logger)
def get_messari_timeseries(
coin: str, timeseries_id: str, interval: str, start: str, end: str
symbol: str,
timeseries_id: str,
interval: str = "1d",
start_date: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end_date: str = datetime.now().strftime("%Y-%m-%d"),
) -> Tuple[pd.DataFrame, str]:
"""Returns messari timeseries
[Source: https://messari.io/]
Parameters
----------
coin : str
symbol : str
Crypto symbol to check messari timeseries
timeseries_id : str
Messari timeserie id
interval : str
Interval frequency (possible values are: 5m, 15m, 30m, 1h, 1d, 1w)
start : int
Initial date like string (e.g., 2021-10-01)
end : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (e.g., 1d)
Returns
-------
@@ -124,13 +143,13 @@ def get_messari_timeseries(
timeserie title
"""
url = base_url + f"assets/{coin}/metrics/{timeseries_id}/time-series"
url = base_url + f"assets/{symbol}/metrics/{timeseries_id}/time-series"
headers = {"x-messari-api-key": cfg.API_MESSARI_KEY}
parameters = {
"start": start,
"end": end,
"start": start_date,
"end": end_date,
"interval": interval,
}
@@ -145,7 +164,7 @@ def get_messari_timeseries(
df = pd.DataFrame(data["values"], columns=data["parameters"]["columns"])
if df.empty:
console.print(f"No data found for {coin}.\n")
console.print(f"No data found for {symbol}.\n")
else:
df = df.set_index("timestamp")
df.index = pd.to_datetime(df.index, unit="ms")
@@ -198,7 +217,7 @@ def get_links(symbol: str) -> pd.DataFrame:
@log_start_end(log=logger)
def get_roadmap(symbol: str) -> pd.DataFrame:
def get_roadmap(symbol: str, ascend: bool = True) -> pd.DataFrame:
"""Returns coin roadmap
[Source: https://messari.io/]
@@ -206,6 +225,8 @@ def get_roadmap(symbol: str) -> pd.DataFrame:
----------
symbol : str
Crypto symbol to check roadmap
ascend: bool
reverse order
Returns
-------
@@ -229,6 +250,10 @@ def get_roadmap(symbol: str) -> pd.DataFrame:
df["date"] = pd.to_datetime(df["date"])
df.columns = map(str.capitalize, df.columns)
df = df.dropna(axis=1, how="all")
df["Date"] = df["Date"].dt.date
show_df = df
show_df = show_df.sort_values(by="Date", ascending=ascend)
show_df.fillna("Unknown", inplace=True)
elif r.status_code == 401:
console.print("[red]Invalid API Key[/red]\n")
else:
@@ -292,7 +317,7 @@ def get_tokenomics(symbol: str, coingecko_id: str) -> Tuple[pd.DataFrame, pd.Dat
df = pd.concat([df, cg_df], ignore_index=True, sort=False)
df.fillna("-", inplace=True)
circ_df, _ = get_messari_timeseries(
coin=symbol,
symbol=symbol,
timeseries_id="sply.circ",
interval="1d",
start="",

View File

@@ -68,10 +68,8 @@ def display_messari_timeseries_list(
Export dataframe data to csv,json,xlsx file
"""
df = get_available_timeseries()
df = get_available_timeseries(only_free)
if not df.empty:
if only_free:
df = df.drop(df[df["Requires Paid Key"]].index)
if query:
mask = np.column_stack(
[
@@ -104,10 +102,10 @@ def display_messari_timeseries_list(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_messari_timeseries(
coin: str,
symbol: str,
timeseries_id: str,
start: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end: str = datetime.now().strftime("%Y-%m-%d"),
start_date: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end_date: str = datetime.now().strftime("%Y-%m-%d"),
interval: str = "1d",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -117,13 +115,13 @@ def display_messari_timeseries(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check market cap dominance
timeseries_id: str
Obtained by api.crypto.dd.get_mt command
start : int
start_date : int
Initial date like string (e.g., 2021-10-01)
end : int
end_date : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (possible values are: 5m, 15m, 30m, 1h, 1d, 1w)
@@ -134,7 +132,11 @@ def display_messari_timeseries(
"""
df, title = get_messari_timeseries(
coin=coin, timeseries_id=timeseries_id, start=start, end=end, interval=interval
symbol=symbol,
timeseries_id=timeseries_id,
start_date=start_date,
end_date=end_date,
interval=interval,
)
if not df.empty:
@@ -152,7 +154,7 @@ def display_messari_timeseries(
ax.plot(df.index, df[df.columns[0]])
ax.set_title(f"{coin}'s {title}")
ax.set_title(f"{symbol}'s {title}")
ax.set_ylabel(title)
ax.set_xlim(df.index[0], df.index[-1])
@@ -172,9 +174,9 @@ def display_messari_timeseries(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_marketcap_dominance(
coin: str,
start: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end: str = datetime.now().strftime("%Y-%m-%d"),
symbol: str,
start_date: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d"),
end_date: str = datetime.now().strftime("%Y-%m-%d"),
interval: str = "1d",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -184,11 +186,11 @@ def display_marketcap_dominance(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check market cap dominance
start : int
start_date : int
Initial date like string (e.g., 2021-10-01)
end : int
end_date : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (possible values are: 5m, 15m, 30m, 1h, 1d, 1w)
@@ -198,7 +200,9 @@ def display_marketcap_dominance(
External axes (1 axis is expected in the list), by default None
"""
df = get_marketcap_dominance(coin=coin, start=start, end=end, interval=interval)
df = get_marketcap_dominance(
symbol=symbol, start_date=start_date, end_date=end_date, interval=interval
)
if not df.empty:
@@ -212,8 +216,8 @@ def display_marketcap_dominance(
ax.plot(df.index, df["marketcap_dominance"])
ax.set_title(f"{coin}'s Market Cap Dominance over time")
ax.set_ylabel(f"{coin} Percentage share")
ax.set_title(f"{symbol}'s Market Cap Dominance over time")
ax.set_ylabel(f"{symbol} Percentage share")
ax.set_xlim(df.index[0], df.index[-1])
theme.style_primary_axis(ax)
@@ -231,13 +235,13 @@ def display_marketcap_dominance(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_links(coin: str, export: str = "") -> None:
def display_links(symbol: str, export: str = "") -> None:
"""Display coin links
[Source: https://messari.io/]
Parameters
----------
coin : str
symbol : str
Crypto symbol to check links
export : str
Export dataframe data to csv,json,xlsx file
@@ -245,13 +249,13 @@ def display_links(coin: str, export: str = "") -> None:
External axes (1 axis is expected in the list), by default None
"""
df = get_links(coin)
df = get_links(symbol)
if not df.empty:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title=f"{coin} Links",
title=f"{symbol} Links",
)
export_data(
@@ -267,8 +271,8 @@ def display_links(coin: str, export: str = "") -> None:
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_roadmap(
coin: str,
descend: bool = False,
symbol: str,
ascend: bool = True,
limit: int = 5,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -278,9 +282,9 @@ def display_roadmap(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check roadmap
descend: bool
ascend: bool
reverse order
limit : int
number to show
@@ -289,21 +293,17 @@ def display_roadmap(
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
df = get_roadmap(coin)
df = get_roadmap(symbol, ascend)
if not df.empty:
df["Date"] = df["Date"].dt.date
show_df = df
show_df = show_df.sort_values(by="Date", ascending=descend)
show_df.fillna("Unknown", inplace=True)
print_rich_table(
show_df.head(limit),
headers=list(show_df.columns),
df.head(limit),
headers=list(df.columns),
show_index=False,
title=f"{coin} Roadmap",
title=f"{symbol} Roadmap",
)
df_prices, _ = cryptocurrency_helpers.load_yf_data(
symbol=coin,
symbol=symbol,
currency="USD",
days=4380,
interval="1d",
@@ -352,7 +352,7 @@ def display_roadmap(
ax.get_yaxis().set_major_formatter(
ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x))
)
ax.set_title(f"{coin.upper()} Price and Roadmap")
ax.set_title(f"{symbol.upper()} Price and Roadmap")
ax.set_ylabel("Price [$]")
ax.set_xlim(df_prices.index[0], df_prices.index[-1])
theme.style_primary_axis(ax)
@@ -373,7 +373,7 @@ def display_roadmap(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_tokenomics(
coin: str,
symbol: str,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -382,15 +382,15 @@ def display_tokenomics(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check tokenomics
export : str
Export dataframe data to csv,json,xlsx file
external_axes : Optional[List[plt.Axes]], optional
External axes (2 axes are expected in the list), by default None
"""
coingecko_id = cryptocurrency_helpers.get_coingecko_id(coin)
df, circ_df = get_tokenomics(coin, coingecko_id)
coingecko_id = cryptocurrency_helpers.get_coingecko_id(symbol)
df, circ_df = get_tokenomics(symbol, coingecko_id)
if not df.empty and not circ_df.empty:
df = df.applymap(lambda x: lambda_long_number_format(x, 2))
@@ -398,7 +398,7 @@ def display_tokenomics(
df,
headers=list(df.columns),
show_index=False,
title=f"{coin} Tokenomics",
title=f"{symbol} Tokenomics",
)
if not external_axes:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=cfgPlot.PLOT_DPI)
@@ -408,7 +408,7 @@ def display_tokenomics(
else:
return
df_prices, _ = cryptocurrency_helpers.load_yf_data(
symbol=coin,
symbol=symbol,
currency="USD",
days=4380,
interval="1d",
@@ -428,14 +428,14 @@ def display_tokenomics(
ax2.get_yaxis().set_major_formatter(
ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x))
)
ax2.set_ylabel(f"{coin} price [$]")
ax2.set_ylabel(f"{symbol} price [$]")
theme.style_twin_axis(ax2)
ax2.yaxis.set_label_position("right")
ax.legend()
ax.get_yaxis().set_major_formatter(
ticker.FuncFormatter(lambda x, _: lambda_long_number_format(x))
)
ax.set_title(f"{coin} circulating supply over time")
ax.set_title(f"{symbol} circulating supply over time")
ax.set_ylabel("Number of tokens")
ax.set_xlim(merged_df.index[0], merged_df.index[-1])
theme.style_primary_axis(ax)
@@ -457,7 +457,7 @@ def display_tokenomics(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_project_info(
coin: str,
symbol: str,
export: str = "",
) -> None:
"""Display project info
@@ -465,49 +465,26 @@ def display_project_info(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check project info
export : str
Export dataframe data to csv,json,xlsx file
"""
(df_info, df_repos, df_audits, df_vulns) = get_project_product_info(coin)
(df_info, df_repos, df_audits, df_vulns) = get_project_product_info(symbol)
if not df_info.empty:
print_rich_table(
df_info,
headers=list(df_info.columns),
show_index=False,
title=f"{coin} General Info",
)
else:
console.print("\nGeneral info not found\n")
if not df_repos.empty:
print_rich_table(
df_repos,
headers=list(df_repos.columns),
show_index=False,
title=f"{coin} Public Repositories",
)
else:
console.print("\nPublic repositories not found\n")
if not df_audits.empty:
print_rich_table(
df_audits,
headers=list(df_audits.columns),
show_index=False,
title=f"{coin} Audits",
)
else:
console.print("\nAudits not found\n")
if not df_vulns.empty:
print_rich_table(
df_vulns,
headers=list(df_vulns.columns),
show_index=False,
title=f"{coin} Vulnerabilities",
)
else:
console.print("\nVulnerabilities not found\n")
for df, title in zip(
[df_info, df_repos, df_audits, df_vulns],
["General Info", "Public Repos", "Audits", "Vulnerabilities"],
):
if not df.empty:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title=f"{symbol} {title}",
)
else:
console.print(f"\n{title} not found\n")
export_data(
export,
@@ -520,7 +497,7 @@ def display_project_info(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_investors(
coin: str,
symbol: str,
export: str = "",
) -> None:
"""Display coin investors
@@ -528,19 +505,19 @@ def display_investors(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check coin investors
export : str
Export dataframe data to csv,json,xlsx file
"""
(df_individuals, df_organizations) = get_investors(coin)
(df_individuals, df_organizations) = get_investors(symbol)
if not df_individuals.empty or not df_organizations.empty:
if not df_individuals.empty:
print_rich_table(
df_individuals,
headers=list(df_individuals.columns),
show_index=False,
title=f"{coin} Investors - Individuals",
title=f"{symbol} Investors - Individuals",
)
else:
console.print("\nIndividual investors not found\n")
@@ -549,7 +526,7 @@ def display_investors(
df_organizations,
headers=list(df_organizations.columns),
show_index=False,
title=f"{coin} Investors - Organizations",
title=f"{symbol} Investors - Organizations",
)
else:
console.print("\nInvestors - Organizations not found\n")
@@ -566,7 +543,7 @@ def display_investors(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_team(
coin: str,
symbol: str,
export: str = "",
) -> None:
"""Display coin team
@@ -574,19 +551,19 @@ def display_team(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check coin team
export : str
Export dataframe data to csv,json,xlsx file
"""
(df_individuals, df_organizations) = get_team(coin)
(df_individuals, df_organizations) = get_team(symbol)
if not df_individuals.empty or not df_organizations.empty:
if not df_individuals.empty:
print_rich_table(
df_individuals,
headers=list(df_individuals.columns),
show_index=False,
title=f"{coin} Team - Individuals",
title=f"{symbol} Team - Individuals",
)
else:
console.print("\nIndividual team members not found\n")
@@ -595,7 +572,7 @@ def display_team(
df_organizations,
headers=list(df_organizations.columns),
show_index=False,
title=f"{coin} Team - Organizations",
title=f"{symbol} Team - Organizations",
)
else:
console.print("\nTeam organizations not found\n")
@@ -612,7 +589,7 @@ def display_team(
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_governance(
coin: str,
symbol: str,
export: str = "",
) -> None:
"""Display coin governance
@@ -620,12 +597,12 @@ def display_governance(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check coin governance
export : str
Export dataframe data to csv,json,xlsx file
"""
(summary, df) = get_governance(coin)
(summary, df) = get_governance(symbol)
if summary:
summary = prettify_paragraph(summary)
console.print(summary, "\n")
@@ -634,7 +611,7 @@ def display_governance(
df,
headers=list(df.columns),
show_index=False,
title=f"{coin} Governance details",
title=f"{symbol} Governance details",
)
export_data(
export,
@@ -643,13 +620,13 @@ def display_governance(
df,
)
else:
console.print(f"\n{coin} governance details not found\n")
console.print(f"\n{symbol} governance details not found\n")
@log_start_end(log=logger)
@check_api_key(["API_MESSARI_KEY"])
def display_fundraising(
coin: str,
symbol: str,
export: str = "",
) -> None:
"""Display coin fundraising
@@ -657,12 +634,12 @@ def display_fundraising(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check coin fundraising
export : str
Export dataframe data to csv,json,xlsx file
"""
(summary, df_sales_rounds, df_treasury_accs, df_details) = get_fundraising(coin)
(summary, df_sales_rounds, df_treasury_accs, df_details) = get_fundraising(symbol)
if summary:
summary = prettify_paragraph(summary)
console.print(summary, "\n")
@@ -674,7 +651,7 @@ def display_fundraising(
df_sales_rounds,
headers=list(df_sales_rounds.columns),
show_index=False,
title=f"{coin} Sales Rounds",
title=f"{symbol} Sales Rounds",
)
else:
console.print("\nSales rounds not found\n")
@@ -683,7 +660,7 @@ def display_fundraising(
df_treasury_accs,
headers=list(df_treasury_accs.columns),
show_index=False,
title=f"{coin} Treasury Accounts",
title=f"{symbol} Treasury Accounts",
)
else:
console.print("\nTreasury accounts not found\n")
@@ -723,7 +700,7 @@ def display_fundraising(
startangle=90,
colors=theme.get_colors()[1:4],
)
ax.set_title(f"{coin} Fundraising Distribution")
ax.set_title(f"{symbol} Fundraising Distribution")
if obbff.USE_ION:
plt.ion()
plt.show()
@@ -734,7 +711,7 @@ def display_fundraising(
df_details,
headers=list(df_details.columns),
show_index=False,
title=f"{coin} Fundraising Details",
title=f"{symbol} Fundraising Details",
)
else:
console.print("\nFundraising details not found\n")

View File

@@ -48,11 +48,22 @@ BASE_INFO = [
]
def format_df(df: pd.DataFrame):
df["Potential Market Cap ($)"] = df.apply(
lambda x: f"{int(x['Potential Market Cap ($)']):n}", axis=1
)
df["Current Market Cap ($)"] = df.apply(
lambda x: f"{int(x['Current Market Cap ($)']):n}", axis=1
)
return df
@log_start_end(log=logger)
def get_coin_potential_returns(
main_coin: str,
vs: Union[str, None] = None,
top: Union[int, None] = None,
limit: Union[int, None] = None,
price: Union[int, None] = None,
) -> pd.DataFrame:
"""Fetch data to calculate potential returns of a certain coin. [Source: CoinGecko]
@@ -63,7 +74,7 @@ def get_coin_potential_returns(
Coin loaded to check potential returns for (e.g., algorand)
vs : str | None
Coin to compare main_coin with (e.g., bitcoin)
top : int | None
limit : int | None
Number of coins with highest market cap to compare main_coin with (e.g., 5)
price
Target price of main_coin to check potential returns (e.g., 5)
@@ -84,7 +95,7 @@ def get_coin_potential_returns(
"Potential Market Cap ($)",
"Change (%)",
]
if top and top > 0: # user wants to compare with top coins
if limit and limit > 0: # user wants to compare with top coins
data = client.get_price(
ids=f"{main_coin}",
vs_currencies="usd",
@@ -94,7 +105,7 @@ def get_coin_potential_returns(
include_last_updated_at=False,
)
top_coins_data = client.get_coins_markets(
vs_currency="usd", per_page=top, order="market_cap_desc"
vs_currency="usd", per_page=limit, order="market_cap_desc"
)
main_coin_data = data[main_coin]
diff_arr = []
@@ -116,10 +127,11 @@ def get_coin_potential_returns(
market_cap_difference_percentage,
]
)
return pd.DataFrame(
df = pd.DataFrame(
data=diff_arr,
columns=COLUMNS,
)
return format_df(df)
if vs: # user passed a coin
data = client.get_price(
@@ -140,7 +152,7 @@ def get_coin_potential_returns(
future_price = main_coin_data["usd"] * (
1 + market_cap_difference_percentage / 100
)
return pd.DataFrame(
df = pd.DataFrame(
data=[
[
main_coin,
@@ -154,6 +166,7 @@ def get_coin_potential_returns(
],
columns=COLUMNS,
)
return format_df(df)
if price and price > 0: # user passed a price
data = client.get_price(
@@ -175,7 +188,7 @@ def get_coin_potential_returns(
future_price = main_coin_data["usd"] * (
1 + market_cap_difference_percentage / 100
)
return pd.DataFrame(
df = pd.DataFrame(
data=[
[
main_coin,
@@ -189,24 +202,25 @@ def get_coin_potential_returns(
],
columns=COLUMNS,
)
return format_df(df)
return pd.DataFrame()
@log_start_end(log=logger)
def check_coin(coin_id: str):
def check_coin(symbol: str):
coins = read_file_data("coingecko_coins.json")
for coin in coins:
if coin["id"] == coin_id:
if coin["id"] == symbol:
return coin["id"]
if coin["symbol"] == coin_id:
if coin["symbol"] == symbol:
return coin["id"]
return None
@log_start_end(log=logger)
def get_coin_market_chart(
coin_id: str = "", vs_currency: str = "usd", days: int = 30, **kwargs: Any
symbol: str = "", vs_currency: str = "usd", days: int = 30, **kwargs: Any
) -> pd.DataFrame:
"""Get prices for given coin. [Source: CoinGecko]
@@ -225,7 +239,7 @@ def get_coin_market_chart(
Columns: time, price, currency
"""
client = CoinGeckoAPI()
prices = client.get_coin_market_chart_by_id(coin_id, vs_currency, days, **kwargs)
prices = client.get_coin_market_chart_by_id(symbol, vs_currency, days, **kwargs)
prices = prices["prices"]
df = pd.DataFrame(data=prices, columns=["time", "price"])
df["time"] = pd.to_datetime(df.time, unit="ms")

View File

@@ -3,7 +3,7 @@ __docformat__ = "numpy"
import logging
import os
from typing import Union
from typing import Optional
from pandas.plotting import register_matplotlib_converters
import openbb_terminal.cryptocurrency.due_diligence.pycoingecko_model as gecko
from openbb_terminal.cryptocurrency import cryptocurrency_helpers
@@ -18,36 +18,28 @@ register_matplotlib_converters()
@log_start_end(log=logger)
def display_coin_potential_returns(
main_coin: str,
vs: Union[str, None] = None,
top: Union[int, None] = None,
price: Union[int, None] = None,
to_symbol: str,
from_symbol: Optional[str] = None,
limit: Optional[int] = None,
price: Optional[int] = None,
export: str = "",
) -> None:
"""Displays potential returns of a certain coin. [Source: CoinGecko]
Parameters
----------
main_coin : str
to_symbol : str
Coin loaded to check potential returns for (e.g., algorand)
vs : str | None
from_symbol : str | None
Coin to compare main_coin with (e.g., bitcoin)
top : int | None
limit : int | None
Number of coins with highest market cap to compare main_coin with (e.g., 5)
price
Target price of main_coin to check potential returns (e.g., 5)
export : str
Export dataframe data to csv,json,xlsx file
"""
df = gecko.get_coin_potential_returns(main_coin, vs, top, price)
df["Potential Market Cap ($)"] = df.apply(
lambda x: f"{int(x['Potential Market Cap ($)']):n}", axis=1
)
df["Current Market Cap ($)"] = df.apply(
lambda x: f"{int(x['Current Market Cap ($)']):n}", axis=1
)
df = gecko.get_coin_potential_returns(to_symbol, from_symbol, limit, price)
print_rich_table(
df, headers=list(df.columns), show_index=False, title="Potential Coin Returns"

View File

@@ -12,24 +12,24 @@ from openbb_terminal.cryptocurrency.discovery.pycoingecko_model import read_file
logger = logging.getLogger(__name__)
def get_slug(coin: str) -> str:
def get_slug(symbol: str) -> str:
"""
Get Santiment slug mapping and return corresponding slug for a given coin
"""
df = pd.DataFrame(read_file_data("santiment_slugs.json"))
slug = df.loc[df["ticker"] == coin.upper()]["slug"].values[0]
slug = df.loc[df["ticker"] == symbol.upper()]["slug"].values[0]
return slug
@log_start_end(log=logger)
def get_github_activity(
coin: str,
symbol: str,
dev_activity: bool,
interval: str,
start: str,
end: str,
start_date: str,
end_date: str,
) -> pd.DataFrame:
"""Returns a list of developer activity for a given coin and time interval.
@@ -37,13 +37,13 @@ def get_github_activity(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check github activity
dev_activity: bool
Whether to filter only for development activity
start : int
start_date : int
Initial date like string (e.g., 2021-10-01)
end : int
end_date : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (e.g., 1d)
@@ -56,15 +56,17 @@ def get_github_activity(
activity_type = "dev_activity" if dev_activity else "github_activity"
slug = get_slug(coin)
slug = get_slug(symbol)
headers = {
"Content-Type": "application/graphql",
"Authorization": f"Apikey {cfg.API_SANTIMENT_KEY}",
}
# pylint: disable=line-too-long
data = f'\n{{ getMetric(metric: "{activity_type}"){{ timeseriesData( slug: "{slug}" from: "{start}" to: "{end}" interval: "{interval}"){{ datetime value }} }} }}' # noqa: E501
data = (
f'\n{{ getMetric(metric: "{activity_type}"){{ timeseriesData( slug: "{slug}"'
f'from: "{start_date}" to: "{end_date}" interval: "{interval}"){{ datetime value }} }} }}'
)
response = requests.post(
"https://api.santiment.net/graphql", headers=headers, data=data
@@ -79,7 +81,7 @@ def get_github_activity(
df["datetime"] = pd.to_datetime(df["datetime"])
df = df.set_index("datetime")
else:
console.print(f"Could not find github activity found for {coin}\n")
console.print(f"Could not find github activity found for {symbol}\n")
elif response.status_code == 400:
if "Apikey" in response.json()["errors"]["details"]:

View File

@@ -25,10 +25,12 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
@check_api_key(["API_SANTIMENT_KEY"])
def display_github_activity(
coin: str,
start: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%dT%H:%M:%SZ"),
symbol: str,
start_date: str = (datetime.now() - timedelta(days=365)).strftime(
"%Y-%m-%dT%H:%M:%SZ"
),
dev_activity: bool = False,
end: str = (datetime.now()).strftime("%Y-%m-%dT%H:%M:%SZ"),
end_date: str = (datetime.now()).strftime("%Y-%m-%dT%H:%M:%SZ"),
interval: str = "1d",
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
@@ -39,13 +41,13 @@ def display_github_activity(
Parameters
----------
coin : str
symbol : str
Crypto symbol to check github activity
dev_activity: bool
Whether to filter only for development activity
start : int
start_date : int
Initial date like string (e.g., 2021-10-01)
end : int
end_date : int
End date like string (e.g., 2021-10-01)
interval : str
Interval frequency (some possible values are: 1h, 1d, 1w)
@@ -56,7 +58,11 @@ def display_github_activity(
"""
df = get_github_activity(
coin=coin, dev_activity=dev_activity, start=start, end=end, interval=interval
symbol=symbol,
dev_activity=dev_activity,
start_date=start_date,
end_date=end_date,
interval=interval,
)
if df.empty:
@@ -72,8 +78,8 @@ def display_github_activity(
ax.plot(df.index, df["value"])
ax.set_title(f"{coin}'s Github activity over time")
ax.set_ylabel(f"{coin}'s Activity count")
ax.set_title(f"{symbol}'s Github activity over time")
ax.set_ylabel(f"{symbol}'s Activity count")
ax.set_xlim(df.index[0], df.index[-1])
theme.style_primary_axis(ax)

View File

@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_nft_today_drops(num: int, export: str):
def display_nft_today_drops(num: int = 5, export: str = ""):
"""Display NFT today drops. [Source: nftcalendar.io]
Parameters
@@ -43,7 +43,7 @@ def display_nft_today_drops(num: int, export: str):
@log_start_end(log=logger)
def display_nft_upcoming_drops(num: int, export: str):
def display_nft_upcoming_drops(num: int = 5, export: str = ""):
"""Display NFT upcoming drops. [Source: nftcalendar.io]
Parameters
@@ -73,7 +73,7 @@ def display_nft_upcoming_drops(num: int, export: str):
@log_start_end(log=logger)
def display_nft_ongoing_drops(num: int, export: str):
def display_nft_ongoing_drops(num: int = 5, export: str = ""):
"""Display NFT ongoing drops. [Source: nftcalendar.io]
Parameters
@@ -103,7 +103,7 @@ def display_nft_ongoing_drops(num: int, export: str):
@log_start_end(log=logger)
def display_nft_newest_drops(num: int, export: str):
def display_nft_newest_drops(num: int = 5, export: str = ""):
"""Display NFT newest drops. [Source: nftcalendar.io]
Parameters

View File

@@ -13,6 +13,9 @@ import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import HTTPError
from openbb_terminal.cryptocurrency.dataframe_helpers import (
prettify_column_names,
)
from openbb_terminal import config_terminal as cfg
from openbb_terminal.rich_config import console
from openbb_terminal.decorators import log_start_end
@@ -224,15 +227,16 @@ def get_erc20_tokens() -> pd.DataFrame:
@log_start_end(log=logger)
def find_token_address(token: str) -> Optional[str]:
def find_token_address(symbol: str) -> Optional[str]:
"""Helper methods that search for ERC20 coin base on provided symbol or token address.
If erc20 token address is provided, then function checks if it's proper address and returns it back.
In other case mapping data is loaded from file (or cache), and function lookup for belonging token address.
If erc20 token address is provided, then checks if it's proper address and returns it back.
In other case mapping data is loaded from file, and lookup for belonging token address.
Parameters
----------
token: str
ERC20 token symbol e.g. UNI, SUSHI, ETH, WBTC or token address e.g. 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
symbol: str
ERC20 token symbol e.g. UNI, SUSHI, ETH, WBTC or token address e.g.
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Returns
-------
@@ -240,13 +244,13 @@ def find_token_address(token: str) -> Optional[str]:
ERC20 token address, or None if nothing found.
"""
if token.startswith("0x") and len(token) >= 38:
return token
if symbol.startswith("0x") and len(symbol) >= 38:
return symbol
if token == "ETH":
return token
if symbol == "ETH":
return symbol
token = "WBTC" if token == "BTC" else token
token = "WBTC" if symbol == "BTC" else symbol
tokens_map: pd.DataFrame = get_erc20_tokens()
found_token = tokens_map.loc[tokens_map["symbol"] == token]
@@ -259,7 +263,10 @@ def find_token_address(token: str) -> Optional[str]:
@log_start_end(log=logger)
def get_dex_trades_by_exchange(
trade_amount_currency: str = "USD", limit: int = 90
trade_amount_currency: str = "USD",
limit: int = 90,
sortby: str = "tradeAmount",
ascend: bool = True,
) -> pd.DataFrame:
"""Get trades on Decentralized Exchanges aggregated by DEX [Source: https://graphql.bitquery.io/]
@@ -270,6 +277,10 @@ def get_dex_trades_by_exchange(
limit: int
Last n days to query data. Maximum 365 (bigger numbers can cause timeouts
on server side)
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -309,16 +320,20 @@ def get_dex_trades_by_exchange(
df = _extract_dex_trades(data)
df.columns = ["trades", "tradeAmount", "exchange"]
df = df[~df["exchange"].isin([None, np.NaN, ""])]
return df[["exchange", "trades", "tradeAmount"]].sort_values(
df = df[["exchange", "trades", "tradeAmount"]].sort_values(
by="tradeAmount", ascending=True
)
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_dex_trades_monthly(
trade_amount_currency: str = "USD", limit: int = 90
trade_amount_currency: str = "USD", limit: int = 90, ascend: bool = True
) -> pd.DataFrame:
"""Get list of trades on Decentralized Exchanges monthly aggregated. [Source: https://graphql.bitquery.io/]
"""Get list of trades on Decentralized Exchanges monthly aggregated.
[Source: https://graphql.bitquery.io/]
Parameters
----------
@@ -327,6 +342,8 @@ def get_dex_trades_monthly(
limit: int
Last n days to query data. Maximum 365 (bigger numbers can cause timeouts
on server side)
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -372,14 +389,19 @@ def get_dex_trades_monthly(
lambda x: datetime.date(int(x["date.year"]), int(x["date.month"]), 1), axis=1
)
df.rename(columns={"count": "trades"}, inplace=True)
return df[["date", "trades", "tradeAmount"]]
df = df[["date", "trades", "tradeAmount"]]
df = df.sort_values(by="date", ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_daily_dex_volume_for_given_pair(
limit: int = 100,
token: str = "UNI",
symbol: str = "UNI",
vs: str = "USDT",
sortby: str = "date",
ascend: bool = True,
) -> pd.DataFrame:
"""Get daily volume for given pair [Source: https://graphql.bitquery.io/]
@@ -387,10 +409,14 @@ def get_daily_dex_volume_for_given_pair(
-------
limit: int
Last n days to query data
token: str
symbol: str
ERC20 token symbol
vs: str
Quote currency.
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -402,7 +428,7 @@ def get_daily_dex_volume_for_given_pair(
"%Y-%m-%d"
)
base, quote = find_token_address(token), find_token_address(vs)
base, quote = find_token_address(symbol), find_token_address(vs)
if not base or not quote:
raise ValueError("Provided coin or quote currency doesn't exist\n")
@@ -463,7 +489,7 @@ def get_daily_dex_volume_for_given_pair(
"quote",
"exchange",
]
return df[
df = df[
[
"date",
"exchange",
@@ -476,22 +502,31 @@ def get_daily_dex_volume_for_given_pair(
"tradeAmount",
"trades",
]
].sort_values(by="date", ascending=False)
]
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_token_volume_on_dexes(
token: str = "UNI",
symbol: str = "UNI",
trade_amount_currency: str = "USD",
sortby: str = "tradeAmount",
ascend: bool = True,
) -> pd.DataFrame:
"""Get token volume on different Decentralized Exchanges. [Source: https://graphql.bitquery.io/]
Parameters
----------
token: str
symbol: str
ERC20 token symbol.
trade_amount_currency: str
Currency to display trade amount in.
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -502,9 +537,9 @@ def get_token_volume_on_dexes(
if trade_amount_currency not in CURRENCIES:
trade_amount_currency = "USD"
token_address = find_token_address(token)
token_address = find_token_address(symbol)
if token_address is None:
raise ValueError(f"Couldn't find token with symbol {token}\n")
raise ValueError(f"Couldn't find token with symbol {symbol}\n")
query = f"""
{{
ethereum {{
@@ -538,21 +573,32 @@ def get_token_volume_on_dexes(
df = _extract_dex_trades(data)[["exchange.fullName", "tradeAmount", "count"]]
df.columns = LT_FILTERS
return df[~df["exchange"].str.startswith("<")].sort_values(
by="tradeAmount", ascending=False
)
df = df[~df["exchange"].str.startswith("<")]
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_ethereum_unique_senders(interval: str = "day", limit: int = 90) -> pd.DataFrame:
def get_ethereum_unique_senders(
interval: str = "day",
limit: int = 90,
sortby: str = "tradeAmount",
ascend: bool = True,
) -> pd.DataFrame:
"""Get number of unique ethereum addresses which made a transaction in given time interval.
Parameters
----------
interval: str
Time interval in which count unique ethereum addresses which made transaction. day, month or week.
Time interval in which count unique ethereum addresses which made transaction. day,
month or week.
limit: int
Number of records for data query.
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -601,12 +647,19 @@ def get_ethereum_unique_senders(interval: str = "day", limit: int = 90) -> pd.Da
df = pd.DataFrame(data["ethereum"]["transactions"])
df["date"] = df["date"].apply(lambda x: x["date"])
return df[UEAT_FILTERS]
df = df[UEAT_FILTERS]
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_most_traded_pairs(
network: str = "ethereum", exchange: str = "Uniswap", limit: int = 90
network: str = "ethereum",
exchange: str = "Uniswap",
limit: int = 90,
sortby: str = "tradeAmount",
ascend: bool = True,
) -> pd.DataFrame:
"""Get most traded crypto pairs on given decentralized exchange in chosen time period.
[Source: https://graphql.bitquery.io/]
@@ -619,6 +672,10 @@ def get_most_traded_pairs(
Decentralized exchange name
limit:
Number of days taken into calculation account.
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -656,12 +713,19 @@ def get_most_traded_pairs(
df = _extract_dex_trades(data)
df.columns = ["trades", "tradeAmount", "base", "quoted"]
return df[TTCP_FILTERS]
df = df[TTCP_FILTERS]
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
@log_start_end(log=logger)
def get_spread_for_crypto_pair(
token: str = "WETH", vs: str = "USDT", limit: int = 30
symbol: str = "WETH",
vs: str = "USDT",
limit: int = 30,
sortby: str = "tradeAmount",
ascend: bool = True,
) -> pd.DataFrame:
"""Get an average bid and ask prices, average spread for given crypto pair for chosen time period.
[Source: https://graphql.bitquery.io/]
@@ -670,10 +734,14 @@ def get_spread_for_crypto_pair(
----------
limit: int
Last n days to query data
token: str
symbol: str
ERC20 token symbol
vs: str
Quoted currency.
sortby: str
Key by which to sort data
ascend: bool
Flag to sort data ascending
Returns
-------
@@ -682,7 +750,7 @@ def get_spread_for_crypto_pair(
"""
dt = (datetime.date.today() - datetime.timedelta(limit)).strftime("%Y-%m-%d")
base, quote = find_token_address(token), find_token_address(vs)
base, quote = find_token_address(symbol), find_token_address(vs)
if not base or not quote:
raise ValueError("Provided coin or quote currency doesn't exist\n")
@@ -729,7 +797,7 @@ def get_spread_for_crypto_pair(
daily_spread["dailySpread"] = abs(
daily_spread["averageBidPrice"] - daily_spread["averageAskPrice"]
)
return daily_spread[
df = daily_spread[
[
"date",
"baseCurrency",
@@ -738,7 +806,10 @@ def get_spread_for_crypto_pair(
"averageBidPrice",
"averageAskPrice",
]
].sort_values(by="date", ascending=True)
]
df = df.sort_values(by=sortby, ascending=ascend)
df.columns = prettify_column_names(df.columns)
return df
POSSIBLE_CRYPTOS = list(get_erc20_tokens()["symbol"].unique())

View File

@@ -5,7 +5,6 @@ import logging
import os
from openbb_terminal.cryptocurrency.dataframe_helpers import (
prettify_column_names,
lambda_very_long_number_formatter,
)
from openbb_terminal.cryptocurrency.onchain import bitquery_model
@@ -24,10 +23,11 @@ def display_dex_trades(
top: int = 20,
days: int = 90,
sortby: str = "tradeAmount",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Trades on Decentralized Exchanges aggregated by DEX or Month [Source: https://graphql.bitquery.io/]
"""Trades on Decentralized Exchanges aggregated by DEX or Month
[Source: https://graphql.bitquery.io/]
Parameters
----------
@@ -39,8 +39,8 @@ def display_dex_trades(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
days: int
Last n days to query data. Maximum 365 (bigger numbers can cause timeouts
on server side)
@@ -49,13 +49,11 @@ def display_dex_trades(
"""
if kind == "time":
df = bitquery_model.get_dex_trades_monthly(trade_amount_currency, days)
if not df.empty:
df = df.sort_values(by="date", ascending=descend)
df = bitquery_model.get_dex_trades_monthly(trade_amount_currency, days, ascend)
else:
df = bitquery_model.get_dex_trades_by_exchange(trade_amount_currency, days)
if not df.empty:
df = df.sort_values(by=sortby, ascending=descend)
df = bitquery_model.get_dex_trades_by_exchange(
trade_amount_currency, days, sortby, ascend
)
if not df.empty:
df_data = df.copy()
@@ -64,8 +62,6 @@ def display_dex_trades(
lambda x: lambda_very_long_number_formatter(x)
)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df.head(top),
headers=list(df.columns),
@@ -84,11 +80,11 @@ def display_dex_trades(
@log_start_end(log=logger)
@check_api_key(["API_BITQUERY_KEY"])
def display_daily_volume_for_given_pair(
token: str = "WBTC",
symbol: str = "WBTC",
vs: str = "USDT",
top: int = 20,
sortby: str = "date",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display daily volume for given pair
@@ -96,7 +92,7 @@ def display_daily_volume_for_given_pair(
Parameters
----------
token: str
symbol: str
ERC20 token symbol or address
vs: str
Quote currency.
@@ -104,10 +100,11 @@ def display_daily_volume_for_given_pair(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
Returns
-------
pd.DataFrame
@@ -115,21 +112,21 @@ def display_daily_volume_for_given_pair(
"""
df = bitquery_model.get_daily_dex_volume_for_given_pair(
token=token,
symbol=symbol,
vs=vs,
limit=top,
sortby=sortby,
ascend=ascend,
)
if df.empty:
return
df = df.sort_values(by=sortby, ascending=descend)
df_data = df.copy()
df[["tradeAmount", "trades"]] = df[["tradeAmount", "trades"]].applymap(
lambda x: lambda_very_long_number_formatter(x)
)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df.head(top),
@@ -149,18 +146,19 @@ def display_daily_volume_for_given_pair(
@log_start_end(log=logger)
@check_api_key(["API_BITQUERY_KEY"])
def display_dex_volume_for_token(
token: str = "WBTC",
symbol: str = "WBTC",
trade_amount_currency: str = "USD",
top: int = 10,
sortby: str = "tradeAmount",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display token volume on different Decentralized Exchanges. [Source: https://graphql.bitquery.io/]
"""Display token volume on different Decentralized Exchanges.
[Source: https://graphql.bitquery.io/]
Parameters
----------
token: str
symbol: str
ERC20 token symbol or address
trade_amount_currency: str
Currency of displayed trade amount. Default: USD
@@ -168,8 +166,8 @@ def display_dex_volume_for_token(
Number of records to display
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
Returns
@@ -179,18 +177,17 @@ def display_dex_volume_for_token(
"""
df = bitquery_model.get_token_volume_on_dexes(
token=token, trade_amount_currency=trade_amount_currency
symbol=symbol,
trade_amount_currency=trade_amount_currency,
sortby=sortby,
ascend=ascend,
)
if not df.empty:
df = df.sort_values(by=sortby, ascending=descend)
df_data = df.copy()
df[["tradeAmount", "trades"]] = df[["tradeAmount", "trades"]].applymap(
lambda x: lambda_very_long_number_formatter(x)
)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df.head(top),
headers=list(df.columns),
@@ -212,7 +209,7 @@ def display_ethereum_unique_senders(
interval: str = "days",
limit: int = 10,
sortby: str = "date",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display number of unique ethereum addresses which made a transaction in given time interval
@@ -229,8 +226,8 @@ def display_ethereum_unique_senders(
For better user experience maximum time period in days is equal to 90.
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
Returns
@@ -239,17 +236,13 @@ def display_ethereum_unique_senders(
Number of unique ethereum addresses which made a transaction in given time interval
"""
df = bitquery_model.get_ethereum_unique_senders(interval, limit)
df = bitquery_model.get_ethereum_unique_senders(interval, limit, sortby, ascend)
if not df.empty:
df = df.sort_values(by=sortby, ascending=descend)
df[["uniqueSenders", "transactions", "maximumGasPrice"]] = df[
["uniqueSenders", "transactions", "maximumGasPrice"]
].applymap(lambda x: lambda_very_long_number_formatter(x))
df_data = df.copy()
df.columns = prettify_column_names(df.columns)
print_rich_table(
df,
@@ -273,7 +266,7 @@ def display_most_traded_pairs(
days: int = 10,
top: int = 10,
sortby: str = "tradeAmount",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display most traded crypto pairs on given decentralized exchange in chosen time period.
@@ -287,8 +280,8 @@ def display_most_traded_pairs(
Number of days taken into calculation account.
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
Returns
@@ -297,14 +290,14 @@ def display_most_traded_pairs(
Most traded crypto pairs on given decentralized exchange in chosen time period.
"""
df = bitquery_model.get_most_traded_pairs(exchange=exchange, limit=days)
df = bitquery_model.get_most_traded_pairs(
exchange=exchange, limit=days, sortby=sortby, ascend=ascend
)
if not df.empty:
df = df.sort_values(by=sortby, ascending=descend)
df_data = df.copy()
df[["tradeAmount", "trades"]] = df[["tradeAmount", "trades"]].applymap(
lambda x: lambda_very_long_number_formatter(x)
)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df.head(top),
@@ -324,28 +317,28 @@ def display_most_traded_pairs(
@log_start_end(log=logger)
@check_api_key(["API_BITQUERY_KEY"])
def display_spread_for_crypto_pair(
token="ETH",
symbol="ETH",
vs="USDC",
days: int = 10,
sortby: str = "date",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display an average bid and ask prices, average spread for given crypto pair for chosen time period.
[Source: https://graphql.bitquery.io/]
"""Display an average bid and ask prices, average spread for given crypto pair for chosen
time period. [Source: https://graphql.bitquery.io/]
Parameters
----------
days: int
Last n days to query data
token: str
symbol: str
ERC20 token symbol
vs: str
Quoted currency.
sortby: str
Key by which to sort data
descend: bool
Flag to sort data descending
ascend: bool
Flag to sort data ascending
export : str
Export dataframe data to csv,json,xlsx file
@@ -355,11 +348,10 @@ def display_spread_for_crypto_pair(
Average bid and ask prices, spread for given crypto pair for chosen time period
"""
df = bitquery_model.get_spread_for_crypto_pair(token=token, vs=vs, limit=days)
df = bitquery_model.get_spread_for_crypto_pair(
symbol=symbol, vs=vs, limit=days, sortby=sortby, ascend=ascend
)
if not df.empty:
df = df.sort_values(by=sortby, ascending=descend)
df.columns = prettify_column_names(df.columns)
print_rich_table(
df,

View File

@@ -25,8 +25,8 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_btc_circulating_supply(
since: int,
until: int,
since: int = int(datetime(2010, 1, 1).timestamp()),
until: int = int(datetime.now().timestamp()),
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -78,8 +78,8 @@ def display_btc_circulating_supply(
@log_start_end(log=logger)
def display_btc_confirmed_transactions(
since: int,
until: int,
since: int = int(datetime(2010, 1, 1).timestamp()),
until: int = int(datetime.now().timestamp()),
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:

View File

@@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_gwei_fees(export: str) -> None:
def display_gwei_fees(export: str = "") -> None:
"""Current gwei fees
[Source: https://ethgasstation.info]

View File

@@ -88,7 +88,7 @@ def split_cols_with_dot(column: str) -> str:
Returns
-------
str:
Camel case string with removed dots. E.g. price.availableSupply -> priceAvailableSupply.
Camel case string with no dots. E.g. price.availableSupply -> priceAvailableSupply.
"""
return string[:index] + char + string[index + 1 :]
@@ -102,8 +102,8 @@ def split_cols_with_dot(column: str) -> str:
@log_start_end(log=logger)
def enrich_social_media(dct: dict) -> None:
"""Searching inside dictionary if there are any information about twitter, reddit or coingecko. If yes it
updates dictionary with url to given social media site.
"""Searching inside dictionary if there are any information about twitter, reddit or coingecko.
If yes it updates dictionary with url to given social media site.
Parameters
----------
@@ -131,7 +131,7 @@ def make_request(
Parameters
----------
endpoint: str
endpoint which we want to query e.g. https://api.ethplorer.io/<endpoint><arg>?=apiKey=freekey
endpoint we want to query e.g. https://api.ethplorer.io/<endpoint><arg>?=apiKey=freekey
address: str
balance argument for given endpoint. In most cases it's tx hash, or eth balance.
kwargs: Any
@@ -193,7 +193,9 @@ def get_token_decimals(address: str) -> Optional[int]:
@log_start_end(log=logger)
def get_address_info(address: str) -> pd.DataFrame:
def get_address_info(
address: str, sortby: str = "index", ascend: bool = False
) -> pd.DataFrame:
"""Get info about tokens on you ethereum blockchain balance. Eth balance, balance of all tokens which
have name and symbol. [Source: Ethplorer]
@@ -201,6 +203,10 @@ def get_address_info(address: str) -> pd.DataFrame:
----------
address: str
Blockchain balance e.g. 0x3cD751E6b0078Be393132286c442345e5DC49699
sortby: str
Key to sort by.
ascend: str
Sort in descending order.
Returns
-------
@@ -254,11 +260,12 @@ def get_address_info(address: str) -> pd.DataFrame:
df = pd.concat([eth_row_df, df], ignore_index=True)
df = df[df["tokenName"].notna()][cols]
create_df_index(df, "index")
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_top_tokens() -> pd.DataFrame:
def get_top_tokens(sortby: str = "rank", ascend: bool = False) -> pd.DataFrame:
"""Get top 50 tokens. [Source: Ethplorer]
Returns
@@ -283,17 +290,24 @@ def get_top_tokens() -> pd.DataFrame:
]
df["price"] = df["price"].apply(lambda x: x["rate"] if x and "rate" in x else None)
create_df_index(df, "rank")
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_top_token_holders(address) -> pd.DataFrame:
def get_top_token_holders(
address, sortby: str = "balance", ascend: bool = True
) -> pd.DataFrame:
"""Get info about top token holders. [Source: Ethplorer]
Parameters
----------
address: str
Token balance e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
sortby: str
Key to sort by.
ascend: str
Sort in descending order.
Returns
-------
@@ -307,17 +321,24 @@ def get_top_token_holders(address) -> pd.DataFrame:
token_decimals_divider = get_token_decimals(address)
if token_decimals_divider:
df["balance"] = df["balance"] / token_decimals_divider
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_address_history(address) -> pd.DataFrame:
def get_address_history(
address, sortby: str = "timestamp", ascend: bool = True
) -> pd.DataFrame:
"""Get information about balance historical transactions. [Source: Ethplorer]
Parameters
----------
address: str
Blockchain balance e.g. 0x3cD751E6b0078Be393132286c442345e5DC49699
sortby: str
Key to sort by.
ascend: str
Sort in ascending order.
Returns
-------
@@ -343,7 +364,9 @@ def get_address_history(address) -> pd.DataFrame:
console.print(f"No historical transaction found for {address}")
return pd.DataFrame(columns=cols)
return df[cols]
df = df[cols]
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
@@ -456,13 +479,19 @@ def get_tx_info(tx_hash) -> pd.DataFrame:
@log_start_end(log=logger)
def get_token_history(address) -> pd.DataFrame:
def get_token_history(
address, sortby: str = "timestamp", ascend: bool = False
) -> pd.DataFrame:
"""Get info about token historical transactions. [Source: Ethplorer]
Parameters
----------
address: str
Token e.g. 0xf3db5fa2c66b7af3eb0c0b782510816cbe4813b8
sortby: str
Key to sort by.
ascend: str
Sort in descending order.
Returns
-------
@@ -500,17 +529,27 @@ def get_token_history(address) -> pd.DataFrame:
df[["name", "symbol"]] = name, symbol
df["value"] = df["value"].astype(float) / (10 ** int(decimals))
return df[["timestamp", "name", "symbol", "value", "from", "to", "transactionHash"]]
df = df[["timestamp", "name", "symbol", "value", "from", "to", "transactionHash"]]
df = df.sort_values(by=sortby, ascending=ascend)
return df
@log_start_end(log=logger)
def get_token_historical_price(address) -> pd.DataFrame:
def get_token_historical_price(
address,
sortby: str = "date",
ascend: bool = False,
) -> pd.DataFrame:
"""Get token historical prices with volume and market cap, and average price. [Source: Ethplorer]
Parameters
----------
address: str
Token e.g. 0xf3db5fa2c66b7af3eb0c0b782510816cbe4813b8
sortby: str
Key to sort by.
ascend: str
Sort in descending order.
Returns
-------
@@ -533,6 +572,8 @@ def get_token_historical_price(address) -> pd.DataFrame:
if "tmp" in prices_df.columns:
prices_df.drop("tmp", axis=1, inplace=True)
return prices_df[
df = prices_df[
["date", "open", "close", "high", "low", "volumeConverted", "cap", "average"]
]
df = df.sort_values(by=sortby, ascending=ascend)
return df

View File

@@ -22,11 +22,11 @@ def display_address_info(
address: str,
top: int = 15,
sortby: str = "index",
descend: bool = True,
ascend: bool = False,
export: str = "",
) -> None:
"""Display info about tokens for given ethereum blockchain balance e.g. ETH balance, balance of all tokens with
name and symbol. [Source: Ethplorer]
"""Display info about tokens for given ethereum blockchain balance e.g. ETH balance,
balance of all tokens with name and symbol. [Source: Ethplorer]
Parameters
----------
@@ -36,15 +36,14 @@ def display_address_info(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
ascend: str
Sort in descending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_address_info(address)
df = ethplorer_model.get_address_info(address, sortby=sortby, ascend=ascend)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df["balance"] = df["balance"].apply(
lambda x: lambda_very_long_number_formatter(x)
if x >= 10000
@@ -71,7 +70,7 @@ def display_address_info(
def display_top_tokens(
top: int = 15,
sortby: str = "rank",
descend: bool = True,
ascend: bool = True,
export: str = "",
) -> None:
"""Display top ERC20 tokens [Source: Ethplorer]
@@ -82,16 +81,15 @@ def display_top_tokens(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
ascend: str
Sort in descending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_top_tokens()
df = ethplorer_model.get_top_tokens(sortby, ascend)
df_data = df.copy()
df.fillna("", inplace=True)
df = df.sort_values(by=sortby, ascending=descend)
for col in ["txsCount", "transfersCount", "holdersCount"]:
if col in df.columns:
df[col] = df[col].apply(lambda x: lambda_very_long_number_formatter(x))
@@ -117,7 +115,7 @@ def display_top_token_holders(
address: str,
top: int = 10,
sortby: str = "balance",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display info about top ERC20 token holders. [Source: Ethplorer]
@@ -130,15 +128,14 @@ def display_top_token_holders(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
ascend: str
Sort in descending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_top_token_holders(address)
df = ethplorer_model.get_top_token_holders(address, sortby, ascend)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df["balance"] = df["balance"].apply(lambda x: lambda_very_long_number_formatter(x))
print_rich_table(
@@ -162,7 +159,7 @@ def display_address_history(
address: str,
top: int = 10,
sortby: str = "timestamp",
descend: bool = False,
ascend: bool = True,
export: str = "",
) -> None:
"""Display information about balance historical transactions. [Source: Ethplorer]
@@ -175,15 +172,14 @@ def display_address_history(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
Sort in descending order.
ascend: str
Sort in ascending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_address_history(address)
df = ethplorer_model.get_address_history(address, sortby, ascend)
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
df["value"] = df["value"].apply(
lambda x: lambda_very_long_number_formatter(x)
if x >= 10000
@@ -265,7 +261,6 @@ def display_tx_info(
"""
df = ethplorer_model.get_tx_info(tx_hash)
df_data = df.copy()
print_rich_table(
df,
headers=list(df.columns),
@@ -273,12 +268,7 @@ def display_tx_info(
title="Information About Transactions",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"tx",
df_data,
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "tx", df)
@log_start_end(log=logger)
@@ -287,8 +277,8 @@ def display_token_history(
address: str,
top: int = 10,
sortby: str = "timestamp",
ascend: bool = False,
hash_: bool = False,
descend: bool = False,
export: str = "",
) -> None:
"""Display info about token history. [Source: Ethplorer]
@@ -301,7 +291,7 @@ def display_token_history(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
ascend: str
Sort in descending order.
hash_: bool,
Flag to show transaction hash.
@@ -309,7 +299,7 @@ def display_token_history(
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_token_history(address)
df = ethplorer_model.get_token_history(address, sortby, ascend)
df_data = df.copy()
if df.empty:
console.print(f"No results found for balance: {address}\n")
@@ -318,7 +308,6 @@ def display_token_history(
df.loc[:, "value"] = df["value"].apply(
lambda x: lambda_very_long_number_formatter(x)
)
df = df.sort_values(by=sortby, ascending=descend)
if hash_:
df.drop(["from", "to"], axis=1, inplace=True)
@@ -346,10 +335,11 @@ def display_token_historical_prices(
address: str,
top: int = 30,
sortby: str = "date",
descend: bool = False,
ascend: bool = False,
export: str = "",
) -> None:
"""Display token historical prices with volume and market cap, and average price. [Source: Ethplorer]
"""Display token historical prices with volume and market cap, and average price.
[Source: Ethplorer]
Parameters
----------
@@ -359,13 +349,13 @@ def display_token_historical_prices(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
ascend: str
Sort in descending order.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ethplorer_model.get_token_historical_price(address)
df = ethplorer_model.get_token_historical_price(address, sortby, ascend)
df_data = df.copy()
if df.empty:
@@ -376,7 +366,6 @@ def display_token_historical_prices(
lambda x: lambda_very_long_number_formatter(x)
)
df.loc[:, "cap"] = df["cap"].apply(lambda x: lambda_very_long_number_formatter(x))
df = df.sort_values(by=sortby, ascending=descend)
print_rich_table(
df.head(top),

View File

@@ -305,7 +305,7 @@ class OnchainController(BaseController):
if ns_parser:
display_hashrate(
asset=ns_parser.coin,
symbol=ns_parser.coin,
interval=ns_parser.interval,
since=int(datetime.timestamp(ns_parser.since)),
until=int(datetime.timestamp(ns_parser.until)),
@@ -398,7 +398,7 @@ class OnchainController(BaseController):
min_value=ns_parser.min,
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
show_address=ns_parser.address,
export=ns_parser.export,
)
@@ -527,7 +527,7 @@ class OnchainController(BaseController):
ethplorer_view.display_address_info(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
address=self.address,
export=ns_parser.export,
)
@@ -583,7 +583,7 @@ class OnchainController(BaseController):
ethplorer_view.display_address_history(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
address=self.address,
export=ns_parser.export,
)
@@ -638,7 +638,7 @@ class OnchainController(BaseController):
ethplorer_view.display_top_token_holders(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
address=self.address,
export=ns_parser.export,
)
@@ -693,7 +693,7 @@ class OnchainController(BaseController):
ethplorer_view.display_top_tokens(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -789,7 +789,7 @@ class OnchainController(BaseController):
top=ns_parser.limit,
hash_=ns_parser.hash,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
address=self.address,
export=ns_parser.export,
)
@@ -870,7 +870,7 @@ class OnchainController(BaseController):
ethplorer_view.display_token_historical_prices(
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
address=self.address,
export=ns_parser.export,
)
@@ -957,7 +957,7 @@ class OnchainController(BaseController):
top=ns_parser.limit,
days=ns_parser.days,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1036,7 +1036,7 @@ class OnchainController(BaseController):
vs=ns_parser.vs,
top=ns_parser.days,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1111,7 +1111,7 @@ class OnchainController(BaseController):
trade_amount_currency=ns_parser.vs,
top=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1177,7 +1177,7 @@ class OnchainController(BaseController):
interval=ns_parser.interval,
limit=ns_parser.limit,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1286,7 +1286,7 @@ class OnchainController(BaseController):
top=ns_parser.limit,
exchange=exchange,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1357,7 +1357,7 @@ class OnchainController(BaseController):
vs=ns_parser.vs,
days=ns_parser.days,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
@@ -1380,7 +1380,7 @@ class OnchainController(BaseController):
vs=ns_parser.vs,
days=ns_parser.days,
sortby=ns_parser.sortby,
descend=ns_parser.descend,
ascend=not ns_parser.descend,
export=ns_parser.export,
)
else:

View File

@@ -82,7 +82,12 @@ def make_request(params: Optional[dict] = None) -> Tuple[Optional[int], Any]:
@log_start_end(log=logger)
def get_whales_transactions(min_value: int = 800000, limit: int = 100) -> pd.DataFrame:
def get_whales_transactions(
min_value: int = 800000,
limit: int = 100,
sortby: str = "date",
ascend: bool = False,
) -> pd.DataFrame:
"""Whale Alert's API allows you to retrieve live and historical transaction data from major blockchains.
Supported blockchain: Bitcoin, Ethereum, Ripple, NEO, EOS, Stellar and Tron. [Source: https://docs.whale-alert.io/]
@@ -92,6 +97,10 @@ def get_whales_transactions(min_value: int = 800000, limit: int = 100) -> pd.Dat
Minimum value of trade to track.
limit: int
Limit of transactions. Max 100
sortby: str
Key to sort by.
ascend: str
Sort in ascending order.
Returns
-------
@@ -150,7 +159,7 @@ def get_whales_transactions(min_value: int = 800000, limit: int = 100) -> pd.Dat
inplace=True,
)
return data[
df = data[
[
"date",
"symbol",
@@ -163,3 +172,5 @@ def get_whales_transactions(min_value: int = 800000, limit: int = 100) -> pd.Dat
"to_address",
]
]
df = df.sort_values(by=sortby, ascending=ascend)
return df

View File

@@ -23,7 +23,7 @@ def display_whales_transactions(
min_value: int = 800000,
top: int = 100,
sortby: str = "date",
descend: bool = False,
ascend: bool = False,
show_address: bool = False,
export: str = "",
) -> None:
@@ -37,15 +37,15 @@ def display_whales_transactions(
Limit of transactions. Maximum 100
sortby: str
Key to sort by.
descend: str
Sort in descending order.
ascend: str
Sort in ascending order.
show_address: bool
Flag to show addresses of transactions.
export : str
Export dataframe data to csv,json,xlsx file
"""
df = whale_alert_model.get_whales_transactions(min_value)
df = whale_alert_model.get_whales_transactions(min_value, sortby, ascend)
if df.empty:
console.print("Failed to retrieve data.")
@@ -53,8 +53,6 @@ def display_whales_transactions(
df_data = df.copy()
df = df.sort_values(by=sortby, ascending=descend)
if not show_address:
df = df.drop(["from_address", "to_address"], axis=1)
else:

View File

@@ -16,15 +16,19 @@ DAYS = [30, 90, 365]
@log_start_end(log=logger)
def get_altcoin_index(period: int, since: int, until: int) -> pd.DataFrame:
def get_altcoin_index(
period: int = 30,
since: int = int(datetime(2010, 1, 1).timestamp()),
until: int = int(datetime.now().timestamp()),
) -> pd.DataFrame:
"""Get altcoin index overtime
[Source: https://blockchaincenter.net]
Parameters
----------
period: int
Number of days {30,90,365} to check the performance of coins and calculate the altcoin index.
E.g., 365 will check yearly performance (365 days), 90 will check seasonal performance (90 days),
Number of days {30,90,365} to check performance of coins and calculate the altcoin index.
E.g., 365 checks yearly performance, 90 will check seasonal performance (90 days),
30 will check monthly performance (30 days).
since : int
Initial date timestamp (e.g., 1_609_459_200)

View File

@@ -2,6 +2,7 @@
import logging
import os
from typing import List, Optional
from datetime import datetime
from matplotlib import pyplot as plt
@@ -24,9 +25,9 @@ logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_altcoin_index(
period: int,
since: int,
until: int,
period: int = 365,
since: int = int(datetime(2010, 1, 1).timestamp()),
until: int = int(datetime.now().timestamp()),
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
) -> None:
@@ -41,7 +42,7 @@ def display_altcoin_index(
End date timestamp (e.g., 1_641_588_030)
period: int
Number of days to check the performance of coins and calculate the altcoin index.
E.g., 365 will check yearly performance (365 days), 90 will check seasonal performance (90 days),
E.g., 365 will check yearly performance , 90 will check seasonal performance (90 days),
30 will check monthly performance (30 days).
export : str
Export dataframe data to csv,json,xlsx file

View File

@@ -21,7 +21,9 @@ PAIRS_FILTERS = [
@log_start_end(log=logger)
def get_trading_pairs() -> pd.DataFrame:
def get_trading_pairs(
top: int = 50, sortby: str = "quote_increment", ascend: bool = True
) -> pd.DataFrame:
"""Get a list of available currency pairs for trading. [Source: Coinbase]
base_min_size - min order size
@@ -29,6 +31,15 @@ def get_trading_pairs() -> pd.DataFrame:
min_market_funds - min funds allowed in a market order.
max_market_funds - max funds allowed in a market order.
Parameters
----------
top: int
Top n of pairs
sortby: str
Key to sortby data
ascend: bool
Sort descending flag
Returns
-------
pd.DataFrame
@@ -45,4 +56,6 @@ def get_trading_pairs() -> pd.DataFrame:
"min_market_funds",
]
pairs = make_coinbase_request("/products")
return pd.DataFrame(pairs)[columns]
df = pd.DataFrame(pairs)[columns]
df = df.sort_values(by=sortby, ascending=ascend).head(top)
return df

Some files were not shown because too many files have changed in this diff Show More