{"spec_id":"candlestick-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\ncandlestick-basic: Basic Candlestick Chart\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport plotly.graph_objects as go\n\n\n# Theme tokens (Imprint palette chrome)\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.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint semantic colors: finance gain→green, loss→red\nBULL_COLOR = \"#009E73\"  # Imprint position 1\nBEAR_COLOR = \"#AE3030\"  # Imprint position 5\n\n# Data — 30 trading days of ACME Corp simulated prices\nnp.random.seed(42)\ndates = pd.date_range(start=\"2024-01-02\", periods=30, freq=\"B\")\n\nprice = 150.0\ndrift = [0.4] * 8 + [-0.5] * 12 + [0.6] * 10  # rally, pullback, stronger recovery\nopens, highs, lows, closes = [], [], [], []\n\nfor i in range(30):\n    open_price = price\n    change = np.random.randn() * 2.5 + drift[i]\n    close_price = open_price + change\n    high_price = max(open_price, close_price) + abs(np.random.randn()) * 1.8\n    low_price = min(open_price, close_price) - abs(np.random.randn()) * 1.8\n    opens.append(open_price)\n    highs.append(high_price)\n    lows.append(low_price)\n    closes.append(close_price)\n    price = close_price\n\ndf = pd.DataFrame({\"date\": dates.strftime(\"%Y-%m-%d\"), \"open\": opens, \"high\": highs, \"low\": lows, \"close\": closes})\npeak_idx = df[\"high\"].idxmax()\nlow_idx = df[\"low\"].idxmin()\n\n# Title with length-scaled fontsize (default 16px at 67 chars)\ntitle_text = \"ACME Corp Daily Prices · candlestick-basic · python · plotly · anyplot.ai\"\ntitle_fs = max(round(16 * 67 / len(title_text)), 11)\n\n# Candlestick trace\nfig = go.Figure(\n    data=[\n        go.Candlestick(\n            x=df[\"date\"],\n            open=df[\"open\"],\n            high=df[\"high\"],\n            low=df[\"low\"],\n            close=df[\"close\"],\n            increasing={\"line\": {\"color\": BULL_COLOR, \"width\": 2}, \"fillcolor\": BULL_COLOR},\n            decreasing={\"line\": {\"color\": BEAR_COLOR, \"width\": 2}, \"fillcolor\": BEAR_COLOR},\n            hovertemplate=(\n                \"<b>%{x|%b %d, %Y}</b><br>\"\n                \"Open: $%{open:.2f}<br>\"\n                \"High: $%{high:.2f}<br>\"\n                \"Low: $%{low:.2f}<br>\"\n                \"Close: $%{close:.2f}<br>\"\n                \"<extra></extra>\"\n            ),\n        )\n    ]\n)\n\n# Key price annotations\nann_font = {\"size\": 10, \"color\": INK, \"family\": \"Arial\"}\nfig.add_annotation(\n    x=df.loc[peak_idx, \"date\"],\n    y=df.loc[peak_idx, \"high\"],\n    text=f\"Rally Peak<br>${df.loc[peak_idx, 'high']:.0f}\",\n    showarrow=True,\n    arrowhead=0,\n    arrowwidth=1.5,\n    arrowcolor=INK_SOFT,\n    ax=40,\n    ay=-45,\n    font=ann_font,\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=5,\n)\nfig.add_annotation(\n    x=df.loc[low_idx, \"date\"],\n    y=df.loc[low_idx, \"low\"],\n    text=f\"Pullback Low<br>${df.loc[low_idx, 'low']:.0f}\",\n    showarrow=True,\n    arrowhead=0,\n    arrowwidth=1.5,\n    arrowcolor=INK_SOFT,\n    ax=-40,\n    ay=50,\n    font=ann_font,\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=5,\n)\n\n# Market phase shaded regions\nphase_font = {\"size\": 10, \"color\": INK_SOFT, \"family\": \"Arial\"}\ndate_strs = df[\"date\"].tolist()\nfig.add_vrect(\n    x0=date_strs[0],\n    x1=date_strs[7],\n    fillcolor=BULL_COLOR,\n    opacity=0.05,\n    line_width=0,\n    annotation_text=\"Rally\",\n    annotation_position=\"top left\",\n    annotation_font=phase_font,\n)\nfig.add_vrect(\n    x0=date_strs[8],\n    x1=date_strs[19],\n    fillcolor=BEAR_COLOR,\n    opacity=0.05,\n    line_width=0,\n    annotation_text=\"Pullback\",\n    annotation_position=\"top left\",\n    annotation_font=phase_font,\n)\nfig.add_vrect(\n    x0=date_strs[20],\n    x1=date_strs[29],\n    fillcolor=BULL_COLOR,\n    opacity=0.05,\n    line_width=0,\n    annotation_text=\"Recovery\",\n    annotation_position=\"top left\",\n    annotation_font=phase_font,\n)\n\nfig.update_layout(\n    autosize=False,\n    template=\"plotly_white\",\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"family\": \"Arial\", \"color\": INK},\n    title={\n        \"text\": title_text,\n        \"font\": {\"size\": title_fs, \"color\": INK, \"family\": \"Arial\"},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Date\", \"font\": {\"size\": 12, \"color\": INK, \"family\": \"Arial\"}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT, \"family\": \"Arial\"},\n        \"tickformat\": \"%b %d\",\n        \"rangeslider\": {\"visible\": False},\n        \"rangebreaks\": [{\"bounds\": [\"sat\", \"mon\"]}],\n        \"showgrid\": False,\n        \"showline\": False,\n        \"zeroline\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Price (USD)\", \"font\": {\"size\": 12, \"color\": INK, \"family\": \"Arial\"}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT, \"family\": \"Arial\"},\n        \"tickprefix\": \"$\",\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"showline\": False,\n    },\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 60},\n    hoverlabel={\"bgcolor\": ELEVATED_BG, \"font_size\": 10, \"bordercolor\": INK_SOFT},\n)\n\n# Save — 3200×1800 landscape (width=800 × scale=4)\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}