{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "eabb2e65",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44c499db",
   "metadata": {},
   "source": [
    "This code streams real-time option quotes using the ThetaData API to calculate and print straddle prices for a specific option contract. It defines a callback function to handle incoming quote messages and update the bid, ask, and mid prices of the straddle. The main function initializes the ThetaClient, connects to the stream, and requests quote updates for both call and put options. This setup is useful for traders and analysts monitoring option prices and straddle strategies in real-time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db51b442",
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime as dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54c5fb62",
   "metadata": {},
   "outputs": [],
   "source": [
    "import thetadata.client\n",
    "from thetadata import (\n",
    "    Quote,\n",
    "    StreamMsg,\n",
    "    ThetaClient,\n",
    "    OptionRight,\n",
    "    StreamMsgType\n",
    ")\n",
    "from thetadata import StreamResponseType as ResponseType"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68ddfbd0",
   "metadata": {},
   "source": [
    "Initialize last call and put quotes and price variable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14880c60",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "last_call_quote = Quote()\n",
    "last_put_quote = Quote()\n",
    "price = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b319868",
   "metadata": {},
   "source": [
    "Callback function to handle incoming stream messages and update straddle prices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65f8ab69",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def callback_straddle(msg):\n",
    "    \"\"\"Handles incoming stream messages to update straddle prices.\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    msg : StreamMsg\n",
    "        Incoming stream message containing quote data.\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    None\n",
    "    \"\"\"\n",
    "\n",
    "    if (msg.type != StreamMsgType.QUOTE):\n",
    "        return\n",
    "\n",
    "    if msg.contract.isCall:\n",
    "        last_call_quote.copy_from(msg.quote)\n",
    "    else:\n",
    "        last_put_quote.copy_from(msg.quote)\n",
    "\n",
    "    straddle_bid = round(last_call_quote.bid_price + last_put_quote.bid_price, 2)\n",
    "    straddle_ask = round(last_call_quote.ask_price + last_put_quote.ask_price, 2)\n",
    "    straddle_mid = round((straddle_bid + straddle_ask) / 2, 2)\n",
    "    \n",
    "    time_stamp = thetadata.client.ms_to_time(\n",
    "        msg.quote.ms_of_day\n",
    "    )\n",
    "\n",
    "    if price != straddle_mid:\n",
    "        print(\n",
    "            f\"time: {time_stamp} bid: {straddle_bid} mid: {straddle_mid} ask: {straddle_ask}\"\n",
    "        )\n",
    "        price = straddle_mid"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09157b67",
   "metadata": {},
   "source": [
    "Main function to set up streaming for straddle prices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d963b0f",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def streaming_straddle():\n",
    "    \"\"\"Streams option quotes to calculate straddle prices in real-time.\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    None\n",
    "    \"\"\"\n",
    "    \n",
    "    client = ThetaClient(\n",
    "        username=\"strimp101@gmail.com\",\n",
    "        passwd=\"kdk_fzu6pyb0UZA-yuz\"\n",
    "    )\n",
    "\n",
    "    client.connect_stream(\n",
    "        callback_straddle\n",
    "    )\n",
    "    \n",
    "    req_id_call = client.req_quote_stream_opt(\n",
    "        \"SPY\", dt.date(2024, 3, 28), 475, OptionRight.CALL\n",
    "    )  # Request quote updates\n",
    "    \n",
    "    req_id_put = client.req_quote_stream_opt(\n",
    "        \"SPY\", dt.date(2024, 3, 28), 475, OptionRight.PUT\n",
    "    )\n",
    "\n",
    "    if (\n",
    "        client.verify(req_id_call) != ResponseType.SUBSCRIBED\n",
    "        or client.verify(req_id_put) != ResponseType.SUBSCRIBED\n",
    "    ):\n",
    "        raise Exception(\n",
    "            \"Unable to stream contract. A standard/PRO subscription required.\"\n",
    "        )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f08a4bc5",
   "metadata": {},
   "source": [
    "Call the main function to start streaming"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1bfbff7c",
   "metadata": {},
   "outputs": [],
   "source": [
    "streaming_straddle()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74a5b687",
   "metadata": {},
   "source": [
    "<a href=\"https://pyquantnews.com/\">PyQuant News</a> is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to <a href=\"https://gettingstartedwithpythonforquantfinance.com/\">get started with Python for quant finance</a>. For educational purposes. Not investment advise. Use at your own risk."
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
