Files
OpenBB/openbb_terminal/common/behavioural_analysis/twitter_view.py
montezdesousa 02901f1473 Trim command output spaces (#3424)
* first round of removing spaces

* remove more print statemnts

* remove more spaces

* bullbear color

* spacc color

* improve stalker readability

* delete more spaces

* reddit colors

* rever hood

* flake8

* forgot this one

* fix econometrics tests

* fix econometrics tests

* fix more tests

Co-authored-by: James Maslek <jmaslek11@gmail.com>
2022-11-16 11:47:24 +00:00

190 lines
5.8 KiB
Python

"""Twitter view."""
__docformat__ = "numpy"
import logging
import os
from typing import Optional, List
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from dateutil import parser as dparse
import openbb_terminal.config_plot as cfg_plot
from openbb_terminal.config_terminal import theme
from openbb_terminal.common.behavioural_analysis import twitter_model
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import (
export_data,
plot_autoscale,
get_closing_price,
is_valid_axes_count,
)
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def display_inference(symbol: str, limit: int = 100, export: str = ""):
"""Prints Inference sentiment from past n tweets.
Parameters
----------
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(symbol, limit)
if (isinstance(df_tweets, pd.DataFrame) and df_tweets.empty) or (
not isinstance(df_tweets, pd.DataFrame) and not df_tweets
):
return
# Parse tweets
dt_from = dparse.parse(df_tweets["created_at"].values[-1])
dt_to = dparse.parse(df_tweets["created_at"].values[0])
console.print(f"From: {dt_from.strftime('%Y-%m-%d %H:%M:%S')}")
console.print(f"To: {dt_to.strftime('%Y-%m-%d %H:%M:%S')}")
console.print(f"{len(df_tweets)} tweets were analyzed.")
dt_delta = dt_to - dt_from
n_freq = dt_delta.total_seconds() / len(df_tweets)
console.print(f"Frequency of approx 1 tweet every {round(n_freq)} seconds.")
pos = df_tweets["positive"]
neg = df_tweets["negative"]
percent_pos = len(np.where(pos > neg)[0]) / len(df_tweets)
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 {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"
)
console.print(
f"Of the last {len(df_tweets)} tweets, {100*percent_neg:.2f} % had a higher negative sentiment"
)
export_data(export, os.path.dirname(os.path.abspath(__file__)), "infer", df_tweets)
@log_start_end(log=logger)
def display_sentiment(
symbol: str,
n_tweets: int = 15,
n_days_past: int = 2,
compare: bool = False,
export: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Plots 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
compare: bool
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
"""
df_tweets = twitter_model.get_sentiment(symbol, n_tweets, n_days_past)
if df_tweets.empty:
return
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
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
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"),
)
ax2.bar(
df_tweets["date"],
df_tweets["positive"],
color=theme.up_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 {symbol} total compound sentiment over time is {round(np.sum(df_tweets['sentiment']), 2)}"
)
theme.style_primary_axis(ax1)
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(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)
if external_axes is None:
theme.visualize_output()
export_data(
export, os.path.dirname(os.path.abspath(__file__)), "sentiment", df_tweets
)