{"spec_id":"indicator-ema","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nindicator-ema: Exponential Moving Average (EMA) Indicator Chart\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 74/100 | Updated: 2026-05-19\n\"\"\"\n\nimport numpy as np\nimport pandas as pd\nfrom bokeh.io import export_png\nfrom bokeh.models import ColumnDataSource, Legend\nfrom bokeh.plotting import figure, output_file, save\n\n\n# Data - Generate synthetic stock price data\nnp.random.seed(42)\nn_days = 120\n\n# Generate realistic price movement using random walk with drift\ndates = pd.date_range(\"2025-01-01\", periods=n_days, freq=\"B\")  # Business days\nreturns = np.random.normal(0.0008, 0.018, n_days)  # Daily returns\nprice = 150 * np.cumprod(1 + returns)\n\n# Add some trend changes for visual interest\nprice[40:80] = price[40:80] * np.linspace(1, 1.15, 40)  # Uptrend\nprice[80:100] = price[80:100] * np.linspace(1, 0.92, 20)  # Downtrend\n\n# Create DataFrame\ndf = pd.DataFrame({\"date\": dates, \"close\": price})\n\n# Calculate EMAs using pandas ewm\ndf[\"ema_12\"] = df[\"close\"].ewm(span=12, adjust=False).mean()\ndf[\"ema_26\"] = df[\"close\"].ewm(span=26, adjust=False).mean()\n\n# Create ColumnDataSource\nsource = ColumnDataSource(df)\n\n# Create figure with datetime axis\np = figure(\n    width=4800,\n    height=2700,\n    title=\"indicator-ema \\u00b7 bokeh \\u00b7 pyplots.ai\",\n    x_axis_label=\"Date\",\n    y_axis_label=\"Price (USD)\",\n    x_axis_type=\"datetime\",\n    tools=\"pan,wheel_zoom,box_zoom,reset,save\",\n)\n\n# Plot price line (prominent)\nprice_line = p.line(\"date\", \"close\", source=source, line_width=5, line_color=\"#306998\", alpha=1.0)\n\n# Plot EMA 12 (short-term, thinner)\nema_12_line = p.line(\"date\", \"ema_12\", source=source, line_width=3, line_color=\"#FFD43B\", alpha=0.9)\n\n# Plot EMA 26 (longer-term, thinner)\nema_26_line = p.line(\"date\", \"ema_26\", source=source, line_width=3, line_color=\"#E74C3C\", alpha=0.9)\n\n# Find and mark crossover points\ncrossover_indices = []\nfor i in range(1, len(df)):\n    ema12_prev = df[\"ema_12\"].iloc[i - 1]\n    ema26_prev = df[\"ema_26\"].iloc[i - 1]\n    ema12_curr = df[\"ema_12\"].iloc[i]\n    ema26_curr = df[\"ema_26\"].iloc[i]\n\n    # Detect crossover (EMA12 crosses EMA26)\n    if (ema12_prev < ema26_prev and ema12_curr >= ema26_curr) or (ema12_prev > ema26_prev and ema12_curr <= ema26_curr):\n        crossover_indices.append(i)\n\n# Mark crossovers with circles\ncrossover_scatter = None\nif crossover_indices:\n    crossover_source = ColumnDataSource(\n        data={\n            \"date\": [df[\"date\"].iloc[i] for i in crossover_indices],\n            \"price\": [df[\"close\"].iloc[i] for i in crossover_indices],\n        }\n    )\n    crossover_scatter = p.scatter(\"date\", \"price\", source=crossover_source, size=25, color=\"#9B59B6\", marker=\"circle\")\n\n# Create legend manually for better control\nlegend_items = [(\"Close Price\", [price_line]), (\"EMA 12\", [ema_12_line]), (\"EMA 26\", [ema_26_line])]\nif crossover_scatter:\n    legend_items.append((\"Crossover Signal\", [crossover_scatter]))\n\nlegend = Legend(items=legend_items, location=\"top_left\")\np.add_layout(legend, \"right\")\n\n# Style the plot\np.title.text_font_size = \"36pt\"\np.title.text_font_style = \"bold\"\np.xaxis.axis_label_text_font_size = \"26pt\"\np.yaxis.axis_label_text_font_size = \"26pt\"\np.xaxis.major_label_text_font_size = \"20pt\"\np.yaxis.major_label_text_font_size = \"20pt\"\n\n# Legend styling\np.legend.label_text_font_size = \"22pt\"\np.legend.glyph_width = 50\np.legend.glyph_height = 30\np.legend.spacing = 15\np.legend.padding = 20\np.legend.background_fill_alpha = 0.9\n\n# Grid styling\np.grid.grid_line_alpha = 0.3\np.grid.grid_line_dash = [6, 4]\n\n# Background\np.background_fill_color = \"#fafafa\"\np.border_fill_color = \"#ffffff\"\n\n# Axis styling\np.xaxis.axis_line_width = 2\np.yaxis.axis_line_width = 2\np.xaxis.major_tick_line_width = 2\np.yaxis.major_tick_line_width = 2\n\n# Save PNG\nexport_png(p, filename=\"plot.png\")\n\n# Save interactive HTML\noutput_file(\"plot.html\", title=\"EMA Indicator - bokeh - pyplots.ai\")\nsave(p)\n"}