Overall Statistics
Total Orders
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Start Equity
100000
End Equity
100000
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
Drawdown Recovery
0
# region imports
from AlgorithmImports import *
# endregion

# Verification backtest for Intercom ticket 215474891197531.
# Customer claims (fresh QuantBook repros):
#   1. 2022-01-28: SPX/SPXW price, IV, gamma OK but SPXW open interest zero across contracts.
#   2. 2022-02-25 and 2022-03-04: ES complete, SPX minute history missing, and the
#      prior-session SPXW OptionUniverse chain snapshot missing.
#   3. Adjacent Fridays normal.
# Everything runs in initialize() via explicit-range history calls; results are
# logged AND saved to the ObjectStore for API retrieval.

REPORT_KEY = "repro-215474891197531/report.txt"


class SpxwDataGapVerification(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2022, 3, 14)
        self.set_end_date(2022, 3, 15)
        self.set_cash(100000)
        self.lines = []

        spx = self.add_index("SPX", Resolution.MINUTE).symbol
        es = self.add_future(Futures.Indices.SP_500_E_MINI, Resolution.MINUTE).symbol
        spxw = Symbol.create_canonical_option(spx, "SPXW", Market.USA, "?SPXW")

        # --- Part A: SPX + ES minute bar counts per date -------------------
        minute_dates = [
            date(2022, 1, 21), date(2022, 1, 28), date(2022, 2, 4),
            date(2022, 2, 11), date(2022, 2, 18), date(2022, 2, 24),
            date(2022, 2, 25), date(2022, 2, 28), date(2022, 3, 3),
            date(2022, 3, 4), date(2022, 3, 7), date(2022, 3, 11),
        ]
        for d in minute_dates:
            s = datetime(d.year, d.month, d.day)
            e = s + timedelta(days=1)
            try:
                spx_n = len(self.history([spx], s, e, Resolution.MINUTE))
            except Exception as ex:
                spx_n = f"EXC:{ex}"
            try:
                es_n = len(self.history([es], s, e, Resolution.MINUTE))
            except Exception as ex:
                es_n = f"EXC:{ex}"
            self.note(f"MINUTE {d} SPX_bars={spx_n} ES_bars={es_n}")

        # --- Part B: SPXW option-universe snapshots, weekly chunks ---------
        chunks = [
            (datetime(2022, 1, 18), datetime(2022, 1, 25)),
            (datetime(2022, 1, 25), datetime(2022, 2, 1)),
            (datetime(2022, 2, 1), datetime(2022, 2, 8)),
            (datetime(2022, 2, 8), datetime(2022, 2, 15)),
            (datetime(2022, 2, 15), datetime(2022, 2, 22)),
            (datetime(2022, 2, 22), datetime(2022, 3, 1)),
            (datetime(2022, 3, 1), datetime(2022, 3, 8)),
            (datetime(2022, 3, 8), datetime(2022, 3, 12)),
        ]
        jan28_snapshot = None
        for s, e in chunks:
            try:
                df = self.history(spxw, s, e, flatten=True)
            except Exception as ex:
                self.note(f"UNIV chunk {s.date()}..{e.date()} EXC:{ex}")
                continue
            if df is None or df.empty:
                self.note(f"UNIV chunk {s.date()}..{e.date()} EMPTY")
                continue
            cols = {c.lower().replace("_", ""): c for c in df.columns}
            oi_c = cols.get("openinterest")
            iv_c = cols.get("impliedvolatility")
            g_c = cols.get("gamma")
            lvl0 = df.index.get_level_values(0)
            for day in sorted(set(lvl0.date)):
                sub = df[lvl0.date == day]
                syms = sub.index.get_level_values(1)
                odte = [x.id.date.date() == day for x in syms]
                sub0 = sub[odte]
                n, n0 = len(sub), len(sub0)
                oi_nz = int((sub[oi_c] > 0).sum()) if oi_c else -1
                iv_nz = int((sub[iv_c] > 0).sum()) if iv_c else -1
                g_nz = int((sub[g_c] != 0).sum()) if g_c else -1
                oi0 = int((sub0[oi_c] > 0).sum()) if (oi_c and n0) else 0
                self.note(
                    f"UNIV {day} contracts={n} oi_gt0={oi_nz} iv_gt0={iv_nz} "
                    f"gamma_nz={g_nz} odte_n={n0} odte_oi_gt0={oi0}")
                if day == date(2022, 1, 28):
                    jan28_snapshot = (sub, cols)

        # --- Part C: single-day universe calls (mirrors customer usage) ----
        for d in [date(2022, 1, 27), date(2022, 1, 28), date(2022, 2, 17),
                  date(2022, 2, 18), date(2022, 2, 24), date(2022, 2, 25),
                  date(2022, 3, 3), date(2022, 3, 4), date(2022, 3, 10),
                  date(2022, 3, 11)]:
            s = datetime(d.year, d.month, d.day)
            try:
                df = self.history(spxw, s, s + timedelta(days=1), flatten=True)
                n = 0 if df is None or df.empty else len(df)
            except Exception as ex:
                n = f"EXC:{ex}"
            self.note(f"UNIV-1DAY {d} rows={n}")

        # --- Part D: contract minute data for top-volume 0DTE on 1/28 ------
        if jan28_snapshot is not None:
            sub, cols = jan28_snapshot
            syms = sub.index.get_level_values(1)
            sub0 = sub[[x.id.date.date() == date(2022, 1, 28) for x in syms]]
            vol_c = cols.get("volume")
            oi_c, iv_c, g_c = cols.get("openinterest"), cols.get("impliedvolatility"), cols.get("gamma")
            top = sub0.sort_values(vol_c, ascending=False).head(5) if vol_c else sub0.head(5)
            for idx, row in top.iterrows():
                sym = idx[1]
                try:
                    bars = self.history([sym], datetime(2022, 1, 28), datetime(2022, 1, 29), Resolution.MINUTE)
                    nb = len(bars)
                except Exception as ex:
                    nb = f"EXC:{ex}"
                self.note(
                    f"CONTRACT {sym.value} strike={sym.id.strike_price} "
                    f"right={sym.id.option_right} minute_rows={nb} "
                    f"oi={row[oi_c] if oi_c else '?'} iv={row[iv_c] if iv_c else '?'} "
                    f"gamma={row[g_c] if g_c else '?'}")
        else:
            self.note("CONTRACT check skipped - no 2022-01-28 universe snapshot found")

        self.object_store.save(REPORT_KEY, "\n".join(str(x) for x in self.lines))
        self.note("REPORT SAVED")

    def note(self, msg):
        self.lines.append(msg)
        self.log(msg)

    def on_data(self, data: Slice):
        pass