diff --git a/notebooks/multiple-options-historical-test.ipynb b/notebooks/multiple-options-historical-test.ipynb
new file mode 100644
index 0000000..3397f2f
--- /dev/null
+++ b/notebooks/multiple-options-historical-test.ipynb
@@ -0,0 +1,1746 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "563c124a",
+ "metadata": {
+ "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
+ "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
+ "papermill": {
+ "duration": 0.037344,
+ "end_time": "2023-02-27T05:31:50.171956",
+ "exception": false,
+ "start_time": "2023-02-27T05:31:50.134612",
+ "status": "completed"
+ },
+ "tags": []
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "data/spy-options-data-2020-2022/spy_2020_2022.csv\n",
+ "data/qqq-options-data-2020-2022/qqq_2020_2022.csv\n"
+ ]
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import os\n",
+ "import pandas as pd\n",
+ "import pandas_ta as ta\n",
+ "\n",
+ "%matplotlib widget\n",
+ "pd.options.display.max_columns = 100\n",
+ "pd.options.display.max_rows = 100\n",
+ "\n",
+ "product_data = {\n",
+ " \"SPY\": {\n",
+ " \"directory_path\": \"data/spy-options-data-2020-2022\",\n",
+ " \"df_raw\": None,\n",
+ " \"df_final\": None,\n",
+ " \"df_option_history\": None,\n",
+ " },\n",
+ " \"QQQ\": {\n",
+ " \"directory_path\": \"data/qqq-options-data-2020-2022\",\n",
+ " \"df_raw\": None,\n",
+ " \"df_final\": None,\n",
+ " \"df_option_history\": None,\n",
+ " },\n",
+ "}\n",
+ "\n",
+ "for product_id in product_data.keys():\n",
+ " dfs = []\n",
+ "\n",
+ " for dirname, _, filenames in os.walk(product_data[product_id][\"directory_path\"]):\n",
+ " for filename in filenames:\n",
+ " data_path = os.path.join(dirname, filename)\n",
+ " print(data_path)\n",
+ " dfs.append(pd.read_csv(data_path, low_memory=False))\n",
+ "\n",
+ " df_raw = pd.concat(dfs)\n",
+ " columns = df_raw.columns\n",
+ " columns = [s.replace(\"[\", \"\") for s in columns]\n",
+ " columns = [s.replace(\"]\", \"\") for s in columns]\n",
+ " columns = [s.replace(\" \", \"\") for s in columns]\n",
+ " df_raw.columns = columns\n",
+ "\n",
+ " product_data[product_id][\"df_raw\"] = df_raw"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "4e199f2c",
+ "metadata": {
+ "papermill": {
+ "duration": 10.257179,
+ "end_time": "2023-02-27T05:32:14.035264",
+ "exception": false,
+ "start_time": "2023-02-27T05:32:03.778085",
+ "status": "completed"
+ },
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "for product_id in product_data.keys():\n",
+ " df_raw = product_data[product_id][\"df_raw\"]\n",
+ " date_columns = [\"QUOTE_READTIME\", \"QUOTE_DATE\", \"EXPIRE_DATE\"]\n",
+ " numeric_cols = df_raw.columns.to_list()\n",
+ " numeric_cols.remove(\"QUOTE_READTIME\")\n",
+ " numeric_cols.remove(\"QUOTE_DATE\")\n",
+ " numeric_cols.remove(\"EXPIRE_DATE\")\n",
+ "\n",
+ " df_numeric = df_raw.drop(columns=date_columns)\n",
+ "\n",
+ " for i in numeric_cols:\n",
+ " df_numeric[i] = pd.to_numeric(df_numeric[i], errors=\"coerce\")\n",
+ "\n",
+ " df_final = df_numeric.drop(columns=[\"C_SIZE\", \"P_SIZE\"])\n",
+ " product_data[product_id][\"df_final\"] = df_final"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "7aa6169d-117f-4b6b-8ff7-668533d80d7a",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Retrieving historical ETF fear and greed index\n",
+ "Retrieving historical ETF fear and greed index\n"
+ ]
+ }
+ ],
+ "source": [
+ "for product_id in product_data.keys():\n",
+ " df_final = product_data[product_id][\"df_final\"]\n",
+ " df_option_history = df_final.copy()\n",
+ "\n",
+ " df_option_history[\"EXPIRE_UNIX\"] = pd.to_datetime(df_option_history.EXPIRE_UNIX, unit=\"s\", utc=True)\n",
+ " df_option_history[\"QUOTE_UNIXTIME\"] = pd.to_datetime(df_option_history.QUOTE_UNIXTIME, unit=\"s\", utc=True).apply(\n",
+ " lambda x: pd.Timestamp(x).round(freq=\"D\")\n",
+ " )\n",
+ "\n",
+ " df_option_history.set_index(pd.DatetimeIndex(df_option_history.QUOTE_UNIXTIME), inplace=True)\n",
+ " df_option_history.drop(columns=[\"QUOTE_UNIXTIME\"], inplace=True)\n",
+ " df_option_history.sort_index(inplace=True)\n",
+ "\n",
+ " df_option_history[\"UNDERLYING_PRODUCT_ID\"] = product_id\n",
+ " df_option_history[\"OPTION_ID\"] = (\n",
+ " df_option_history[\"UNDERLYING_PRODUCT_ID\"]\n",
+ " + df_option_history[\"EXPIRE_UNIX\"].astype(str)\n",
+ " + df_option_history[\"STRIKE\"].astype(str)\n",
+ " )\n",
+ " df_option_history[\"OPTION_ID\"] = df_option_history[\"OPTION_ID\"].apply(lambda x: hash(x))\n",
+ "\n",
+ " def get_df_cnn_fear_greed_index():\n",
+ " print(\"Retrieving historical ETF fear and greed index\")\n",
+ " import json\n",
+ "\n",
+ " with open(\"cnn_fear_greed_index_data.json\") as f:\n",
+ " cnn_fear_greed_index_data = json.load(f)\n",
+ "\n",
+ " df_fear_greed_index = pd.DataFrame(\n",
+ " data=cnn_fear_greed_index_data[\"data\"][\"c:50108\"][\"series\"][0], columns=[\"x\", \"y\"]\n",
+ " )\n",
+ " df_fear_greed_index.set_index(\n",
+ " pd.DatetimeIndex([pd.Timestamp(x, unit=\"s\", tz=\"UTC\") for x in df_fear_greed_index.x]),\n",
+ " inplace=True,\n",
+ " )\n",
+ " df_fear_greed_index.rename(columns={\"y\": \"fear_greed_index\"}, inplace=True)\n",
+ " df_fear_greed_index[\"fear_greed_index\"] = df_fear_greed_index.fear_greed_index.astype(float).round()\n",
+ " return df_fear_greed_index\n",
+ "\n",
+ " df_fear_greed_index = get_df_cnn_fear_greed_index()\n",
+ " df_option_history = df_option_history.join(df_fear_greed_index, how=\"inner\")\n",
+ "\n",
+ " df_history = df_option_history.groupby(df_option_history.index).first()[[\"UNDERLYING_LAST\", \"fear_greed_index\"]]\n",
+ " # df_history = df_option_history.groupby(df_option_history.index).first()[[\"UNDERLYING_LAST\"]]\n",
+ " df_history.rename(columns={\"UNDERLYING_LAST\": \"close\"}, inplace=True)\n",
+ "\n",
+ " CustomStrategy = ta.Strategy(\n",
+ " name=\"RSI\",\n",
+ " ta=[\n",
+ " {\"kind\": \"rsi\", \"length\": 14},\n",
+ " ],\n",
+ " )\n",
+ " df_history.ta.strategy(CustomStrategy)\n",
+ "\n",
+ " for column in [\"close\", \"fear_greed_index\", \"RSI_14\"]:\n",
+ " for days in [14]:\n",
+ " periods = days\n",
+ " df_history[f\"{column}_min_{days}\"] = df_history[column].rolling(window=periods, min_periods=periods).min()\n",
+ " df_history[f\"{column}_max_{days}\"] = df_history[column].rolling(window=periods, min_periods=periods).max()\n",
+ "\n",
+ " # df_option_history = df_option_history.join(df_history, how=\"inner\")\n",
+ " df_option_history = df_option_history.join(df_history.drop(columns=[\"fear_greed_index\"]), how=\"inner\")\n",
+ " df_option_history[\"index\"] = df_option_history.index\n",
+ " df_option_history.sort_values(by=[\"index\", \"EXPIRE_UNIX\", \"DTE\", \"STRIKE_DISTANCE_PCT\"], inplace=True)\n",
+ "\n",
+ " product_data[product_id][\"df_option_history\"] = df_option_history"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "094e8869-7d66-4c91-b590-a1e00c9d5a92",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " QUOTE_TIME_HOURS | \n",
+ " UNDERLYING_LAST | \n",
+ " EXPIRE_UNIX | \n",
+ " DTE | \n",
+ " C_DELTA | \n",
+ " C_GAMMA | \n",
+ " C_VEGA | \n",
+ " C_THETA | \n",
+ " C_RHO | \n",
+ " C_IV | \n",
+ " C_VOLUME | \n",
+ " C_LAST | \n",
+ " C_BID | \n",
+ " C_ASK | \n",
+ " STRIKE | \n",
+ " P_BID | \n",
+ " P_ASK | \n",
+ " P_LAST | \n",
+ " P_DELTA | \n",
+ " P_GAMMA | \n",
+ " P_VEGA | \n",
+ " P_THETA | \n",
+ " P_RHO | \n",
+ " P_IV | \n",
+ " P_VOLUME | \n",
+ " STRIKE_DISTANCE | \n",
+ " STRIKE_DISTANCE_PCT | \n",
+ " UNDERLYING_PRODUCT_ID | \n",
+ " OPTION_ID | \n",
+ " x | \n",
+ " fear_greed_index | \n",
+ " close | \n",
+ " RSI_14 | \n",
+ " close_min_14 | \n",
+ " close_max_14 | \n",
+ " fear_greed_index_min_14 | \n",
+ " fear_greed_index_max_14 | \n",
+ " RSI_14_min_14 | \n",
+ " RSI_14_max_14 | \n",
+ " index | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 324.44 | \n",
+ " 2021-05-17 20:00:00+00:00 | \n",
+ " 0.0 | \n",
+ " 1.00000 | \n",
+ " 0.00000 | \n",
+ " 0.00000 | \n",
+ " -0.00035 | \n",
+ " 0.00694 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 0.35 | \n",
+ " 0.34 | \n",
+ " 0.44 | \n",
+ " 324.0 | \n",
+ " 0.03 | \n",
+ " 0.07 | \n",
+ " 0.04 | \n",
+ " -0.18585 | \n",
+ " 0.54261 | \n",
+ " 0.03924 | \n",
+ " -0.05014 | \n",
+ " -0.00094 | \n",
+ " 0.03353 | \n",
+ " NaN | \n",
+ " 0.4 | \n",
+ " 0.001 | \n",
+ " QQQ | \n",
+ " -8578305565234411172 | \n",
+ " 2021-05-18 | \n",
+ " 35.0 | \n",
+ " 324.44 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 324.44 | \n",
+ " 2021-05-17 20:00:00+00:00 | \n",
+ " 0.0 | \n",
+ " 0.09826 | \n",
+ " 0.40027 | \n",
+ " 0.02551 | \n",
+ " -0.02006 | \n",
+ " 0.00069 | \n",
+ " 0.03015 | \n",
+ " NaN | \n",
+ " 0.02 | \n",
+ " 0.01 | \n",
+ " 0.04 | \n",
+ " 325.0 | \n",
+ " 0.61 | \n",
+ " 0.76 | \n",
+ " 0.79 | \n",
+ " -0.74789 | \n",
+ " 0.38048 | \n",
+ " 0.04665 | \n",
+ " -0.12534 | \n",
+ " -0.00433 | \n",
+ " 0.05740 | \n",
+ " NaN | \n",
+ " 0.6 | \n",
+ " 0.002 | \n",
+ " QQQ | \n",
+ " -3912251940911432638 | \n",
+ " 2021-05-18 | \n",
+ " 35.0 | \n",
+ " 324.44 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 324.44 | \n",
+ " 2021-05-17 20:00:00+00:00 | \n",
+ " 0.0 | \n",
+ " 0.03029 | \n",
+ " 0.08312 | \n",
+ " 0.01023 | \n",
+ " -0.01026 | \n",
+ " -0.00003 | \n",
+ " 0.05774 | \n",
+ " NaN | \n",
+ " 0.03 | \n",
+ " 0.02 | \n",
+ " 0.02 | \n",
+ " 326.0 | \n",
+ " 1.56 | \n",
+ " 1.71 | \n",
+ " 1.84 | \n",
+ " -0.87522 | \n",
+ " 0.14638 | \n",
+ " 0.02973 | \n",
+ " -0.08046 | \n",
+ " -0.00473 | \n",
+ " 0.09216 | \n",
+ " 481.0 | \n",
+ " 1.6 | \n",
+ " 0.005 | \n",
+ " QQQ | \n",
+ " -796774111719326768 | \n",
+ " 2021-05-18 | \n",
+ " 35.0 | \n",
+ " 324.44 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 324.44 | \n",
+ " 2021-05-17 20:00:00+00:00 | \n",
+ " 0.0 | \n",
+ " 1.00000 | \n",
+ " 0.00000 | \n",
+ " 0.00000 | \n",
+ " -0.00017 | \n",
+ " 0.00682 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2.38 | \n",
+ " 2.26 | \n",
+ " 2.42 | \n",
+ " 322.0 | \n",
+ " 0.02 | \n",
+ " 0.03 | \n",
+ " 0.01 | \n",
+ " -0.02943 | \n",
+ " 0.05143 | \n",
+ " 0.00999 | \n",
+ " -0.01417 | \n",
+ " -0.00016 | \n",
+ " 0.08914 | \n",
+ " NaN | \n",
+ " 2.4 | \n",
+ " 0.008 | \n",
+ " QQQ | \n",
+ " -8305044159569129464 | \n",
+ " 2021-05-18 | \n",
+ " 35.0 | \n",
+ " 324.44 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 324.44 | \n",
+ " 2021-05-17 20:00:00+00:00 | \n",
+ " 0.0 | \n",
+ " 0.00953 | \n",
+ " 0.01719 | \n",
+ " 0.00381 | \n",
+ " -0.00535 | \n",
+ " -0.00039 | \n",
+ " 0.10426 | \n",
+ " NaN | \n",
+ " 0.01 | \n",
+ " 0.00 | \n",
+ " 0.01 | \n",
+ " 328.0 | \n",
+ " 3.54 | \n",
+ " 3.70 | \n",
+ " 4.03 | \n",
+ " -0.92770 | \n",
+ " 0.04573 | \n",
+ " 0.02007 | \n",
+ " -0.06009 | \n",
+ " -0.00385 | \n",
+ " 0.16061 | \n",
+ " 130.0 | \n",
+ " 3.6 | \n",
+ " 0.011 | \n",
+ " QQQ | \n",
+ " -1070438577502752343 | \n",
+ " 2021-05-18 | \n",
+ " 35.0 | \n",
+ " 324.44 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 2021-05-18 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 382.44 | \n",
+ " 2025-12-19 21:00:00+00:00 | \n",
+ " 1085.0 | \n",
+ " 0.10595 | \n",
+ " 0.00150 | \n",
+ " 1.19348 | \n",
+ " -0.01204 | \n",
+ " 1.05129 | \n",
+ " 0.17770 | \n",
+ " 2.0 | \n",
+ " 5.71 | \n",
+ " 0.59 | \n",
+ " 10.00 | \n",
+ " 630.0 | \n",
+ " 243.00 | \n",
+ " 250.50 | \n",
+ " 0.00 | \n",
+ " -1.00000 | \n",
+ " 0.00000 | \n",
+ " 0.00000 | \n",
+ " 0.00000 | \n",
+ " 0.00000 | \n",
+ " NaN | \n",
+ " NaN | \n",
+ " 247.6 | \n",
+ " 0.647 | \n",
+ " SPY | \n",
+ " -2602091060095401525 | \n",
+ " 2022-12-31 | \n",
+ " 38.0 | \n",
+ " 382.44 | \n",
+ " 44.376002 | \n",
+ " 376.71 | \n",
+ " 401.95 | \n",
+ " 36.0 | \n",
+ " 61.0 | \n",
+ " 37.972031 | \n",
+ " 56.545485 | \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 382.44 | \n",
+ " 2025-12-19 21:00:00+00:00 | \n",
+ " 1085.0 | \n",
+ " 0.09392 | \n",
+ " 0.00140 | \n",
+ " 1.09723 | \n",
+ " -0.01082 | \n",
+ " 0.94207 | \n",
+ " 0.17304 | \n",
+ " NaN | \n",
+ " 0.00 | \n",
+ " 2.00 | \n",
+ " 7.00 | \n",
+ " 635.0 | \n",
+ " 247.66 | \n",
+ " 257.50 | \n",
+ " 0.00 | \n",
+ " -0.89431 | \n",
+ " 0.00307 | \n",
+ " 0.72687 | \n",
+ " -0.00434 | \n",
+ " -0.20330 | \n",
+ " 0.29557 | \n",
+ " NaN | \n",
+ " 252.6 | \n",
+ " 0.660 | \n",
+ " SPY | \n",
+ " -2872950415384401199 | \n",
+ " 2022-12-31 | \n",
+ " 38.0 | \n",
+ " 382.44 | \n",
+ " 44.376002 | \n",
+ " 376.71 | \n",
+ " 401.95 | \n",
+ " 36.0 | \n",
+ " 61.0 | \n",
+ " 37.972031 | \n",
+ " 56.545485 | \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 382.44 | \n",
+ " 2025-12-19 21:00:00+00:00 | \n",
+ " 1085.0 | \n",
+ " 0.09279 | \n",
+ " 0.00137 | \n",
+ " 1.08956 | \n",
+ " -0.01114 | \n",
+ " 0.93199 | \n",
+ " 0.17558 | \n",
+ " NaN | \n",
+ " 0.00 | \n",
+ " 2.00 | \n",
+ " 7.00 | \n",
+ " 640.0 | \n",
+ " 253.00 | \n",
+ " 262.50 | \n",
+ " 0.00 | \n",
+ " -0.88536 | \n",
+ " 0.00298 | \n",
+ " 0.78662 | \n",
+ " -0.00524 | \n",
+ " -1.78777 | \n",
+ " 0.30289 | \n",
+ " NaN | \n",
+ " 257.6 | \n",
+ " 0.673 | \n",
+ " SPY | \n",
+ " -6162682096078852249 | \n",
+ " 2022-12-31 | \n",
+ " 38.0 | \n",
+ " 382.44 | \n",
+ " 44.376002 | \n",
+ " 376.71 | \n",
+ " 401.95 | \n",
+ " 36.0 | \n",
+ " 61.0 | \n",
+ " 37.972031 | \n",
+ " 56.545485 | \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 382.44 | \n",
+ " 2025-12-19 21:00:00+00:00 | \n",
+ " 1085.0 | \n",
+ " 0.09938 | \n",
+ " 0.00147 | \n",
+ " 1.14502 | \n",
+ " -0.01128 | \n",
+ " 0.99068 | \n",
+ " 0.18239 | \n",
+ " 3.0 | \n",
+ " 4.33 | \n",
+ " 0.12 | \n",
+ " 10.00 | \n",
+ " 645.0 | \n",
+ " 258.00 | \n",
+ " 267.50 | \n",
+ " 0.00 | \n",
+ " -0.88264 | \n",
+ " 0.00287 | \n",
+ " 0.79928 | \n",
+ " -0.00538 | \n",
+ " -1.82985 | \n",
+ " 0.30699 | \n",
+ " NaN | \n",
+ " 262.6 | \n",
+ " 0.687 | \n",
+ " SPY | \n",
+ " 3937355187600415841 | \n",
+ " 2022-12-31 | \n",
+ " 38.0 | \n",
+ " 382.44 | \n",
+ " 44.376002 | \n",
+ " 376.71 | \n",
+ " 401.95 | \n",
+ " 36.0 | \n",
+ " 61.0 | \n",
+ " 37.972031 | \n",
+ " 56.545485 | \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ " 16.0 | \n",
+ " 382.44 | \n",
+ " 2025-12-19 21:00:00+00:00 | \n",
+ " 1085.0 | \n",
+ " 0.11433 | \n",
+ " 0.00149 | \n",
+ " 1.25917 | \n",
+ " -0.01324 | \n",
+ " 1.11689 | \n",
+ " 0.19561 | \n",
+ " 2.0 | \n",
+ " 4.15 | \n",
+ " 2.60 | \n",
+ " 10.00 | \n",
+ " 650.0 | \n",
+ " 262.75 | \n",
+ " 272.50 | \n",
+ " 0.00 | \n",
+ " -0.88467 | \n",
+ " 0.00288 | \n",
+ " 0.78257 | \n",
+ " -0.00516 | \n",
+ " -0.63195 | \n",
+ " 0.31007 | \n",
+ " NaN | \n",
+ " 267.6 | \n",
+ " 0.700 | \n",
+ " SPY | \n",
+ " 4608604951368675058 | \n",
+ " 2022-12-31 | \n",
+ " 38.0 | \n",
+ " 382.44 | \n",
+ " 44.376002 | \n",
+ " 376.71 | \n",
+ " 401.95 | \n",
+ " 36.0 | \n",
+ " 61.0 | \n",
+ " 37.972031 | \n",
+ " 56.545485 | \n",
+ " 2022-12-31 00:00:00+00:00 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
2924028 rows × 40 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " QUOTE_TIME_HOURS UNDERLYING_LAST \\\n",
+ "2021-05-18 00:00:00+00:00 16.0 324.44 \n",
+ "2021-05-18 00:00:00+00:00 16.0 324.44 \n",
+ "2021-05-18 00:00:00+00:00 16.0 324.44 \n",
+ "2021-05-18 00:00:00+00:00 16.0 324.44 \n",
+ "2021-05-18 00:00:00+00:00 16.0 324.44 \n",
+ "... ... ... \n",
+ "2022-12-31 00:00:00+00:00 16.0 382.44 \n",
+ "2022-12-31 00:00:00+00:00 16.0 382.44 \n",
+ "2022-12-31 00:00:00+00:00 16.0 382.44 \n",
+ "2022-12-31 00:00:00+00:00 16.0 382.44 \n",
+ "2022-12-31 00:00:00+00:00 16.0 382.44 \n",
+ "\n",
+ " EXPIRE_UNIX DTE C_DELTA C_GAMMA \\\n",
+ "2021-05-18 00:00:00+00:00 2021-05-17 20:00:00+00:00 0.0 1.00000 0.00000 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-17 20:00:00+00:00 0.0 0.09826 0.40027 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-17 20:00:00+00:00 0.0 0.03029 0.08312 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-17 20:00:00+00:00 0.0 1.00000 0.00000 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-17 20:00:00+00:00 0.0 0.00953 0.01719 \n",
+ "... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 2025-12-19 21:00:00+00:00 1085.0 0.10595 0.00150 \n",
+ "2022-12-31 00:00:00+00:00 2025-12-19 21:00:00+00:00 1085.0 0.09392 0.00140 \n",
+ "2022-12-31 00:00:00+00:00 2025-12-19 21:00:00+00:00 1085.0 0.09279 0.00137 \n",
+ "2022-12-31 00:00:00+00:00 2025-12-19 21:00:00+00:00 1085.0 0.09938 0.00147 \n",
+ "2022-12-31 00:00:00+00:00 2025-12-19 21:00:00+00:00 1085.0 0.11433 0.00149 \n",
+ "\n",
+ " C_VEGA C_THETA C_RHO C_IV C_VOLUME \\\n",
+ "2021-05-18 00:00:00+00:00 0.00000 -0.00035 0.00694 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 0.02551 -0.02006 0.00069 0.03015 NaN \n",
+ "2021-05-18 00:00:00+00:00 0.01023 -0.01026 -0.00003 0.05774 NaN \n",
+ "2021-05-18 00:00:00+00:00 0.00000 -0.00017 0.00682 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 0.00381 -0.00535 -0.00039 0.10426 NaN \n",
+ "... ... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 1.19348 -0.01204 1.05129 0.17770 2.0 \n",
+ "2022-12-31 00:00:00+00:00 1.09723 -0.01082 0.94207 0.17304 NaN \n",
+ "2022-12-31 00:00:00+00:00 1.08956 -0.01114 0.93199 0.17558 NaN \n",
+ "2022-12-31 00:00:00+00:00 1.14502 -0.01128 0.99068 0.18239 3.0 \n",
+ "2022-12-31 00:00:00+00:00 1.25917 -0.01324 1.11689 0.19561 2.0 \n",
+ "\n",
+ " C_LAST C_BID C_ASK STRIKE P_BID P_ASK \\\n",
+ "2021-05-18 00:00:00+00:00 0.35 0.34 0.44 324.0 0.03 0.07 \n",
+ "2021-05-18 00:00:00+00:00 0.02 0.01 0.04 325.0 0.61 0.76 \n",
+ "2021-05-18 00:00:00+00:00 0.03 0.02 0.02 326.0 1.56 1.71 \n",
+ "2021-05-18 00:00:00+00:00 2.38 2.26 2.42 322.0 0.02 0.03 \n",
+ "2021-05-18 00:00:00+00:00 0.01 0.00 0.01 328.0 3.54 3.70 \n",
+ "... ... ... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 5.71 0.59 10.00 630.0 243.00 250.50 \n",
+ "2022-12-31 00:00:00+00:00 0.00 2.00 7.00 635.0 247.66 257.50 \n",
+ "2022-12-31 00:00:00+00:00 0.00 2.00 7.00 640.0 253.00 262.50 \n",
+ "2022-12-31 00:00:00+00:00 4.33 0.12 10.00 645.0 258.00 267.50 \n",
+ "2022-12-31 00:00:00+00:00 4.15 2.60 10.00 650.0 262.75 272.50 \n",
+ "\n",
+ " P_LAST P_DELTA P_GAMMA P_VEGA P_THETA \\\n",
+ "2021-05-18 00:00:00+00:00 0.04 -0.18585 0.54261 0.03924 -0.05014 \n",
+ "2021-05-18 00:00:00+00:00 0.79 -0.74789 0.38048 0.04665 -0.12534 \n",
+ "2021-05-18 00:00:00+00:00 1.84 -0.87522 0.14638 0.02973 -0.08046 \n",
+ "2021-05-18 00:00:00+00:00 0.01 -0.02943 0.05143 0.00999 -0.01417 \n",
+ "2021-05-18 00:00:00+00:00 4.03 -0.92770 0.04573 0.02007 -0.06009 \n",
+ "... ... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 0.00 -1.00000 0.00000 0.00000 0.00000 \n",
+ "2022-12-31 00:00:00+00:00 0.00 -0.89431 0.00307 0.72687 -0.00434 \n",
+ "2022-12-31 00:00:00+00:00 0.00 -0.88536 0.00298 0.78662 -0.00524 \n",
+ "2022-12-31 00:00:00+00:00 0.00 -0.88264 0.00287 0.79928 -0.00538 \n",
+ "2022-12-31 00:00:00+00:00 0.00 -0.88467 0.00288 0.78257 -0.00516 \n",
+ "\n",
+ " P_RHO P_IV P_VOLUME STRIKE_DISTANCE \\\n",
+ "2021-05-18 00:00:00+00:00 -0.00094 0.03353 NaN 0.4 \n",
+ "2021-05-18 00:00:00+00:00 -0.00433 0.05740 NaN 0.6 \n",
+ "2021-05-18 00:00:00+00:00 -0.00473 0.09216 481.0 1.6 \n",
+ "2021-05-18 00:00:00+00:00 -0.00016 0.08914 NaN 2.4 \n",
+ "2021-05-18 00:00:00+00:00 -0.00385 0.16061 130.0 3.6 \n",
+ "... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 0.00000 NaN NaN 247.6 \n",
+ "2022-12-31 00:00:00+00:00 -0.20330 0.29557 NaN 252.6 \n",
+ "2022-12-31 00:00:00+00:00 -1.78777 0.30289 NaN 257.6 \n",
+ "2022-12-31 00:00:00+00:00 -1.82985 0.30699 NaN 262.6 \n",
+ "2022-12-31 00:00:00+00:00 -0.63195 0.31007 NaN 267.6 \n",
+ "\n",
+ " STRIKE_DISTANCE_PCT UNDERLYING_PRODUCT_ID \\\n",
+ "2021-05-18 00:00:00+00:00 0.001 QQQ \n",
+ "2021-05-18 00:00:00+00:00 0.002 QQQ \n",
+ "2021-05-18 00:00:00+00:00 0.005 QQQ \n",
+ "2021-05-18 00:00:00+00:00 0.008 QQQ \n",
+ "2021-05-18 00:00:00+00:00 0.011 QQQ \n",
+ "... ... ... \n",
+ "2022-12-31 00:00:00+00:00 0.647 SPY \n",
+ "2022-12-31 00:00:00+00:00 0.660 SPY \n",
+ "2022-12-31 00:00:00+00:00 0.673 SPY \n",
+ "2022-12-31 00:00:00+00:00 0.687 SPY \n",
+ "2022-12-31 00:00:00+00:00 0.700 SPY \n",
+ "\n",
+ " OPTION_ID x fear_greed_index \\\n",
+ "2021-05-18 00:00:00+00:00 -8578305565234411172 2021-05-18 35.0 \n",
+ "2021-05-18 00:00:00+00:00 -3912251940911432638 2021-05-18 35.0 \n",
+ "2021-05-18 00:00:00+00:00 -796774111719326768 2021-05-18 35.0 \n",
+ "2021-05-18 00:00:00+00:00 -8305044159569129464 2021-05-18 35.0 \n",
+ "2021-05-18 00:00:00+00:00 -1070438577502752343 2021-05-18 35.0 \n",
+ "... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 -2602091060095401525 2022-12-31 38.0 \n",
+ "2022-12-31 00:00:00+00:00 -2872950415384401199 2022-12-31 38.0 \n",
+ "2022-12-31 00:00:00+00:00 -6162682096078852249 2022-12-31 38.0 \n",
+ "2022-12-31 00:00:00+00:00 3937355187600415841 2022-12-31 38.0 \n",
+ "2022-12-31 00:00:00+00:00 4608604951368675058 2022-12-31 38.0 \n",
+ "\n",
+ " close RSI_14 close_min_14 close_max_14 \\\n",
+ "2021-05-18 00:00:00+00:00 324.44 NaN NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 324.44 NaN NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 324.44 NaN NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 324.44 NaN NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 324.44 NaN NaN NaN \n",
+ "... ... ... ... ... \n",
+ "2022-12-31 00:00:00+00:00 382.44 44.376002 376.71 401.95 \n",
+ "2022-12-31 00:00:00+00:00 382.44 44.376002 376.71 401.95 \n",
+ "2022-12-31 00:00:00+00:00 382.44 44.376002 376.71 401.95 \n",
+ "2022-12-31 00:00:00+00:00 382.44 44.376002 376.71 401.95 \n",
+ "2022-12-31 00:00:00+00:00 382.44 44.376002 376.71 401.95 \n",
+ "\n",
+ " fear_greed_index_min_14 fear_greed_index_max_14 \\\n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "... ... ... \n",
+ "2022-12-31 00:00:00+00:00 36.0 61.0 \n",
+ "2022-12-31 00:00:00+00:00 36.0 61.0 \n",
+ "2022-12-31 00:00:00+00:00 36.0 61.0 \n",
+ "2022-12-31 00:00:00+00:00 36.0 61.0 \n",
+ "2022-12-31 00:00:00+00:00 36.0 61.0 \n",
+ "\n",
+ " RSI_14_min_14 RSI_14_max_14 \\\n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "2021-05-18 00:00:00+00:00 NaN NaN \n",
+ "... ... ... \n",
+ "2022-12-31 00:00:00+00:00 37.972031 56.545485 \n",
+ "2022-12-31 00:00:00+00:00 37.972031 56.545485 \n",
+ "2022-12-31 00:00:00+00:00 37.972031 56.545485 \n",
+ "2022-12-31 00:00:00+00:00 37.972031 56.545485 \n",
+ "2022-12-31 00:00:00+00:00 37.972031 56.545485 \n",
+ "\n",
+ " index \n",
+ "2021-05-18 00:00:00+00:00 2021-05-18 00:00:00+00:00 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-18 00:00:00+00:00 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-18 00:00:00+00:00 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-18 00:00:00+00:00 \n",
+ "2021-05-18 00:00:00+00:00 2021-05-18 00:00:00+00:00 \n",
+ "... ... \n",
+ "2022-12-31 00:00:00+00:00 2022-12-31 00:00:00+00:00 \n",
+ "2022-12-31 00:00:00+00:00 2022-12-31 00:00:00+00:00 \n",
+ "2022-12-31 00:00:00+00:00 2022-12-31 00:00:00+00:00 \n",
+ "2022-12-31 00:00:00+00:00 2022-12-31 00:00:00+00:00 \n",
+ "2022-12-31 00:00:00+00:00 2022-12-31 00:00:00+00:00 \n",
+ "\n",
+ "[2924028 rows x 40 columns]"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_option_history = pd.concat([product_data[product_id][\"df_option_history\"] for product_id in product_data.keys()])\n",
+ "df_option_history.sort_values(\n",
+ " by=[\"index\", \"UNDERLYING_PRODUCT_ID\", \"EXPIRE_UNIX\", \"DTE\", \"STRIKE_DISTANCE_PCT\"], inplace=True\n",
+ ")\n",
+ "df_option_history"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "6fa62b1c-0b12-475f-93b9-c9719d5d44a3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " QUOTE_TIME_HOURS | \n",
+ " UNDERLYING_LAST | \n",
+ " DTE | \n",
+ " C_DELTA | \n",
+ " C_GAMMA | \n",
+ " C_VEGA | \n",
+ " C_THETA | \n",
+ " C_RHO | \n",
+ " C_IV | \n",
+ " C_VOLUME | \n",
+ " C_LAST | \n",
+ " C_BID | \n",
+ " C_ASK | \n",
+ " STRIKE | \n",
+ " P_BID | \n",
+ " P_ASK | \n",
+ " P_LAST | \n",
+ " P_DELTA | \n",
+ " P_GAMMA | \n",
+ " P_VEGA | \n",
+ " P_THETA | \n",
+ " P_RHO | \n",
+ " P_IV | \n",
+ " P_VOLUME | \n",
+ " STRIKE_DISTANCE | \n",
+ " STRIKE_DISTANCE_PCT | \n",
+ " OPTION_ID | \n",
+ " fear_greed_index | \n",
+ " close | \n",
+ " RSI_14 | \n",
+ " close_min_14 | \n",
+ " close_max_14 | \n",
+ " fear_greed_index_min_14 | \n",
+ " fear_greed_index_max_14 | \n",
+ " RSI_14_min_14 | \n",
+ " RSI_14_max_14 | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " count | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2760678.0 | \n",
+ " 2288147.0 | \n",
+ " 2921862.0 | \n",
+ " 2921862.0 | \n",
+ " 2921862.0 | \n",
+ " 2924028.0 | \n",
+ " 2921864.0 | \n",
+ " 2921864.0 | \n",
+ " 2921864.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2923915.0 | \n",
+ " 2727843.0 | \n",
+ " 2268486.0 | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2924028.0 | \n",
+ " 2793236.0 | \n",
+ " 2802474.0 | \n",
+ " 2802474.0 | \n",
+ " 2802474.0 | \n",
+ " 2802474.0 | \n",
+ " 2678509.0 | \n",
+ " 2678509.0 | \n",
+ "
\n",
+ " \n",
+ " mean | \n",
+ " 16.0 | \n",
+ " 384.4283184189752 | \n",
+ " 138.02139746951772 | \n",
+ " 0.5147727075171475 | \n",
+ " -0.1426652472695 | \n",
+ " 0.37393658445953426 | \n",
+ " -0.062448612658028674 | \n",
+ " 0.5338645020665787 | \n",
+ " 0.32184403888465085 | \n",
+ " 223.67174268086796 | \n",
+ " 27.457221319829635 | \n",
+ " 42.82091449219715 | \n",
+ " 43.63370481905037 | \n",
+ " 378.4349665940271 | \n",
+ " 36.412099159988266 | \n",
+ " 37.20279069799281 | \n",
+ " 17.72762483811704 | \n",
+ " -0.4751130797851511 | \n",
+ " -1.3617365511890733 | \n",
+ " -3.372096385903825 | \n",
+ " -0.09526726047781825 | \n",
+ " -0.582160194400316 | \n",
+ " 0.33483247641084907 | \n",
+ " 278.73488617518467 | \n",
+ " 70.2024498397416 | \n",
+ " 0.1851790229094933 | \n",
+ " -5.510601608850764e+16 | \n",
+ " 39.008525910148606 | \n",
+ " 384.4283184189752 | \n",
+ " 51.6879211539061 | \n",
+ " 372.19830265686676 | \n",
+ " 397.4107338301801 | \n",
+ " 25.5486259640589 | \n",
+ " 52.2128383706682 | \n",
+ " 40.72111638826419 | \n",
+ " 60.877541732984994 | \n",
+ "
\n",
+ " \n",
+ " std | \n",
+ " 0.0 | \n",
+ " 56.07916429168577 | \n",
+ " 192.17584355995493 | \n",
+ " 0.3861001036753277 | \n",
+ " 253.33533046255502 | \n",
+ " 11.651493477130716 | \n",
+ " 0.07740579303640395 | \n",
+ " 7.729401177572637 | \n",
+ " 0.36249734941884854 | \n",
+ " 2948.9633538167545 | \n",
+ " 50.11363709421322 | \n",
+ " 59.9099974008247 | \n",
+ " 60.562646345379925 | \n",
+ " 103.57771221293312 | \n",
+ " 55.349329423001045 | \n",
+ " 56.04450959839431 | \n",
+ " 35.34904177146665 | \n",
+ " 0.38379745483747785 | \n",
+ " 1480.38156758852 | \n",
+ " 51.643064341421855 | \n",
+ " 0.698562963823025 | \n",
+ " 1.3426167492294432 | \n",
+ " 0.280395462162283 | \n",
+ " 2867.3746998730007 | \n",
+ " 69.38664370647663 | \n",
+ " 0.18296795839302013 | \n",
+ " 5.322665503534296e+18 | \n",
+ " 16.58751018152316 | \n",
+ " 56.07916429168577 | \n",
+ " 12.344754413310964 | \n",
+ " 55.83092688175122 | \n",
+ " 54.13280441889287 | \n",
+ " 13.969148762327524 | \n",
+ " 14.340958582930437 | \n",
+ " 10.346188286759945 | \n",
+ " 9.91193022420065 | \n",
+ "
\n",
+ " \n",
+ " min | \n",
+ " 16.0 | \n",
+ " 260.05 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " -433189.70517 | \n",
+ " -2815.39969 | \n",
+ " -7.16086 | \n",
+ " -2878.27141 | \n",
+ " -0.0005 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 25.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " -1.0 | \n",
+ " -2211829.9611 | \n",
+ " -2199.50048 | \n",
+ " -43.52167 | \n",
+ " -36.5688 | \n",
+ " -0.0005 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " -9.223268179247174e+18 | \n",
+ " 4.0 | \n",
+ " 260.05 | \n",
+ " 23.20999431509113 | \n",
+ " 260.05 | \n",
+ " 282.17 | \n",
+ " 4.0 | \n",
+ " 22.0 | \n",
+ " 23.20999431509113 | \n",
+ " 42.18860128883254 | \n",
+ "
\n",
+ " \n",
+ " 25% | \n",
+ " 16.0 | \n",
+ " 349.86 | \n",
+ " 16.0 | \n",
+ " 0.06801 | \n",
+ " 0.0005 | \n",
+ " 0.0311 | \n",
+ " -0.08407 | \n",
+ " 0.01039 | \n",
+ " 0.19401 | \n",
+ " 0.0 | \n",
+ " 0.01 | \n",
+ " 0.77 | \n",
+ " 0.92 | \n",
+ " 314.0 | \n",
+ " 1.7 | \n",
+ " 1.79 | \n",
+ " 0.02 | \n",
+ " -0.89625 | \n",
+ " 0.00057 | \n",
+ " 0.05015 | \n",
+ " -0.08544 | \n",
+ " -0.56005 | \n",
+ " 0.20922 | \n",
+ " 0.0 | \n",
+ " 21.6 | \n",
+ " 0.057 | \n",
+ " -4.677348367868452e+18 | \n",
+ " 27.0 | \n",
+ " 349.86 | \n",
+ " 41.85144511620841 | \n",
+ " 339.57 | \n",
+ " 368.47 | \n",
+ " 17.0 | \n",
+ " 41.0 | \n",
+ " 32.63792421591388 | \n",
+ " 52.672438402454766 | \n",
+ "
\n",
+ " \n",
+ " 50% | \n",
+ " 16.0 | \n",
+ " 390.15 | \n",
+ " 43.0 | \n",
+ " 0.58257 | \n",
+ " 0.0028 | \n",
+ " 0.21219 | \n",
+ " -0.04248 | \n",
+ " 0.1143 | \n",
+ " 0.25148 | \n",
+ " 1.0 | \n",
+ " 3.33 | \n",
+ " 17.41 | \n",
+ " 18.06 | \n",
+ " 379.0 | \n",
+ " 13.69 | \n",
+ " 14.28 | \n",
+ " 2.98 | \n",
+ " -0.42047 | \n",
+ " 0.00288 | \n",
+ " 0.24047 | \n",
+ " -0.04357 | \n",
+ " -0.11167 | \n",
+ " 0.27624 | \n",
+ " 2.0 | \n",
+ " 47.3 | \n",
+ " 0.125 | \n",
+ " -6.743361482311614e+16 | \n",
+ " 37.0 | \n",
+ " 390.15 | \n",
+ " 50.69687314399896 | \n",
+ " 377.94 | \n",
+ " 402.42 | \n",
+ " 21.0 | \n",
+ " 52.0 | \n",
+ " 38.470403626970906 | \n",
+ " 60.6994653162677 | \n",
+ "
\n",
+ " \n",
+ " 75% | \n",
+ " 16.0 | \n",
+ " 432.88 | \n",
+ " 191.04 | \n",
+ " 0.9021 | \n",
+ " 0.00684 | \n",
+ " 0.57939 | \n",
+ " -0.01035 | \n",
+ " 0.54251 | \n",
+ " 0.3307 | \n",
+ " 13.0 | \n",
+ " 31.32 | \n",
+ " 60.15 | \n",
+ " 61.45 | \n",
+ " 440.0 | \n",
+ " 45.21 | \n",
+ " 46.49 | \n",
+ " 19.42 | \n",
+ " -0.07504 | \n",
+ " 0.00676 | \n",
+ " 0.62677 | \n",
+ " -0.01672 | \n",
+ " -0.00796 | \n",
+ " 0.37669 | \n",
+ " 30.0 | \n",
+ " 98.6 | \n",
+ " 0.26 | \n",
+ " 4.520398356603582e+18 | \n",
+ " 52.0 | \n",
+ " 432.88 | \n",
+ " 61.698535691456804 | \n",
+ " 420.84 | \n",
+ " 444.89 | \n",
+ " 33.0 | \n",
+ " 64.0 | \n",
+ " 47.07514402308029 | \n",
+ " 68.28616665486885 | \n",
+ "
\n",
+ " \n",
+ " max | \n",
+ " 16.0 | \n",
+ " 477.77 | \n",
+ " 1096.0 | \n",
+ " 1.0 | \n",
+ " 2.26443 | \n",
+ " 147.32807 | \n",
+ " 0.0 | \n",
+ " 263.72682 | \n",
+ " 41.39908 | \n",
+ " 282571.0 | \n",
+ " 444.2 | \n",
+ " 445.08 | \n",
+ " 446.28 | \n",
+ " 4898.0 | \n",
+ " 4451.19 | \n",
+ " 4455.5 | \n",
+ " 359.21 | \n",
+ " 0.0 | \n",
+ " 280.89887 | \n",
+ " 81.84637 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 12.17003 | \n",
+ " 265102.0 | \n",
+ " 4469.3 | \n",
+ " 10.425 | \n",
+ " 9.222556436732245e+18 | \n",
+ " 77.0 | \n",
+ " 477.77 | \n",
+ " 83.36208171663986 | \n",
+ " 464.72 | \n",
+ " 477.77 | \n",
+ " 63.0 | \n",
+ " 77.0 | \n",
+ " 72.8276648027665 | \n",
+ " 83.36208171663986 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " QUOTE_TIME_HOURS UNDERLYING_LAST DTE \\\n",
+ "count 2924028.0 2924028.0 2924028.0 \n",
+ "mean 16.0 384.4283184189752 138.02139746951772 \n",
+ "std 0.0 56.07916429168577 192.17584355995493 \n",
+ "min 16.0 260.05 0.0 \n",
+ "25% 16.0 349.86 16.0 \n",
+ "50% 16.0 390.15 43.0 \n",
+ "75% 16.0 432.88 191.04 \n",
+ "max 16.0 477.77 1096.0 \n",
+ "\n",
+ " C_DELTA C_GAMMA C_VEGA \\\n",
+ "count 2923915.0 2923915.0 2923915.0 \n",
+ "mean 0.5147727075171475 -0.1426652472695 0.37393658445953426 \n",
+ "std 0.3861001036753277 253.33533046255502 11.651493477130716 \n",
+ "min 0.0 -433189.70517 -2815.39969 \n",
+ "25% 0.06801 0.0005 0.0311 \n",
+ "50% 0.58257 0.0028 0.21219 \n",
+ "75% 0.9021 0.00684 0.57939 \n",
+ "max 1.0 2.26443 147.32807 \n",
+ "\n",
+ " C_THETA C_RHO C_IV \\\n",
+ "count 2923915.0 2923915.0 2760678.0 \n",
+ "mean -0.062448612658028674 0.5338645020665787 0.32184403888465085 \n",
+ "std 0.07740579303640395 7.729401177572637 0.36249734941884854 \n",
+ "min -7.16086 -2878.27141 -0.0005 \n",
+ "25% -0.08407 0.01039 0.19401 \n",
+ "50% -0.04248 0.1143 0.25148 \n",
+ "75% -0.01035 0.54251 0.3307 \n",
+ "max 0.0 263.72682 41.39908 \n",
+ "\n",
+ " C_VOLUME C_LAST C_BID \\\n",
+ "count 2288147.0 2921862.0 2921862.0 \n",
+ "mean 223.67174268086796 27.457221319829635 42.82091449219715 \n",
+ "std 2948.9633538167545 50.11363709421322 59.9099974008247 \n",
+ "min 0.0 0.0 0.0 \n",
+ "25% 0.0 0.01 0.77 \n",
+ "50% 1.0 3.33 17.41 \n",
+ "75% 13.0 31.32 60.15 \n",
+ "max 282571.0 444.2 445.08 \n",
+ "\n",
+ " C_ASK STRIKE P_BID \\\n",
+ "count 2921862.0 2924028.0 2921864.0 \n",
+ "mean 43.63370481905037 378.4349665940271 36.412099159988266 \n",
+ "std 60.562646345379925 103.57771221293312 55.349329423001045 \n",
+ "min 0.0 25.0 0.0 \n",
+ "25% 0.92 314.0 1.7 \n",
+ "50% 18.06 379.0 13.69 \n",
+ "75% 61.45 440.0 45.21 \n",
+ "max 446.28 4898.0 4451.19 \n",
+ "\n",
+ " P_ASK P_LAST P_DELTA \\\n",
+ "count 2921864.0 2921864.0 2923915.0 \n",
+ "mean 37.20279069799281 17.72762483811704 -0.4751130797851511 \n",
+ "std 56.04450959839431 35.34904177146665 0.38379745483747785 \n",
+ "min 0.0 0.0 -1.0 \n",
+ "25% 1.79 0.02 -0.89625 \n",
+ "50% 14.28 2.98 -0.42047 \n",
+ "75% 46.49 19.42 -0.07504 \n",
+ "max 4455.5 359.21 0.0 \n",
+ "\n",
+ " P_GAMMA P_VEGA P_THETA \\\n",
+ "count 2923915.0 2923915.0 2923915.0 \n",
+ "mean -1.3617365511890733 -3.372096385903825 -0.09526726047781825 \n",
+ "std 1480.38156758852 51.643064341421855 0.698562963823025 \n",
+ "min -2211829.9611 -2199.50048 -43.52167 \n",
+ "25% 0.00057 0.05015 -0.08544 \n",
+ "50% 0.00288 0.24047 -0.04357 \n",
+ "75% 0.00676 0.62677 -0.01672 \n",
+ "max 280.89887 81.84637 0.0 \n",
+ "\n",
+ " P_RHO P_IV P_VOLUME \\\n",
+ "count 2923915.0 2727843.0 2268486.0 \n",
+ "mean -0.582160194400316 0.33483247641084907 278.73488617518467 \n",
+ "std 1.3426167492294432 0.280395462162283 2867.3746998730007 \n",
+ "min -36.5688 -0.0005 0.0 \n",
+ "25% -0.56005 0.20922 0.0 \n",
+ "50% -0.11167 0.27624 2.0 \n",
+ "75% -0.00796 0.37669 30.0 \n",
+ "max 0.0 12.17003 265102.0 \n",
+ "\n",
+ " STRIKE_DISTANCE STRIKE_DISTANCE_PCT OPTION_ID \\\n",
+ "count 2924028.0 2924028.0 2924028.0 \n",
+ "mean 70.2024498397416 0.1851790229094933 -5.510601608850764e+16 \n",
+ "std 69.38664370647663 0.18296795839302013 5.322665503534296e+18 \n",
+ "min 0.0 0.0 -9.223268179247174e+18 \n",
+ "25% 21.6 0.057 -4.677348367868452e+18 \n",
+ "50% 47.3 0.125 -6.743361482311614e+16 \n",
+ "75% 98.6 0.26 4.520398356603582e+18 \n",
+ "max 4469.3 10.425 9.222556436732245e+18 \n",
+ "\n",
+ " fear_greed_index close RSI_14 \\\n",
+ "count 2924028.0 2924028.0 2793236.0 \n",
+ "mean 39.008525910148606 384.4283184189752 51.6879211539061 \n",
+ "std 16.58751018152316 56.07916429168577 12.344754413310964 \n",
+ "min 4.0 260.05 23.20999431509113 \n",
+ "25% 27.0 349.86 41.85144511620841 \n",
+ "50% 37.0 390.15 50.69687314399896 \n",
+ "75% 52.0 432.88 61.698535691456804 \n",
+ "max 77.0 477.77 83.36208171663986 \n",
+ "\n",
+ " close_min_14 close_max_14 fear_greed_index_min_14 \\\n",
+ "count 2802474.0 2802474.0 2802474.0 \n",
+ "mean 372.19830265686676 397.4107338301801 25.5486259640589 \n",
+ "std 55.83092688175122 54.13280441889287 13.969148762327524 \n",
+ "min 260.05 282.17 4.0 \n",
+ "25% 339.57 368.47 17.0 \n",
+ "50% 377.94 402.42 21.0 \n",
+ "75% 420.84 444.89 33.0 \n",
+ "max 464.72 477.77 63.0 \n",
+ "\n",
+ " fear_greed_index_max_14 RSI_14_min_14 RSI_14_max_14 \n",
+ "count 2802474.0 2678509.0 2678509.0 \n",
+ "mean 52.2128383706682 40.72111638826419 60.877541732984994 \n",
+ "std 14.340958582930437 10.346188286759945 9.91193022420065 \n",
+ "min 22.0 23.20999431509113 42.18860128883254 \n",
+ "25% 41.0 32.63792421591388 52.672438402454766 \n",
+ "50% 52.0 38.470403626970906 60.6994653162677 \n",
+ "75% 64.0 47.07514402308029 68.28616665486885 \n",
+ "max 77.0 72.8276648027665 83.36208171663986 "
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# for c in [\"UNDERLYING_LAST\", \"fear_greed_index\"]:\n",
+ "# df = df_option_history[[c]]\n",
+ "# df[\"date\"] = df.index\n",
+ "# df.drop_duplicates(subset=[\"date\", c]).plot(x=\"date\", y=c)\n",
+ "\n",
+ "df_option_history.describe().astype(str)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "95a774ff-3056-460b-a80c-a39cac253015",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2021-06-10 QQQ $1027 1 buy call 2021-06-25 336.86 337.0 $486 3479158678833100675\n",
+ "2021-06-10 QQQ $117 2 buy call 2021-06-25 336.86 337.5 $454 -3598241872408703621\n",
+ "2021-06-11 SPY $0 3 buy call 2021-06-25 423.61 431.0 $58 -3094602456089219840\n",
+ "2021-06-16 QQQ $1305 2 sell call 2021-06-25 342.15 337.5 $653 -3598241872408703621\n",
+ "2021-06-16 QQQ $2685 1 sell call 2021-06-25 342.15 337.0 $691 3479158678833100675\n",
+ "2021-06-16 SPY $2782 0 sell call 2021-06-25 424.51 431.0 $49 -3094602456089219840\n",
+ "2021-07-07 QQQ $2275 1 buy put 2021-07-21 360.13 354.0 $253 1455647653561036424\n",
+ "2021-07-07 QQQ $1305 2 buy put 2021-07-23 360.13 360.0 $484 -2619219960940882630\n",
+ "2021-07-07 QQQ $414 3 buy put 2021-07-23 360.13 359.0 $445 -3008072389610402244\n",
+ "2021-07-07 SPY $-1 4 buy put 2021-07-21 432.88 427.0 $207 4274915379359932434\n",
+ "2021-07-09 QQQ $679 3 sell put 2021-07-21 358.79 354.0 $341 1455647653561036424\n",
+ "2021-07-09 QQQ $1820 2 sell put 2021-07-23 358.79 359.0 $571 -3008072389610402244\n",
+ "2021-07-09 QQQ $3035 1 sell put 2021-07-23 358.79 360.0 $608 -2619219960940882630\n",
+ "2021-07-09 SPY $3666 0 sell put 2021-07-21 430.87 427.0 $316 4274915379359932434\n",
+ "2021-07-15 QQQ $2570 1 buy put 2021-07-30 363.1 363.0 $547 7665537119925776718\n",
+ "2021-07-15 QQQ $1529 2 buy put 2021-07-30 363.1 362.5 $520 -4215429045744817303\n",
+ "2021-07-15 QQQ $344 3 buy put 2021-07-30 363.1 364.0 $592 4021412419915507109\n",
+ "2021-07-21 QQQ $1574 2 sell put 2021-07-30 358.78 362.5 $616 -4215429045744817303\n",
+ "2021-07-21 QQQ $2857 1 sell put 2021-07-30 358.78 363.0 $642 7665537119925776718\n",
+ "2021-07-21 QQQ $4264 0 sell put 2021-07-30 358.78 364.0 $704 4021412419915507109\n",
+ "2021-08-05 QQQ $3274 1 buy call 2021-08-20 367.34 367.0 $494 -2492154288151173285\n",
+ "2021-08-05 QQQ $2157 2 buy call 2021-08-20 367.34 366.0 $558 4029445948671140943\n",
+ "2021-08-05 QQQ $1402 3 buy call 2021-08-20 367.34 369.0 $377 7664081963786003086\n",
+ "2021-08-05 QQQ $168 4 buy call 2021-08-20 367.34 365.0 $616 -6352818614728215081\n",
+ "2021-08-06 SPY $29 5 buy call 2021-08-20 441.73 450.0 $69 -8845821036070862059\n",
+ "2021-08-13 QQQ $642 4 sell call 2021-08-20 367.58 367.0 $307 -2492154288151173285\n",
+ "2021-08-13 QQQ $1378 3 sell call 2021-08-20 367.58 366.0 $369 4029445948671140943\n",
+ "2021-08-13 QQQ $1775 2 sell call 2021-08-20 367.58 369.0 $199 7664081963786003086\n",
+ "2021-08-13 QQQ $2650 1 sell call 2021-08-20 367.58 365.0 $438 -6352818614728215081\n",
+ "2021-08-13 QQQ $1844 2 buy call 2021-08-27 367.58 368.0 $402 5701635151616173389\n",
+ "2021-08-13 QQQ $923 3 buy call 2021-08-27 367.58 367.0 $460 6833983001175984167\n",
+ "2021-08-13 QQQ $232 4 buy call 2021-08-27 367.58 369.0 $345 -29270181784786071\n",
+ "2021-08-13 SPY $42 5 buy call 2021-08-27 445.06 451.0 $94 -7049535863332786931\n",
+ "2021-08-17 QQQ $713 4 sell call 2021-08-27 368.97 369.0 $336 -29270181784786071\n",
+ "2021-08-17 QQQ $1508 3 sell call 2021-08-27 368.97 368.0 $398 5701635151616173389\n",
+ "2021-08-17 QQQ $2434 2 sell call 2021-08-27 368.97 367.0 $464 6833983001175984167\n",
+ "2021-08-17 SPY $2515 1 sell call 2021-08-20 447.06 450.0 $41 -8845821036070862059\n",
+ "2021-08-17 SPY $2716 0 sell call 2021-08-27 447.06 451.0 $101 -7049535863332786931\n",
+ "2021-08-18 QQQ $1539 1 buy put 2021-09-01 365.67 368.0 $588 5563668740461325759\n",
+ "2021-08-18 QQQ $527 2 buy put 2021-09-03 365.67 365.0 $505 -4896361780820862711\n",
+ "2021-08-18 SPY $14 3 buy put 2021-09-01 443.95 437.0 $256 -7241514007088948224\n",
+ "2021-08-20 QQQ $1337 2 sell put 2021-09-01 364.0 368.0 $662 5563668740461325759\n",
+ "2021-08-20 QQQ $2525 1 sell put 2021-09-03 364.0 365.0 $595 -4896361780820862711\n",
+ "2021-08-20 SPY $3384 0 sell put 2021-09-01 439.87 437.0 $430 -7241514007088948224\n",
+ "2021-08-27 QQQ $2661 1 buy call 2021-09-10 372.4 374.0 $361 -5581727436213367973\n",
+ "2021-08-27 QQQ $2041 2 buy call 2021-09-10 372.4 375.0 $309 5011091652458344542\n",
+ "2021-08-27 QQQ $1044 3 buy call 2021-09-15 372.4 373.0 $498 -3897788335741031678\n",
+ "2021-08-27 QQQ $283 4 buy call 2021-09-15 372.4 375.0 $380 -5607472823889186386\n",
+ "2021-08-27 SPY $29 5 buy call 2021-09-10 446.33 452.5 $126 6193195140520552914\n"
+ ]
+ },
+ {
+ "ename": "KeyboardInterrupt",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[14], line 15\u001b[0m\n\u001b[1;32m 12\u001b[0m owned_options \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m 13\u001b[0m trade_data \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m---> 15\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m index, row \u001b[38;5;129;01min\u001b[39;00m df_option_history\u001b[38;5;241m.\u001b[39miterrows():\n\u001b[1;32m 16\u001b[0m expire_date \u001b[38;5;241m=\u001b[39m row\u001b[38;5;241m.\u001b[39mEXPIRE_UNIX\u001b[38;5;241m.\u001b[39mstrftime(\u001b[38;5;28mformat\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124mY-\u001b[39m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124mm-\u001b[39m\u001b[38;5;132;01m%d\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 17\u001b[0m index_date \u001b[38;5;241m=\u001b[39m index\u001b[38;5;241m.\u001b[39mstrftime(\u001b[38;5;28mformat\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124mY-\u001b[39m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124mm-\u001b[39m\u001b[38;5;132;01m%d\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
+ "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/frame.py:1450\u001b[0m, in \u001b[0;36mDataFrame.iterrows\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1448\u001b[0m using_cow \u001b[38;5;241m=\u001b[39m using_copy_on_write()\n\u001b[1;32m 1449\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k, v \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mzip\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mindex, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvalues):\n\u001b[0;32m-> 1450\u001b[0m s \u001b[38;5;241m=\u001b[39m \u001b[43mklass\u001b[49m\u001b[43m(\u001b[49m\u001b[43mv\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mk\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39m__finalize__(\u001b[38;5;28mself\u001b[39m)\n\u001b[1;32m 1451\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m using_cow \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_mgr\u001b[38;5;241m.\u001b[39mis_single_block:\n\u001b[1;32m 1452\u001b[0m s\u001b[38;5;241m.\u001b[39m_mgr\u001b[38;5;241m.\u001b[39madd_references(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_mgr) \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n",
+ "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/series.py:512\u001b[0m, in \u001b[0;36mSeries.__init__\u001b[0;34m(self, data, index, dtype, name, copy, fastpath)\u001b[0m\n\u001b[1;32m 510\u001b[0m data \u001b[38;5;241m=\u001b[39m data\u001b[38;5;241m.\u001b[39mcopy()\n\u001b[1;32m 511\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 512\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43msanitize_array\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mindex\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 514\u001b[0m manager \u001b[38;5;241m=\u001b[39m get_option(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmode.data_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 515\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m manager \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mblock\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n",
+ "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/construction.py:603\u001b[0m, in \u001b[0;36msanitize_array\u001b[0;34m(data, index, dtype, copy, allow_2d)\u001b[0m\n\u001b[1;32m 601\u001b[0m subarr \u001b[38;5;241m=\u001b[39m data\n\u001b[1;32m 602\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m data\u001b[38;5;241m.\u001b[39mdtype \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mobject\u001b[39m:\n\u001b[0;32m--> 603\u001b[0m subarr \u001b[38;5;241m=\u001b[39m \u001b[43mmaybe_infer_to_datetimelike\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 604\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m data\u001b[38;5;241m.\u001b[39mdtype\u001b[38;5;241m.\u001b[39mkind \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mU\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m using_pyarrow_string_dtype():\n\u001b[1;32m 605\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcore\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01marrays\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mstring_\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m StringDtype\n",
+ "File \u001b[0;32m~/.local/lib/python3.10/site-packages/pandas/core/dtypes/cast.py:1180\u001b[0m, in \u001b[0;36mmaybe_infer_to_datetimelike\u001b[0;34m(value)\u001b[0m\n\u001b[1;32m 1175\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m value\n\u001b[1;32m 1177\u001b[0m \u001b[38;5;66;03m# error: Incompatible return value type (got \"Union[ExtensionArray,\u001b[39;00m\n\u001b[1;32m 1178\u001b[0m \u001b[38;5;66;03m# ndarray[Any, Any]]\", expected \"Union[ndarray[Any, Any], DatetimeArray,\u001b[39;00m\n\u001b[1;32m 1179\u001b[0m \u001b[38;5;66;03m# TimedeltaArray, PeriodArray, IntervalArray]\")\u001b[39;00m\n\u001b[0;32m-> 1180\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mlib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmaybe_convert_objects\u001b[49m\u001b[43m(\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[return-value]\u001b[39;49;00m\n\u001b[1;32m 1181\u001b[0m \u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1182\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Here we do not convert numeric dtypes, as if we wanted that,\u001b[39;49;00m\n\u001b[1;32m 1183\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# numpy would have done it for us.\u001b[39;49;00m\n\u001b[1;32m 1184\u001b[0m \u001b[43m \u001b[49m\u001b[43mconvert_numeric\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 1185\u001b[0m \u001b[43m \u001b[49m\u001b[43mconvert_non_numeric\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 1186\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype_if_all_nat\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mM8[ns]\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1187\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
+ "File \u001b[0;32mlib.pyx:2519\u001b[0m, in \u001b[0;36mpandas._libs.lib.maybe_convert_objects\u001b[0;34m()\u001b[0m\n",
+ "File \u001b[0;32m~/.local/lib/python3.10/site-packages/numpy/core/numeric.py:274\u001b[0m, in \u001b[0;36mfull\u001b[0;34m(shape, fill_value, dtype, order, like)\u001b[0m\n\u001b[1;32m 270\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_full_dispatcher\u001b[39m(shape, fill_value, dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, order\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m, like\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 271\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m(like,)\n\u001b[0;32m--> 274\u001b[0m \u001b[38;5;129m@set_array_function_like_doc\u001b[39m\n\u001b[1;32m 275\u001b[0m \u001b[38;5;129m@set_module\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnumpy\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 276\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mfull\u001b[39m(shape, fill_value, dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, order\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mC\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;241m*\u001b[39m, like\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 277\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 278\u001b[0m \u001b[38;5;124;03m Return a new array of given shape and type, filled with `fill_value`.\u001b[39;00m\n\u001b[1;32m 279\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 320\u001b[0m \n\u001b[1;32m 321\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m 322\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m like \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
+ "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
+ ]
+ }
+ ],
+ "source": [
+ "min_dte_buy = 14\n",
+ "min_dte_sell = int(min_dte_buy / 2)\n",
+ "min_volume = 100\n",
+ "max_strike_distance_pct = 0.02\n",
+ "contract_fee = 0.66\n",
+ "total_contracts = 2\n",
+ "\n",
+ "money = 2000\n",
+ "start_money = money\n",
+ "last_index = df_option_history.index.values[-1]\n",
+ "\n",
+ "owned_options = []\n",
+ "trade_data = []\n",
+ "\n",
+ "for index, row in df_option_history.iterrows():\n",
+ " expire_date = row.EXPIRE_UNIX.strftime(format=\"%Y-%m-%d\")\n",
+ " index_date = index.strftime(format=\"%Y-%m-%d\")\n",
+ " is_last_index = index.to_numpy() == last_index\n",
+ "\n",
+ " good_call_buy = row.fear_greed_index >= row.fear_greed_index_max_14 - 1\n",
+ " good_put_buy = row.fear_greed_index <= row.fear_greed_index_min_14 + 1\n",
+ "\n",
+ " call_bid_price = row.C_BID * 100\n",
+ " put_bid_price = row.P_BID * 100\n",
+ "\n",
+ " owned_options_not_sold = []\n",
+ "\n",
+ " for option in owned_options:\n",
+ " if option[\"OPTION_ID\"] == row.OPTION_ID:\n",
+ " if (\n",
+ " option[\"side\"] == \"call\"\n",
+ " and not np.isnan(row.C_BID)\n",
+ " and (\n",
+ " not good_call_buy\n",
+ " or row.DTE < min_dte_sell\n",
+ " or (option[\"DTE\"] - row.DTE) > min_dte_sell\n",
+ " or is_last_index\n",
+ " )\n",
+ " ):\n",
+ " money += (call_bid_price - contract_fee) * total_contracts\n",
+ " print(\n",
+ " f\"{index_date} {row.UNDERLYING_PRODUCT_ID} ${money:.0f} {len(owned_options)-1} sell call {expire_date} {row.UNDERLYING_LAST} {row.STRIKE} ${call_bid_price:.0f} {row.OPTION_ID}\"\n",
+ " )\n",
+ " trade_data.append(\n",
+ " {\n",
+ " \"date\": index_date,\n",
+ " \"money\": money,\n",
+ " \"side\": \"sell\",\n",
+ " \"price\": call_bid_price,\n",
+ " \"options\": len(owned_options) - 1,\n",
+ " }\n",
+ " )\n",
+ " elif (\n",
+ " option[\"side\"] == \"put\"\n",
+ " and not np.isnan(row.P_BID)\n",
+ " and (\n",
+ " not good_put_buy\n",
+ " or row.DTE < min_dte_sell\n",
+ " or (option[\"DTE\"] - row.DTE) > min_dte_sell\n",
+ " or is_last_index\n",
+ " )\n",
+ " ):\n",
+ " money += (put_bid_price - contract_fee) * total_contracts\n",
+ " print(\n",
+ " f\"{index_date} {row.UNDERLYING_PRODUCT_ID} ${money:.0f} {len(owned_options)-1} sell put {expire_date} {row.UNDERLYING_LAST} {row.STRIKE} ${put_bid_price:.0f} {row.OPTION_ID}\"\n",
+ " )\n",
+ " trade_data.append(\n",
+ " {\n",
+ " \"date\": index_date,\n",
+ " \"money\": money,\n",
+ " \"side\": \"sell\",\n",
+ " \"price\": put_bid_price,\n",
+ " \"options\": len(owned_options) - 1,\n",
+ " }\n",
+ " )\n",
+ " else:\n",
+ " owned_options_not_sold.append(option)\n",
+ " else:\n",
+ " owned_options_not_sold.append(option)\n",
+ "\n",
+ " owned_options = owned_options_not_sold\n",
+ "\n",
+ " max_buy_price = money / total_contracts\n",
+ " max_buy_amount = 10\n",
+ " call_ask_price = row.C_ASK * 100\n",
+ " put_ask_price = row.P_ASK * 100\n",
+ "\n",
+ " if not is_last_index and row.DTE > min_dte_buy and row.STRIKE_DISTANCE_PCT < max_strike_distance_pct:\n",
+ " if (\n",
+ " good_call_buy\n",
+ " and not np.isnan(row.C_ASK)\n",
+ " and row.C_VOLUME > min_volume\n",
+ " and call_ask_price <= max_buy_price\n",
+ " and money >= call_ask_price\n",
+ " and len([x for x in owned_options if x[\"OPTION_ID\"] == row.OPTION_ID]) == 0\n",
+ " # and len([x for x in owned_options if x[\"side\"] == \"call\" and x[\"purchase_date\"] == index_date]) <= max_buy_amount\n",
+ " # and row.UNDERLYING_LAST > row.STRIKE\n",
+ " ):\n",
+ " money -= (call_ask_price + contract_fee) * total_contracts\n",
+ " option_to_buy = row.to_dict()\n",
+ " option_to_buy[\"side\"] = \"call\"\n",
+ " option_to_buy[\"purchase_date\"] = index_date\n",
+ " owned_options.append(option_to_buy)\n",
+ " print(\n",
+ " f\"{index_date} {row.UNDERLYING_PRODUCT_ID} ${money:.0f} {len(owned_options)} buy call {expire_date} {row.UNDERLYING_LAST} {row.STRIKE} ${call_ask_price:.0f} {row.OPTION_ID}\"\n",
+ " )\n",
+ " trade_data.append(\n",
+ " {\n",
+ " \"date\": index_date,\n",
+ " \"money\": money,\n",
+ " \"side\": \"buy\",\n",
+ " \"price\": call_ask_price,\n",
+ " \"options\": len(owned_options),\n",
+ " }\n",
+ " )\n",
+ " elif (\n",
+ " good_put_buy\n",
+ " and not np.isnan(row.P_ASK)\n",
+ " and row.P_VOLUME > min_volume\n",
+ " and put_ask_price <= max_buy_price\n",
+ " and money >= put_ask_price\n",
+ " and len([x for x in owned_options if x[\"OPTION_ID\"] == row.OPTION_ID]) == 0\n",
+ " # and len([x for x in owned_options if x[\"side\"] == \"put\" and x[\"purchase_date\"] == index_date]) <= max_buy_amount\n",
+ " # and row.UNDERLYING_LAST < row.STRIKE\n",
+ " ):\n",
+ " money -= (put_ask_price + contract_fee) * total_contracts\n",
+ " option_to_buy = row.to_dict()\n",
+ " option_to_buy[\"side\"] = \"put\"\n",
+ " option_to_buy[\"purchase_date\"] = index_date\n",
+ " owned_options.append(option_to_buy)\n",
+ " print(\n",
+ " f\"{index_date} {row.UNDERLYING_PRODUCT_ID} ${money:.0f} {len(owned_options)} buy put {expire_date} {row.UNDERLYING_LAST} {row.STRIKE} ${put_ask_price:.0f} {row.OPTION_ID}\"\n",
+ " )\n",
+ " trade_data.append(\n",
+ " {\n",
+ " \"date\": index_date,\n",
+ " \"money\": money,\n",
+ " \"side\": \"buy\",\n",
+ " \"price\": put_ask_price,\n",
+ " \"options\": len(owned_options),\n",
+ " }\n",
+ " )\n",
+ "\n",
+ "print(f\"Start money: ${start_money:.2f}\")\n",
+ "print(f\"End money: ${money:.2f} ({(money-start_money)/start_money*100:.2f}%)\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6784b905-13d8-4f2d-9f51-724d5451ba14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from matplotlib.pyplot import figure\n",
+ "\n",
+ "figure(figsize=(13, 4), dpi=80)\n",
+ "\n",
+ "df_trades = pd.DataFrame(trade_data)\n",
+ "\n",
+ "field_to_plot = \"money\"\n",
+ "# df_trades_plot = df_trades_plot.copy()\n",
+ "# df_trades_plot = df_trades.loc[(df_trades[\"side\"] == \"sell\")]\n",
+ "df_trades_plot = df_trades.loc[(df_trades[\"side\"] == \"sell\") & (df_trades[\"options\"] == 0)]\n",
+ "\n",
+ "# field_to_plot = \"options\"\n",
+ "# df_trades_plot = df_trades.groupby([\"date\"]).max(\"options\").reset_index()\n",
+ "\n",
+ "plt.clf()\n",
+ "plt.plot(pd.to_datetime(df_trades_plot[\"date\"]), df_trades_plot[field_to_plot])\n",
+ "plt.xlabel(\"date\")\n",
+ "plt.ylabel(field_to_plot)\n",
+ "plt.show()\n",
+ "df_trades.describe().astype(str)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9c86f9b9-1941-4b42-9d3b-46d512e775e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# SPY, max strike distance .05, fear and greed max+1/min-1, max purchase money / 10, max 10 options daily\n",
+ "# Options: 3304\n",
+ "# End money: $379182.36 (18859.12%)\n",
+ "\n",
+ "# SPY, max strike distance .02, fear and greed max+1/min-1, max purchase money / 10, max 10 options daily\n",
+ "# Options: 2966\n",
+ "# End money: $369782.44 (18389.12%)\n",
+ "\n",
+ "# SPY, max strike distance .02, fear and greed max+1/min-1, max purchase money, max 10 options daily\n",
+ "# Options: 3206\n",
+ "# End money: $427413.04 (21270.65%)\n",
+ "\n",
+ "# SPY, max strike distance .01, fear and greed max+1/min-1, max purchase money, max 50 options daily\n",
+ "# Options: 8828\n",
+ "# End money: $1249933.52 (62396.68%)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.12"
+ },
+ "papermill": {
+ "default_parameters": {},
+ "duration": 42.448071,
+ "end_time": "2023-02-27T05:32:21.988648",
+ "environment_variables": {},
+ "exception": null,
+ "input_path": "__notebook__.ipynb",
+ "output_path": "__notebook__.ipynb",
+ "parameters": {},
+ "start_time": "2023-02-27T05:31:39.540577",
+ "version": "2.4.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}