{"spec_id":"indicator-rsi","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nindicator-rsi: RSI Technical Indicator Chart\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-16\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_hline,\n    geom_line,\n    ggplot,\n    labs,\n    scale_x_datetime,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\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\"\nBRAND = \"#009E73\"\n\n# Data - Generate RSI values for 120 trading days\nnp.random.seed(42)\nn_days = 120\nperiod = 14\n\n# Generate synthetic price changes to calculate RSI\nprice_changes = np.random.normal(0, 1.5, n_days + period)\n\n# Calculate RSI using 14-period lookback\nrsi_values = []\nfor i in range(period, len(price_changes)):\n    window = price_changes[i - period : i]\n    gains = np.maximum(window, 0)\n    losses = np.abs(np.minimum(window, 0))\n    avg_gain = np.mean(gains)\n    avg_loss = np.mean(losses)\n    if avg_loss == 0:\n        rsi = 100\n    else:\n        rs = avg_gain / avg_loss\n        rsi = 100 - (100 / (1 + rs))\n    rsi_values.append(rsi)\nrsi_values = np.array(rsi_values)\n\n# Create date range (business days)\ndates = pd.date_range(start=\"2024-01-01\", periods=n_days, freq=\"B\")\n\ndf = pd.DataFrame({\"date\": dates, \"rsi\": rsi_values})\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"date\", y=\"rsi\"))\n    # Overbought zone (70-100) - light red shading\n    + annotate(\"rect\", xmin=dates.min(), xmax=dates.max(), ymin=70, ymax=100, fill=\"#FF6B6B\", alpha=0.2)\n    # Oversold zone (0-30) - light green shading\n    + annotate(\"rect\", xmin=dates.min(), xmax=dates.max(), ymin=0, ymax=30, fill=\"#4ECDC4\", alpha=0.2)\n    # Threshold lines\n    + geom_hline(yintercept=70, color=\"#D62828\", size=1, linetype=\"dashed\", alpha=0.8)\n    + geom_hline(yintercept=30, color=\"#2A9D8F\", size=1, linetype=\"dashed\", alpha=0.8)\n    + geom_hline(yintercept=50, color=INK_SOFT, size=0.8, linetype=\"dotted\", alpha=0.6)\n    # RSI line in brand color\n    + geom_line(color=BRAND, size=1.5, alpha=0.9)\n    # Axis settings\n    + scale_y_continuous(limits=(0, 100), breaks=range(0, 101, 10))\n    + scale_x_datetime(date_breaks=\"1 month\", date_labels=\"%b %Y\")\n    # Labels\n    + labs(title=\"indicator-rsi · plotnine · anyplot.ai\", x=\"Date\", y=\"RSI (14-period)\")\n    # Base theme\n    + theme_minimal()\n    # Theme-adaptive styling\n    + theme(\n        figure_size=(16, 9),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.08),\n        panel_grid_minor=element_blank(),\n        panel_border=element_blank(),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_line=element_line(color=INK_SOFT, size=0.5),\n        plot_title=element_text(size=24, weight=\"bold\", color=INK),\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=300, width=16, height=9)\n"}