Skip to main content
Glama

MaverickMCP

by wshobson
MIT License
165
  • Apple
visualization.py8.66 kB
""" Visualization utilities for Maverick-MCP. This module contains functions for generating charts and visualizations for financial data, including technical analysis charts. """ import base64 import logging import os import tempfile import numpy as np import pandas as pd import plotly.graph_objects as go import plotly.subplots as sp from maverick_mcp.config.plotly_config import setup_plotly # Set up logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger("maverick_mcp.visualization") # Configure Plotly to use modern defaults and suppress warnings setup_plotly() def plotly_fig_to_base64(fig: go.Figure, format: str = "png") -> str: """ Convert a Plotly figure to a base64 encoded data URI string. Args: fig: The Plotly figure to convert format: Image format (default: 'png') Returns: Base64 encoded data URI string of the figure """ img_bytes = None with tempfile.NamedTemporaryFile(suffix=f".{format}", delete=False) as tmpfile: try: fig.write_image(tmpfile.name) tmpfile.seek(0) img_bytes = tmpfile.read() except Exception as e: logger.error(f"Error writing image: {e}") raise os.remove(tmpfile.name) if not img_bytes: logger.error("No image bytes were written. Is kaleido installed?") raise RuntimeError( "Plotly failed to write image. Ensure 'kaleido' is installed." ) base64_str = base64.b64encode(img_bytes).decode("utf-8") return f"data:image/{format};base64,{base64_str}" def create_plotly_technical_chart( df: pd.DataFrame, ticker: str, height: int = 400, width: int = 600 ) -> go.Figure: """ Generate a Plotly technical analysis chart for financial data visualization. Args: df: DataFrame with price and technical indicator data ticker: The ticker symbol to display in the chart title height: Chart height width: Chart width Returns: A Plotly figure with the technical analysis chart """ df = df.copy() df.columns = [col.lower() for col in df.columns] df = df.iloc[-126:].copy() # Ensure we keep DataFrame structure fig = sp.make_subplots( rows=4, cols=1, shared_xaxes=True, vertical_spacing=0.03, subplot_titles=("", "", "", ""), row_heights=[0.6, 0.15, 0.15, 0.1], ) bg_color = "#FFFFFF" text_color = "#000000" grid_color = "rgba(0, 0, 0, 0.35)" colors = { "green": "#00796B", "red": "#D32F2F", "blue": "#1565C0", "orange": "#E65100", "purple": "#6A1B9A", "gray": "#424242", "black": "#000000", } line_width = 1 # Candlestick chart fig.add_trace( go.Candlestick( x=df.index, name="Price", open=df["open"], high=df["high"], low=df["low"], close=df["close"], increasing_line_color=colors["green"], decreasing_line_color=colors["red"], line={"width": line_width}, ), row=1, col=1, ) # Moving averages for i, (col, name) in enumerate( [("ema_21", "EMA 21"), ("sma_50", "SMA 50"), ("sma_200", "SMA 200")] ): color = [colors["blue"], colors["green"], colors["red"]][i] fig.add_trace( go.Scatter( x=df.index, y=df[col], mode="lines", name=name, line={"color": color, "width": line_width}, ), row=1, col=1, ) # Bollinger Bands light_blue = "rgba(21, 101, 192, 0.6)" fill_color = "rgba(21, 101, 192, 0.1)" fig.add_trace( go.Scatter( x=df.index, y=df["bbu_20_2.0"], mode="lines", line={"color": light_blue, "width": line_width}, name="Upper BB", legendgroup="bollinger", showlegend=True, ), row=1, col=1, ) fig.add_trace( go.Scatter( x=df.index, y=df["bbl_20_2.0"], mode="lines", line={"color": light_blue, "width": line_width}, name="Lower BB", legendgroup="bollinger", showlegend=False, fill="tonexty", fillcolor=fill_color, ), row=1, col=1, ) # Volume volume_colors = np.where(df["close"] >= df["open"], colors["green"], colors["red"]) fig.add_trace( go.Bar( x=df.index, y=df["volume"], name="Volume", marker={"color": volume_colors}, opacity=0.75, showlegend=False, ), row=2, col=1, ) # RSI fig.add_trace( go.Scatter( x=df.index, y=df["rsi"], mode="lines", name="RSI", line={"color": colors["blue"], "width": line_width}, ), row=3, col=1, ) fig.add_hline( y=70, line_dash="dash", line_color=colors["red"], line_width=line_width, row=3, col=1, ) fig.add_hline( y=30, line_dash="dash", line_color=colors["green"], line_width=line_width, row=3, col=1, ) # MACD fig.add_trace( go.Scatter( x=df.index, y=df["macd_12_26_9"], mode="lines", name="MACD", line={"color": colors["blue"], "width": line_width}, ), row=4, col=1, ) fig.add_trace( go.Scatter( x=df.index, y=df["macds_12_26_9"], mode="lines", name="Signal", line={"color": colors["orange"], "width": line_width}, ), row=4, col=1, ) fig.add_trace( go.Bar( x=df.index, y=df["macdh_12_26_9"], name="Histogram", showlegend=False, marker={"color": df["macdh_12_26_9"], "colorscale": "RdYlGn"}, ), row=4, col=1, ) # Layout import datetime now = datetime.datetime.now(datetime.UTC).strftime("%m/%d/%Y") fig.update_layout( height=height, width=width, title={ "text": f"<b>{ticker.upper()} | {now} | Technical Analysis | Maverick-MCP</b>", "font": {"size": 12, "color": text_color, "family": "Arial, sans-serif"}, "y": 0.98, }, plot_bgcolor=bg_color, paper_bgcolor=bg_color, xaxis_rangeslider_visible=False, legend={ "orientation": "h", "yanchor": "bottom", "y": 1, "xanchor": "left", "x": 0, "font": {"size": 10, "color": text_color, "family": "Arial, sans-serif"}, "itemwidth": 30, "itemsizing": "constant", "borderwidth": 0, "tracegroupgap": 1, }, font={"size": 10, "color": text_color, "family": "Arial, sans-serif"}, margin={"r": 20, "l": 40, "t": 80, "b": 0}, ) fig.update_xaxes( gridcolor=grid_color, zerolinecolor=grid_color, zerolinewidth=line_width, gridwidth=1, griddash="dot", ) fig.update_yaxes( gridcolor=grid_color, zerolinecolor=grid_color, zerolinewidth=line_width, gridwidth=1, griddash="dot", ) y_axis_titles = ["Price", "Volume", "RSI", "MACD"] for i, title in enumerate(y_axis_titles, start=1): if title: fig.update_yaxes( title={ "text": f"<b>{title}</b>", "font": {"size": 8, "color": text_color}, "standoff": 0, }, side="left", position=0, automargin=True, row=i, col=1, tickfont={"size": 8}, ) fig.update_xaxes(showticklabels=False, row=1, col=1) fig.update_xaxes(showticklabels=False, row=2, col=1) fig.update_xaxes(showticklabels=False, row=3, col=1) fig.update_xaxes( title={"text": "Date", "font": {"size": 8, "color": text_color}, "standoff": 5}, row=4, col=1, tickfont={"size": 8}, showticklabels=True, tickangle=45, tickformat="%Y-%m-%d", ) return fig

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wshobson/maverick-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server