Spaces:
Build error
Build error
| import pandas as pd | |
| import mplfinance as mpf | |
| from io import BytesIO | |
| import base64 | |
| import matplotlib.pyplot as plt | |
| def create_mplfinance_chart(df, ticker, predictions=None): | |
| """ | |
| Creates a custom mplfinance candlestick chart and returns it as a base64 encoded image. | |
| Implements the exact layout: Candlestick + Volume + MACD + Stochastic. | |
| """ | |
| if df.empty: | |
| return None | |
| # Define style - Yahoo style as requested | |
| mc = mpf.make_marketcolors( | |
| up='#00ff00', down='#ff0000', # Green/Red candles | |
| wick='black', | |
| edge='black', | |
| volume='#00bfff', | |
| inherit=True | |
| ) | |
| s = mpf.make_mpf_style( | |
| base_mpf_style='yahoo', | |
| marketcolors=mc, | |
| facecolor='white', | |
| edgecolor='black', | |
| gridcolor='lightgray', | |
| gridstyle='-', | |
| figcolor='white', | |
| rc={'axes.labelcolor': 'black', | |
| 'xtick.color': 'black', | |
| 'ytick.color': 'black', | |
| 'figure.titlesize': 16, | |
| 'axes.titlesize': 14, | |
| 'axes.titleweight': 'bold'} | |
| ) | |
| # Define panels: [Candlestick, Volume, MACD, Stochastic] | |
| apds = [] | |
| # MACD Panel (Panel 2 - index 1 for addplot) | |
| # MACD Line | |
| apds.append( | |
| mpf.make_addplot(df['MACD'], color='#606060', panel=2, ylabel='MACD', secondary_y=False) | |
| ) | |
| # Signal Line | |
| apds.append( | |
| mpf.make_addplot(df['MACD_signal'], color='#1f77b4', panel=2, secondary_y=False) | |
| ) | |
| # Positive Histogram Bars | |
| apds.append( | |
| mpf.make_addplot(df['MACD_bar_positive'], type='bar', color='#4dc790', panel=2, width=0.8) | |
| ) | |
| # Negative Histogram Bars | |
| apds.append( | |
| mpf.make_addplot(df['MACD_bar_negative'], type='bar', color='#fd6b6c', panel=2, width=0.8) | |
| ) | |
| # Stochastic Panel (Panel 3 - index 2 for addplot) | |
| apds.append( | |
| mpf.make_addplot(df[['%D', '%SD', 'UL', 'DL']], panel=3, ylabel='Stoch (14,3)', ylim=[0, 100]) | |
| ) | |
| # Prediction overlay on main chart | |
| if predictions is not None and predictions.any(): | |
| last_date = df.index[-1] | |
| future_index = pd.date_range(start=last_date, periods=len(predictions) + 1, freq=df.index.freq or 'D')[1:] | |
| future_series = pd.Series(predictions, index=future_index) | |
| apds.append( | |
| mpf.make_addplot(future_series, color='blue', linestyle='-.', width=2, marker='o', markersize=4) | |
| ) | |
| # Plotting | |
| fig, axes = mpf.plot( | |
| df, | |
| type='candle', | |
| style=s, | |
| title=f'{ticker} Price Chart and Analysis', | |
| ylabel='Price (USD)', | |
| volume=True, | |
| addplot=apds, | |
| mav=(5, 20), # Moving averages as requested | |
| figratio=(16, 9), | |
| figscale=1.5, | |
| panel_ratios=(3, 1, 3, 3), # Ratio as requested | |
| returnfig=True | |
| ) | |
| # Convert to Base64 | |
| buf = BytesIO() | |
| fig.savefig(buf, format='png', bbox_inches='tight', dpi=100) | |
| plt.close(fig) | |
| image_base64 = base64.b64encode(buf.getvalue()).decode('utf-8') | |
| return f'<img src="data:image/png;base64,{image_base64}" style="width: 100%; height: auto;">' |