{"spec_id":"indicator-ema","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nindicator-ema: Exponential Moving Average (EMA) Indicator Chart\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-19\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette — positions 1-5 in canonical order\nBRAND = \"#009E73\"  # price line (first series)\nEMA_SHORT = \"#C475FD\"  # EMA 12\nEMA_LONG = \"#4467A3\"  # EMA 26\nGOLDEN_CLR = \"#DDCC77\"  # imprint amber — golden cross marker\nDEATH_CLR = \"#AE3030\"  # death cross marker\n\n# Data — realistic stock price with trend, consolidation, and recovery\nnp.random.seed(42)\nn_days = 120\n\ndates = pd.date_range(start=\"2024-01-02\", periods=n_days, freq=\"B\")\n\nbase_price = 150\nreturns = np.random.normal(0.001, 0.015, n_days)\ntrend = np.concatenate([np.linspace(0, 0.15, 40), np.linspace(0.15, 0.12, 30), np.linspace(0.12, 0.25, 50)])\nclose_prices = base_price * np.exp(np.cumsum(returns) + trend)\n\ndf = pd.DataFrame({\"date\": dates, \"close\": close_prices})\ndf[\"ema_12\"] = df[\"close\"].ewm(span=12, adjust=False).mean()\ndf[\"ema_26\"] = df[\"close\"].ewm(span=26, adjust=False).mean()\n\ncrossover_up = (df[\"ema_12\"] > df[\"ema_26\"]) & (df[\"ema_12\"].shift(1) <= df[\"ema_26\"].shift(1))\ncrossover_down = (df[\"ema_12\"] < df[\"ema_26\"]) & (df[\"ema_12\"].shift(1) >= df[\"ema_26\"].shift(1))\n\n# Plot\nfig = go.Figure()\n\nfig.add_trace(\n    go.Scatter(\n        x=df[\"date\"],\n        y=df[\"close\"],\n        mode=\"lines\",\n        name=\"Price\",\n        line={\"color\": BRAND, \"width\": 3},\n        hovertemplate=\"Date: %{x|%Y-%m-%d}<br>Price: $%{y:.2f}<extra></extra>\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=df[\"date\"],\n        y=df[\"ema_12\"],\n        mode=\"lines\",\n        name=\"EMA 12\",\n        line={\"color\": EMA_SHORT, \"width\": 2},\n        hovertemplate=\"Date: %{x|%Y-%m-%d}<br>EMA 12: $%{y:.2f}<extra></extra>\",\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=df[\"date\"],\n        y=df[\"ema_26\"],\n        mode=\"lines\",\n        name=\"EMA 26\",\n        line={\"color\": EMA_LONG, \"width\": 2},\n        hovertemplate=\"Date: %{x|%Y-%m-%d}<br>EMA 26: $%{y:.2f}<extra></extra>\",\n    )\n)\n\ngolden_cross = df[crossover_up]\nif len(golden_cross) > 0:\n    fig.add_trace(\n        go.Scatter(\n            x=golden_cross[\"date\"],\n            y=golden_cross[\"ema_12\"],\n            mode=\"markers\",\n            name=\"Golden Cross ▲\",\n            marker={\"color\": GOLDEN_CLR, \"size\": 16, \"symbol\": \"triangle-up\", \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n            hovertemplate=\"Golden Cross<br>Date: %{x|%Y-%m-%d}<br>EMA: $%{y:.2f}<extra></extra>\",\n        )\n    )\n\ndeath_cross = df[crossover_down]\nif len(death_cross) > 0:\n    fig.add_trace(\n        go.Scatter(\n            x=death_cross[\"date\"],\n            y=death_cross[\"ema_12\"],\n            mode=\"markers\",\n            name=\"Death Cross ▼\",\n            marker={\"color\": DEATH_CLR, \"size\": 16, \"symbol\": \"triangle-down\", \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n            hovertemplate=\"Death Cross<br>Date: %{x|%Y-%m-%d}<br>EMA: $%{y:.2f}<extra></extra>\",\n        )\n    )\n\n# Style — theme-adaptive chrome throughout\nfig.update_layout(\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    title={\n        \"text\": \"indicator-ema · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Date\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n        \"showgrid\": True,\n        \"rangeslider\": {\"visible\": True, \"bgcolor\": PAGE_BG, \"bordercolor\": INK_SOFT, \"thickness\": 0.08},\n    },\n    yaxis={\n        \"title\": {\"text\": \"Price (USD)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"tickformat\": \"$,.0f\",\n        \"gridcolor\": GRID,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n        \"showgrid\": True,\n    },\n    legend={\n        \"font\": {\"size\": 18, \"color\": INK_SOFT},\n        \"x\": 0.02,\n        \"y\": 0.98,\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    hovermode=\"x unified\",\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 80},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}