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

# Follow-up checks for ticket 215474891197531:
#  - Is the SPX gap on 2022-02-25 / 2022-03-04 minute-only, or also hour/daily?
#  - Does SPXW contract minute data exist on those two days (underlying missing)?

REPORT_KEY = "repro-215474891197531/report2.txt"


class SpxwDataGapVerification2(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
        spxw = Symbol.create_canonical_option(spx, "SPXW", Market.USA, "?SPXW")

        for d in [date(2022, 2, 24), date(2022, 2, 25), date(2022, 2, 28),
                  date(2022, 3, 3), date(2022, 3, 4), date(2022, 3, 7)]:
            s = datetime(d.year, d.month, d.day)
            e = s + timedelta(days=1)
            counts = {}
            for label, res in [("second", Resolution.SECOND),
                               ("minute", Resolution.MINUTE),
                               ("hour", Resolution.HOUR),
                               ("daily", Resolution.DAILY)]:
                try:
                    counts[label] = len(self.history([spx], s, e, res))
                except Exception as ex:
                    counts[label] = f"EXC:{type(ex).__name__}"
            self.note(f"SPX-RES {d} " + " ".join(f"{k}={v}" for k, v in counts.items()))

        # SPXW 0DTE contract minute data on the two SPX-gap days. The universe
        # row stamped D+1 contains trading day D; request a 2-day window ending
        # D+2 so the snapshot for trading day D is included.
        for d in [date(2022, 2, 25), date(2022, 3, 4)]:
            s = datetime(d.year, d.month, d.day)
            try:
                df = self.history(spxw, s - timedelta(days=1), s + timedelta(days=2), flatten=True)
            except Exception as ex:
                self.note(f"CONTRACT-DAY {d} universe EXC:{ex}")
                continue
            if df is None or df.empty:
                self.note(f"CONTRACT-DAY {d} universe EMPTY")
                continue
            cols = {c.lower().replace("_", ""): c for c in df.columns}
            vol_c, oi_c = cols.get("volume"), cols.get("openinterest")
            syms = df.index.get_level_values(1)
            expiring = df[[x.id.date.date() == d for x in syms]]
            if expiring.empty:
                self.note(f"CONTRACT-DAY {d} no contracts expiring {d} in window")
                continue
            top = expiring.sort_values(vol_c, ascending=False).head(3) if vol_c else expiring.head(3)
            seen = set()
            for idx, row in top.iterrows():
                sym = idx[1]
                if sym in seen:
                    continue
                seen.add(sym)
                try:
                    nb = len(self.history([sym], datetime(d.year, d.month, d.day),
                                          datetime(d.year, d.month, d.day) + timedelta(days=1),
                                          Resolution.MINUTE))
                except Exception as ex:
                    nb = f"EXC:{type(ex).__name__}"
                self.note(f"CONTRACT-DAY {d} {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 '?'}")

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

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

    def on_data(self, data: Slice):
        pass