| 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