{"spec_id":"indicator-rsi","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nindicator-rsi: RSI Technical Indicator Chart\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-16\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)\"\nBRAND = \"#009E73\"\n\n# Generate sample stock data and calculate RSI\nnp.random.seed(42)\ndates = pd.date_range(\"2024-01-01\", periods=120, freq=\"D\").strftime(\"%Y-%m-%d\")\n\n# Simulate price movement with trends\nreturns = np.random.randn(120) * 0.015\nreturns[20:40] += 0.01  # Bull run\nreturns[60:80] -= 0.012  # Bear period\nreturns[95:110] += 0.008  # Recovery\nprice = 100 * np.cumprod(1 + returns)\n\n# Calculate RSI (14-period)\ndelta = pd.Series(price).diff()\ngain = delta.where(delta > 0, 0)\nloss = (-delta).where(delta < 0, 0)\n\navg_gain = gain.rolling(window=14, min_periods=14).mean()\navg_loss = loss.rolling(window=14, min_periods=14).mean()\n\nrs = avg_gain / avg_loss\nrsi = 100 - (100 / (1 + rs))\nrsi = rsi.fillna(50)\n\n# Create figure\nfig = go.Figure()\n\n# Overbought zone (70-100)\nfig.add_trace(\n    go.Scatter(\n        x=dates, y=[100] * len(dates), fill=None, mode=\"lines\", line={\"width\": 0}, showlegend=False, hoverinfo=\"skip\"\n    )\n)\nfig.add_trace(\n    go.Scatter(\n        x=dates,\n        y=[70] * len(dates),\n        fill=\"tonexty\",\n        mode=\"lines\",\n        line={\"width\": 0},\n        fillcolor=\"rgba(196, 117, 253, 0.15)\",\n        name=\"Overbought Zone (70-100)\",\n    )\n)\n\n# Oversold zone (0-30)\nfig.add_trace(\n    go.Scatter(\n        x=dates, y=[30] * len(dates), fill=None, mode=\"lines\", line={\"width\": 0}, showlegend=False, hoverinfo=\"skip\"\n    )\n)\nfig.add_trace(\n    go.Scatter(\n        x=dates,\n        y=[0] * len(dates),\n        fill=\"tonexty\",\n        mode=\"lines\",\n        line={\"width\": 0},\n        fillcolor=\"rgba(0, 158, 115, 0.15)\",\n        name=\"Oversold Zone (0-30)\",\n    )\n)\n\n# RSI line\nfig.add_trace(go.Scatter(x=dates, y=rsi, mode=\"lines\", name=\"RSI (14)\", line={\"color\": BRAND, \"width\": 3}))\n\n# Add reference lines\nfig.add_hline(y=70, line_dash=\"dash\", line_color=\"#AE3030\", line_width=2)  # imprint red overbought\nfig.add_hline(y=50, line_dash=\"dot\", line_color=INK_SOFT, line_width=1.5)\nfig.add_hline(y=30, line_dash=\"dash\", line_color=\"#4467A3\", line_width=2)\n\n# Annotations for threshold lines\nfig.add_annotation(\n    x=dates[-1],\n    y=70,\n    text=\"Overbought (70)\",\n    showarrow=False,\n    xanchor=\"left\",\n    xshift=10,\n    font={\"size\": 16, \"color\": \"#AE3030\"},\n)\nfig.add_annotation(\n    x=dates[-1],\n    y=50,\n    text=\"Neutral (50)\",\n    showarrow=False,\n    xanchor=\"left\",\n    xshift=10,\n    font={\"size\": 14, \"color\": INK_SOFT},\n)\nfig.add_annotation(\n    x=dates[-1],\n    y=30,\n    text=\"Oversold (30)\",\n    showarrow=False,\n    xanchor=\"left\",\n    xshift=10,\n    font={\"size\": 16, \"color\": \"#4467A3\"},\n)\n\n# Layout\nfig.update_layout(\n    title={\n        \"text\": \"indicator-rsi · 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        \"showgrid\": True,\n        \"gridcolor\": GRID,\n    },\n    yaxis={\n        \"title\": {\"text\": \"RSI Value\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"range\": [0, 100],\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"dtick\": 10,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    legend={\n        \"orientation\": \"h\",\n        \"yanchor\": \"bottom\",\n        \"y\": 1.02,\n        \"xanchor\": \"center\",\n        \"x\": 0.5,\n        \"font\": {\"size\": 16, \"color\": INK_SOFT},\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    margin={\"l\": 80, \"r\": 120, \"t\": 100, \"b\": 80},\n)\n\n# Save outputs\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}