{"spec_id":"kagi-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nkagi-basic: Basic Kagi Chart\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_segment,\n    ggplot,\n    ggsize,\n    labs,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\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_COLOR = \"rgba(26,26,23,0.08)\" if THEME == \"light\" else \"rgba(240,239,232,0.08)\"\n\n# Kagi chart colors (semantic meaning: green for bullish/up, red for bearish/down)\nYANG_COLOR = \"#009E73\"  # Green for bullish/uptrend (yang)\nYIN_COLOR = \"#E74C3C\"  # Red for bearish/downtrend (yin)\n\n# Generate synthetic stock price data\nnp.random.seed(42)\nn_days = 200\nreturns = np.random.normal(0.001, 0.02, n_days)\nprices = 100 * np.cumprod(1 + returns)\n\n# Kagi chart parameters\nreversal_threshold = 0.04  # 4% reversal threshold\n\n# Build Kagi chart segments from price data\nsegments = []\ndirection = 1  # 1 = up, -1 = down\nlast_high = prices[0]\nlast_low = prices[0]\ncurrent_price = prices[0]\nx_idx = 0\n\nfor price in prices[1:]:\n    if direction == 1:  # Currently in uptrend\n        if price > last_high:\n            last_high = price\n            current_price = price\n        elif price <= current_price * (1 - reversal_threshold):\n            # Add vertical yang (thick) line\n            segments.append({\"x1\": x_idx, \"y1\": last_low, \"x2\": x_idx, \"y2\": last_high, \"line_type\": \"yang\"})\n            x_idx += 1\n            # Add horizontal shoulder\n            segments.append({\"x1\": x_idx - 1, \"y1\": last_high, \"x2\": x_idx, \"y2\": last_high, \"line_type\": \"yang\"})\n            # Change direction\n            direction = -1\n            last_low = price\n            current_price = price\n    else:  # Currently in downtrend\n        if price < last_low:\n            last_low = price\n            current_price = price\n        elif price >= current_price * (1 + reversal_threshold):\n            # Add vertical yin (thin) line\n            segments.append({\"x1\": x_idx, \"y1\": last_high, \"x2\": x_idx, \"y2\": last_low, \"line_type\": \"yin\"})\n            x_idx += 1\n            # Add horizontal waist\n            segments.append({\"x1\": x_idx - 1, \"y1\": last_low, \"x2\": x_idx, \"y2\": last_low, \"line_type\": \"yin\"})\n            # Change direction\n            direction = 1\n            last_high = price\n            current_price = price\n\n# Add final segment\nif direction == 1:\n    segments.append({\"x1\": x_idx, \"y1\": last_low, \"x2\": x_idx, \"y2\": current_price, \"line_type\": \"yang\"})\nelse:\n    segments.append({\"x1\": x_idx, \"y1\": last_high, \"x2\": x_idx, \"y2\": current_price, \"line_type\": \"yin\"})\n\n# Create dataframe and separate by line type\nkagi_df = pd.DataFrame(segments)\nyang_df = kagi_df[kagi_df[\"line_type\"] == \"yang\"].copy()\nyin_df = kagi_df[kagi_df[\"line_type\"] == \"yin\"].copy()\n\n# Create the plot\nplot = (\n    ggplot()\n    + geom_segment(\n        aes(x=\"x1\", y=\"y1\", xend=\"x2\", yend=\"y2\"),\n        data=yang_df,\n        color=YANG_COLOR,\n        size=4,  # Thick line for yang\n    )\n    + geom_segment(\n        aes(x=\"x1\", y=\"y1\", xend=\"x2\", yend=\"y2\"),\n        data=yin_df,\n        color=YIN_COLOR,\n        size=1.5,  # Thin line for yin\n    )\n    + labs(title=\"kagi-basic · letsplot · anyplot.ai\", x=\"Line Index\", y=\"Price ($)\")\n    + theme_minimal()\n    + theme(\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=GRID_COLOR, size=0.3),\n        panel_grid_minor=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.4),\n        plot_title=element_text(size=24, color=INK),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_text=element_text(size=14, color=INK_SOFT),\n        legend_title=element_text(size=16, color=INK),\n    )\n    + ggsize(1600, 900)\n)\n\n# Save as PNG (scaled 3x for 4800x2700 px)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=3)\n\n# Save as HTML for interactive viewing\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}