DEV Community

Patrick DeVos
Patrick DeVos

Posted on

Build a VIX Options Trading Dashboard in Python (Free API)

The VIX — the CBOE Volatility Index — is the single most actionable indicator for options traders. When VIX spikes, options premiums explode. When VIX collapses, premium sellers get paid. Most traders watch it manually. This guide shows you how to automate it.

We'll use the SignalSage API on RapidAPI to pull live VIX-based signals and build a Python trading dashboard that tells you exactly what to do based on current market conditions.

What the Dashboard Does

  • Reads the current VIX regime (low/elevated/high)
  • Recommends the right options strategy for the environment
  • Identifies high-probability trade setups
  • Tracks the volatility magnet (mean-reversion signal)
  • Outputs a ranked action list every morning

Prerequisites

  • Python 3.8+
  • RapidAPI account (free tier works)
  • Basic options knowledge (know what an iron condor is)

Step 1: Get the API Key

  1. Sign up at RapidAPI
  2. Search "SignalSage"
  3. Subscribe to the free BASIC plan
  4. Copy your X-RapidAPI-Key

Step 2: Install Dependencies

pip install requests rich schedule
Enter fullscreen mode Exit fullscreen mode

Step 3: The Dashboard

import requests
import schedule
import time
from datetime import datetime
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box

console = Console()

RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY_HERE"
BASE_URL = "https://signalsage.p.rapidapi.com"
HEADERS = {
    "X-RapidAPI-Key": RAPIDAPI_KEY,
    "X-RapidAPI-Host": "signalsage.p.rapidapi.com"
}


def get_playbook():
    r = requests.get(f"{BASE_URL}/api/playbook", headers=HEADERS)
    r.raise_for_status()
    return r.json()


def get_setups():
    r = requests.get(f"{BASE_URL}/api/setups", headers=HEADERS)
    r.raise_for_status()
    return r.json()


def get_magnet():
    r = requests.get(f"{BASE_URL}/api/magnet", headers=HEADERS)
    r.raise_for_status()
    return r.json()


def vix_color(vix: float) -> str:
    if vix < 15:
        return "green"
    elif vix < 20:
        return "yellow"
    elif vix < 30:
        return "orange3"
    return "red"


def render_dashboard():
    console.clear()
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    console.print(f"\n[bold cyan]SignalSage Options Dashboard[/bold cyan]  [dim]{now}[/dim]\n")

    # --- PLAYBOOK ---
    pb = get_playbook()
    data = pb.get("data", {})
    overview = data.get("marketOverview", {})
    vix = overview.get("vix", 0)
    vix_analysis = overview.get("vixAnalysis", "")
    key_levels = overview.get("keyLevels", "")
    top_setups = data.get("topSetups", [])

    color = vix_color(vix)
    console.print(Panel(
        f"[{color}]VIX: {vix:.2f}[/{color}]   {vix_analysis}\n\n[dim]{key_levels}[/dim]",
        title="[bold]Market Overview[/bold]",
        border_style=color
    ))

    # --- SETUPS ---
    setups = get_setups()
    setup_list = setups.get("high_conviction_setups", [])

    if setup_list:
        table = Table(box=box.ROUNDED, show_header=True, header_style="bold magenta")
        table.add_column("Symbol", style="cyan", width=8)
        table.add_column("Strategy", width=20)
        table.add_column("Direction", width=12)
        table.add_column("Confidence", justify="right")
        table.add_column("Notes", width=35)

        for s in setup_list[:8]:
            conf = s.get("confidence", 0)
            conf_color = "green" if conf > 0.7 else "yellow" if conf > 0.5 else "white"
            table.add_row(
                s.get("symbol", ""),
                s.get("strategy", ""),
                s.get("direction", ""),
                f"[{conf_color}]{conf:.0%}[/{conf_color}]",
                s.get("notes", "")[:35]
            )

        console.print("\n[bold]High-Conviction Setups[/bold]")
        console.print(table)
    else:
        console.print(Panel(
            "[yellow]No high-conviction setups right now.\nVIX regime suggests waiting for better entries.[/yellow]",
            title="Setups",
            border_style="yellow"
        ))

    # --- MAGNET ---
    magnet = get_magnet()
    magnet_text = magnet.get("magnetAnalysis", "")
    # Show first 400 chars of the magnet analysis
    console.print(Panel(
        magnet_text[:400] + ("..." if len(magnet_text) > 400 else ""),
        title="[bold]Volatility Magnet[/bold]",
        border_style="blue"
    ))

    console.print("\n[dim]Refreshes every 5 minutes. Press Ctrl+C to exit.[/dim]")


def run():
    render_dashboard()
    schedule.every(5).minutes.do(render_dashboard)

    while True:
        schedule.run_pending()
        time.sleep(1)


if __name__ == "__main__":
    try:
        run()
    except KeyboardInterrupt:
        console.print("\n[dim]Dashboard stopped.[/dim]")
Enter fullscreen mode Exit fullscreen mode

Sample Output

SignalSage Options Dashboard  2026-06-06 09:31:00

╭─────────────────────── Market Overview ───────────────────────╮
│ VIX: 21.51   21.51 → IV elevated, avoid new trades           │
│                                                                │
│ SPY key levels: 580 / 570 / 560                               │
╰────────────────────────────────────────────────────────────────╯

High-Conviction Setups
╭────────┬──────────────────────┬────────────┬────────────┬─────────────────────────────────────╮
│ Symbol │ Strategy             │ Direction  │ Confidence │ Notes                               │
├────────┼──────────────────────┼────────────┼────────────┼─────────────────────────────────────┤
│ SPY    │ Iron Condor          │ Neutral    │ 78%        │ VIX elevated, sell both wings       │
│ QQQ    │ Put Credit Spread    │ Bullish    │ 65%        │ Support held at 200MA               │
╰────────┴──────────────────────┴────────────┴────────────┴─────────────────────────────────────╯
Enter fullscreen mode Exit fullscreen mode

VIX Regime Cheat Sheet

VIX Level Regime Best Strategy
< 15 Low volatility Buy straddles, avoid premium selling
15–20 Normal Iron condors, defined-risk spreads
20–30 Elevated Short strangles with wide strikes
> 30 Fear spike Sell puts on pullbacks, cash-secured

The general rule: sell premium when VIX is high, buy it when VIX is low. SignalSage automates this regime detection so you don't have to track it manually every morning.

Automate the Morning Brief

import smtplib
from email.mime.text import MIMEText

def email_brief(to_addr: str):
    pb = get_playbook()
    vix = pb["data"]["marketOverview"]["vix"]
    analysis = pb["data"]["marketOverview"]["vixAnalysis"]

    body = f"VIX: {vix}\n{analysis}\n\nRun your dashboard for full setups."

    msg = MIMEText(body)
    msg["Subject"] = f"Morning Options Brief — VIX {vix}"
    msg["From"] = "your@gmail.com"
    msg["To"] = to_addr

    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as s:
        s.login("your@gmail.com", "app-password")
        s.send_message(msg)
Enter fullscreen mode Exit fullscreen mode

Run it at 9 AM with cron: 0 9 * * 1-5 python brief.py


The API is live on RapidAPI — search "SignalSage" by Circle of Wizards. Free tier, no credit card required. PRO unlocks higher rate limits for algorithmic traders running this on a schedule.

Top comments (0)