{"spec_id":"indicator-macd","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nindicator-macd: MACD Technical Indicator Chart\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-16\n\"\"\"\n\nimport importlib.util\nimport os\nimport sys\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\n\n\n# Load altair from site-packages, bypassing the local altair.py file\nscript_dir = Path(__file__).parent\nspec = importlib.util.find_spec(\"altair\")\nif spec and spec.origin and \"site-packages\" in spec.origin:\n    alt = importlib.util.module_from_spec(spec)\n    sys.modules[\"altair\"] = alt\n    spec.loader.exec_module(alt)\nelse:\n    original_path = sys.path.copy()\n    sys.path = [p for p in sys.path if str(script_dir) not in p]\n    import altair as alt\n\n    sys.path = original_path\n\n\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\"\n\n# Data - Generate realistic stock price data and calculate MACD\nnp.random.seed(42)\nn_days = 150\n\n# Generate a random walk with moderate trend for closing prices\nreturns = np.random.normal(0.001, 0.015, n_days)\nprice = 100 * np.cumprod(1 + returns)\n\n# Calculate EMAs using pandas\nema_12 = pd.Series(price).ewm(span=12, adjust=False).mean().values\nema_26 = pd.Series(price).ewm(span=26, adjust=False).mean().values\nmacd_line = ema_12 - ema_26\nsignal_line = pd.Series(macd_line).ewm(span=9, adjust=False).mean().values\nhistogram = macd_line - signal_line\n\n# Create DataFrame with dates (skip first 26 days for meaningful MACD values)\nstart_idx = 26\ndates = pd.date_range(\"2025-06-01\", periods=n_days - start_idx, freq=\"D\")\n\ndf = pd.DataFrame(\n    {\n        \"date\": dates,\n        \"macd\": macd_line[start_idx:],\n        \"signal\": signal_line[start_idx:],\n        \"histogram\": histogram[start_idx:],\n    }\n)\n\n# Add color column for histogram\ndf[\"hist_color\"] = df[\"histogram\"].apply(lambda x: \"Positive\" if x >= 0 else \"Negative\")\n\n# Melt dataframe for line chart\ndf_lines = df.melt(id_vars=[\"date\"], value_vars=[\"macd\", \"signal\"], var_name=\"line_type\", value_name=\"value\")\n\n# Map line types to labels\nline_labels = {\"macd\": \"MACD (12, 26)\", \"signal\": \"Signal (9)\"}\ndf_lines[\"line_label\"] = df_lines[\"line_type\"].map(line_labels)\n\n# Create histogram chart with green/red coloring\nhistogram_chart = (\n    alt.Chart(df)\n    .mark_bar(size=8)\n    .encode(\n        x=alt.X(\"date:T\", title=\"Date\", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),\n        y=alt.Y(\"histogram:Q\", title=\"Value\", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),\n        color=alt.Color(\n            \"hist_color:N\",\n            scale=alt.Scale(domain=[\"Positive\", \"Negative\"], range=[\"#2E7D32\", \"#C62828\"]),\n            legend=alt.Legend(title=\"Histogram\", labelFontSize=14, titleFontSize=16),\n        ),\n        tooltip=[alt.Tooltip(\"date:T\", title=\"Date\"), alt.Tooltip(\"histogram:Q\", title=\"Histogram\", format=\".4f\")],\n    )\n)\n\n# Create MACD and Signal line chart\nline_chart = (\n    alt.Chart(df_lines)\n    .mark_line(strokeWidth=3)\n    .encode(\n        x=alt.X(\"date:T\", title=\"Date\"),\n        y=alt.Y(\"value:Q\", title=\"Value\"),\n        color=alt.Color(\n            \"line_label:N\",\n            scale=alt.Scale(domain=[\"MACD (12, 26)\", \"Signal (9)\"], range=[\"#4467A3\", \"#AE3030\"]),\n            legend=alt.Legend(title=\"Lines\", labelFontSize=14, titleFontSize=16),\n        ),\n        strokeDash=alt.StrokeDash(\n            \"line_label:N\", scale=alt.Scale(domain=[\"MACD (12, 26)\", \"Signal (9)\"], range=[[0], [8, 4]]), legend=None\n        ),\n        tooltip=[\n            alt.Tooltip(\"date:T\", title=\"Date\"),\n            alt.Tooltip(\"line_label:N\", title=\"Line\"),\n            alt.Tooltip(\"value:Q\", title=\"Value\", format=\".4f\"),\n        ],\n    )\n)\n\n# Create zero reference line\nzero_line = (\n    alt.Chart(pd.DataFrame({\"y\": [0]})).mark_rule(color=INK_SOFT, strokeWidth=1.5, strokeDash=[4, 4]).encode(y=\"y:Q\")\n)\n\n# Combine charts: histogram + lines + zero line\nchart = (\n    alt.layer(histogram_chart, line_chart, zero_line)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\n            \"indicator-macd · altair · anyplot.ai\",\n            fontSize=28,\n            anchor=\"middle\",\n            color=INK,\n            subtitle=\"MACD (12, 26, 9) - Moving Average Convergence Divergence\",\n            subtitleFontSize=18,\n            subtitleColor=INK_SOFT,\n        ),\n    )\n    .configure_axis(\n        labelFontSize=16,\n        titleFontSize=20,\n        gridColor=INK,\n        gridOpacity=0.10,\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=0)\n    .configure_legend(\n        labelFontSize=14,\n        titleFontSize=16,\n        orient=\"right\",\n        fillColor=ELEVATED_BG,\n        strokeColor=INK_SOFT,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n    )\n    .resolve_scale(color=\"independent\")\n)\n\n# Save outputs\nchart.save(str(script_dir / f\"plot-{THEME}.png\"), scale_factor=3.0)\nchart.save(str(script_dir / f\"plot-{THEME}.html\"))\n"}