diff --git a/data/sp500_history.json b/data/sp500_history.json index a882f98..0282497 100644 --- a/data/sp500_history.json +++ b/data/sp500_history.json @@ -1 +1 @@ -{"date": "2026-05-14", "intervals": {"STZ": [["2005-07-01", null]], "TPR": [[null, null]], "LMT": [[null, null]], "WY": [[null, null]], "BLDR": [["2023-12-18", null]], "PODD": [["2023-03-15", null]], "DAL": [["2013-09-10", null]], "SW": [[null, null]], "RTX": [[null, null]], "ODFL": [["2019-12-09", null]], "C": [[null, null]], "META": [[null, null]], "FTNT": [["2018-10-11", null]], "NVR": [["2019-09-26", null]], "NTRS": [[null, null]], "ORCL": [[null, null]], "PGR": [[null, null]], "UBER": [["2023-12-18", null]], "ALLE": [["2013-12-02", null]], "ON": [["2022-06-21", null]], "TT": [[null, null]], "SWKS": [["2015-03-12", null]], "GNRC": [["2021-03-22", null]], "EA": [[null, null]], "SCHW": [[null, null]], "STLD": [["2022-12-22", null]], "CAT": [[null, null]], "DE": [[null, null]], "FE": [[null, null]], "DLR": [["2016-05-18", null]], "PYPL": [["2015-07-20", null]], "UNP": [[null, null]], "HUM": [[null, null]], "TRGP": [["2022-10-12", null]], "VZ": [[null, null]], "ACN": [["2011-07-05", null]], "FFIV": [["2010-12-17", null]], "DOC": [[null, null]], "LVS": [["2019-10-03", null]], "TRMB": [["2021-01-21", null]], "NVDA": [[null, null]], "WTW": [[null, null]], "CTAS": [[null, null]], "NWSA": [["2013-07-01", null]], "D": [[null, null]], "TYL": [["2020-06-22", null]], "OKE": [[null, null]], "NFLX": [["2010-12-17", null]], "BG": [["2023-03-15", null]], "BAX": [[null, null]], "GEHC": [["2023-01-04", null]], "WEC": [[null, null]], "PFG": [[null, null]], "BX": [["2023-09-18", null]], "RMD": [["2017-07-26", null]], "APA": [[null, null]], "HPQ": [[null, null]], "J": [[null, null]], "AIG": [[null, null]], "SO": [[null, null]], "SNA": [[null, null]], "WDAY": [["2024-12-23", null]], "INTU": [["2000-12-05", null]], "PCAR": [[null, null]], "RCL": [["2014-12-05", null]], "ALGN": [["2017-06-19", null]], "EQT": [[null, "2018-11-13"], ["2022-10-03", null]], "T": [[null, null]], "AMZN": [["2005-11-18", null]], "RSG": [[null, null]], "WBD": [["2022-04-11", null]], "ANET": [["2018-08-28", null]], "DTE": [[null, null]], "COIN": [["2025-05-19", null]], "DECK": [["2024-03-18", null]], "LOW": [[null, null]], "CMI": [[null, null]], "WELL": [[null, null]], "LRCX": [["2012-06-05", null]], "SBUX": [["2000-06-07", null]], "PPG": [[null, null]], "GS": [[null, null]], "PWR": [[null, null]], "CNC": [["2016-03-30", null]], "NTAP": [[null, null]], "MNST": [["2012-06-29", null]], "COR": [[null, null]], "CRL": [["2021-05-14", null]], "RL": [[null, null]], "MPWR": [["2021-02-12", null]], "FTV": [["2016-07-05", null]], "GD": [[null, null]], "KVUE": [["2023-08-25", null]], "SYK": [[null, null]], "FCX": [[null, null]], "VMC": [[null, null]], "MDT": [[null, null]], "PSX": [["2012-04-23", null]], "STT": [[null, null]], "COF": [[null, null]], "DASH": [["2025-03-24", null]], "DGX": [[null, null]], "PH": [[null, null]], "HWM": [["2020-04-01", null]], "JCI": [[null, null]], "CDW": [["2019-09-23", null]], "APO": [["2024-12-23", null]], "LDOS": [["2019-08-09", null]], "VRSK": [["2015-10-07", null]], "NEE": [[null, null]], "PFE": [[null, null]], "IT": [["2017-04-05", null]], "AFL": [[null, null]], "ATO": [["2019-02-15", null]], "AEE": [[null, null]], "LEN": [[null, null]], "IFF": [[null, null]], "CMG": [["2011-04-27", null]], "MLM": [["2014-07-02", null]], "TTD": [["2025-07-18", null]], "ULTA": [["2016-04-18", null]], "CFG": [["2016-02-01", null]], "MGM": [["2017-07-26", null]], "LYV": [["2019-12-23", null]], "KMB": [[null, null]], "SMCI": [["2024-03-18", null]], "KEYS": [["2018-11-06", null]], "ROK": [[null, null]], "FRT": [["2016-02-01", null]], "CTVA": [["2019-06-03", null]], "VEEV": [["2026-05-07", null]], "AKAM": [[null, null]], "GLW": [[null, null]], "MSFT": [[null, null]], "TROW": [[null, null]], "DHR": [[null, null]], "MKC": [[null, null]], "AZO": [[null, null]], "FANG": [["2018-12-03", null]], "SBAC": [["2017-09-01", null]], "DOV": [[null, null]], "CL": [[null, null]], "COST": [[null, null]], "IRM": [[null, null]], "CBRE": [[null, null]], "UPS": [[null, null]], "CSX": [[null, null]], "A": [[null, null]], "MTD": [["2016-09-06", null]], "GM": [["2013-06-06", null]], "AJG": [["2016-05-31", null]], "TECH": [["2021-08-30", null]], "IR": [["2020-03-02", null]], "CINF": [[null, null]], "CVS": [[null, null]], "HCA": [["2015-01-27", null]], "MU": [[null, null]], "GDDY": [["2024-06-24", null]], "DELL": [[null, "2013-10-29"], ["2024-09-23", null]], "CPT": [["2022-04-04", null]], "HAL": [[null, null]], "CVX": [[null, null]], "HSY": [[null, null]], "CLX": [[null, null]], "IQV": [[null, null]], "PHM": [[null, null]], "HD": [[null, null]], "CHD": [["2015-12-29", null]], "OXY": [[null, null]], "AMT": [[null, null]], "KO": [[null, null]], "NCLH": [["2017-10-13", null]], "TXT": [[null, null]], "VRT": [["2026-03-23", null]], "ISRG": [[null, null]], "MRK": [[null, null]], "URI": [["2014-09-20", null]], "HST": [[null, null]], "HLT": [["2017-06-19", null]], "EXR": [["2016-01-19", null]], "OTIS": [["2020-04-03", null]], "TJX": [[null, null]], "ARES": [["2025-12-11", null]], "UHS": [["2014-09-20", null]], "AMD": [[null, "2013-09-20"], ["2017-03-20", null]], "CCI": [["2012-03-13", null]], "CDNS": [["2017-09-18", null]], "JPM": [[null, null]], "ADP": [[null, null]], "CPAY": [[null, null]], "ETN": [[null, null]], "NKE": [[null, null]], "EXC": [[null, null]], "KKR": [["2024-06-24", null]], "SYY": [[null, null]], "VTRS": [[null, null]], "PANW": [["2023-06-20", null]], "AME": [["2013-09-20", null]], "FOXA": [[null, "2019-03-19"], ["2019-03-19", null]], "CEG": [[null, "2012-03-13"], ["2022-02-02", null]], "MAR": [[null, null]], "SWK": [[null, null]], "AVB": [["2007-01-10", null]], "MA": [[null, null]], "MSI": [[null, null]], "NDAQ": [[null, null]], "CME": [[null, null]], "VLTO": [["2023-10-02", null]], "DUK": [[null, null]], "PNR": [["2012-10-01", null]], "FICO": [["2023-03-20", null]], "KLAC": [[null, null]], "LITE": [["2026-03-23", null]], "TSCO": [["2014-01-24", null]], "WAB": [["2019-02-27", null]], "MSCI": [["2018-04-04", null]], "SYF": [["2015-11-18", null]], "ALL": [[null, null]], "PCG": [[null, "2019-01-18"], ["2022-10-03", null]], "SRE": [[null, null]], "GWW": [[null, null]], "EXPD": [[null, null]], "HAS": [[null, null]], "EQR": [[null, null]], "DOW": [[null, "2017-09-01"], ["2019-04-02", null]], "CHRW": [[null, null]], "GRMN": [["2012-12-11", null]], "TER": [[null, "2013-12-23"], ["2020-09-21", null]], "PSKY": [[null, null]], "JBL": [[null, "2014-11-05"], ["2023-12-18", null]], "PKG": [["2017-07-26", null]], "PLD": [[null, null]], "LUV": [[null, null]], "SPGI": [[null, null]], "XEL": [[null, null]], "LIN": [[null, null]], "JKHY": [["2018-11-13", null]], "HOOD": [["2025-09-22", null]], "AON": [[null, null]], "ADI": [[null, null]], "RVTY": [[null, null]], "SLB": [[null, null]], "SNPS": [["2017-03-16", null]], "EW": [["2011-03-31", null]], "NI": [[null, null]], "NUE": [[null, null]], "WM": [[null, null]], "AIZ": [[null, null]], "COHR": [["2026-03-23", null]], "FDS": [["2021-12-20", null]], "AMAT": [[null, null]], "HON": [[null, null]], "O": [["2015-04-07", null]], "BR": [["2018-06-18", null]], "TEL": [[null, "2009-06-25"], ["2011-10-14", null]], "AXP": [[null, null]], "LLY": [[null, null]], "AEP": [[null, null]], "BKNG": [[null, null]], "CVNA": [["2025-12-22", null]], "UAL": [["2015-09-02", null]], "IVZ": [[null, null]], "IEX": [["2019-08-09", null]], "CASY": [["2026-04-09", null]], "BAC": [[null, null]], "POOL": [["2020-10-07", null]], "CSCO": [[null, null]], "EG": [[null, null]], "ABT": [[null, null]], "CTSH": [[null, null]], "EIX": [[null, null]], "USB": [[null, null]], "CRWD": [["2024-06-24", null]], "TSN": [[null, null]], "BRK-B": [[null, null]], "KEY": [[null, null]], "HUBB": [["2023-10-18", null]], "HPE": [["2015-11-02", null]], "GOOGL": [["2014-04-03", null]], "ROST": [["2009-12-18", null]], "CMCSA": [[null, null]], "ERIE": [["2024-09-23", null]], "CAG": [[null, null]], "GPC": [[null, null]], "FISV": [[null, null]], "WFC": [[null, null]], "COP": [[null, null]], "IDXX": [["2017-01-05", null]], "EVRG": [["2018-06-05", null]], "ITW": [[null, null]], "PLTR": [["2024-09-23", null]], "DIS": [["1976-07-01", null]], "ZTS": [["2013-06-21", null]], "PNW": [[null, null]], "UNH": [[null, null]], "MCHP": [[null, null]], "WSM": [["2025-03-24", null]], "DDOG": [["2025-07-09", null]], "AMGN": [[null, null]], "NEM": [[null, null]], "GOOG": [[null, null]], "VRSN": [[null, null]], "AMP": [[null, null]], "TSLA": [["2020-12-21", null]], "ADBE": [[null, null]], "BLK": [["2011-04-01", null]], "TMO": [[null, null]], "LULU": [["2023-10-18", null]], "CNP": [[null, null]], "VRTX": [["2013-09-20", null]], "CPRT": [["2018-07-02", null]], "FSLR": [[null, "2017-03-20"], ["2022-12-19", null]], "BKR": [["2017-07-07", null]], "AES": [[null, null]], "AVGO": [["2014-05-08", null]], "RJF": [["2017-03-20", null]], "PG": [[null, null]], "TFC": [[null, null]], "DXCM": [["2020-05-12", null]], "DG": [["2012-12-03", null]], "MOS": [["2011-09-23", null]], "HSIC": [["2015-03-18", null]], "FOX": [["2015-09-18", "2019-03-19"], ["2019-03-19", null]], "PTC": [["2021-04-20", null]], "ES": [[null, null]], "PNC": [[null, null]], "SPG": [[null, null]], "EXE": [["2025-03-24", null]], "GIS": [[null, null]], "ADSK": [[null, null]], "CBOE": [["2017-03-01", null]], "CHTR": [["2016-09-08", null]], "WMT": [[null, null]], "APTV": [[null, null]], "OMC": [[null, null]], "DPZ": [["2020-05-12", null]], "NOC": [[null, null]], "TGT": [[null, null]], "APH": [[null, null]], "TKO": [["2025-03-24", null]], "EBAY": [[null, null]], "MO": [[null, null]], "FIX": [["2025-12-22", null]], "CSGP": [["2022-09-19", null]], "NWS": [["2015-09-18", null]], "DLTR": [["2011-12-16", null]], "Q": [[null, "2011-03-31"], ["2025-11-03", null]], "XOM": [[null, null]], "CIEN": [[null, "2009-12-18"], ["2026-02-09", null]], "GE": [[null, null]], "BALL": [[null, null]], "NDSN": [["2022-02-15", null]], "MCO": [[null, null]], "ICE": [["2007-09-26", null]], "BF-B": [[null, null]], "ALB": [["2016-07-01", null]], "KHC": [["2015-07-06", null]], "EME": [["2025-09-22", null]], "DHI": [[null, null]], "COO": [["2016-09-22", null]], "AVY": [[null, null]], "WDC": [[null, null]], "BK": [[null, null]], "ACGL": [["2022-11-01", null]], "FAST": [["2008-09-12", null]], "MCD": [[null, null]], "MMM": [[null, null]], "CF": [[null, null]], "MCK": [[null, null]], "GEV": [["2024-04-02", null]], "KDP": [["2022-06-21", null]], "TRV": [[null, null]], "DRI": [[null, null]], "HII": [["2018-01-03", null]], "KR": [[null, null]], "WRB": [["2019-12-05", null]], "GEN": [[null, null]], "FDX": [[null, null]], "BIIB": [[null, null]], "CPB": [[null, null]], "BSX": [[null, null]], "IBM": [[null, null]], "TXN": [[null, null]], "JNJ": [[null, null]], "GILD": [[null, null]], "REGN": [["2013-04-30", null]], "CMS": [[null, null]], "AOS": [["2017-07-26", null]], "IBKR": [["2025-08-28", null]], "LH": [[null, null]], "TTWO": [["2018-03-19", null]], "EL": [[null, null]], "WAT": [[null, null]], "STE": [["2019-12-23", null]], "V": [["2009-12-18", null]], "WST": [["2020-05-22", null]], "WMB": [[null, null]], "NXPI": [["2021-03-22", null]], "SJM": [[null, null]], "ARE": [["2017-03-20", null]], "PPL": [[null, null]], "LHX": [[null, null]], "ADM": [[null, null]], "HRL": [["2009-03-03", null]], "BMY": [[null, null]], "MDLZ": [["2012-10-02", null]], "PRU": [[null, null]], "DVA": [[null, null]], "TDG": [["2016-06-03", null]], "ABNB": [["2023-09-18", null]], "TAP": [[null, null]], "L": [[null, null]], "ORLY": [[null, null]], "ZBH": [[null, null]], "MRSH": [[null, null]], "PAYX": [[null, null]], "QCOM": [[null, null]], "FITB": [[null, null]], "BRO": [["2021-09-20", null]], "KMI": [["2012-05-17", null]], "BDX": [[null, null]], "TPL": [["2024-11-26", null]], "VTR": [["2009-03-03", null]], "EFX": [[null, null]], "YUM": [[null, null]], "ELV": [[null, null]], "AWK": [["2016-03-04", null]], "MS": [[null, null]], "NSC": [[null, null]], "ETR": [[null, null]], "XYL": [["2011-10-31", null]], "LYB": [["2012-09-05", null]], "SATS": [["2026-03-23", null]], "CRM": [["2008-09-12", null]], "ESS": [["2014-04-02", null]], "BA": [[null, null]], "ABBV": [["2013-01-02", null]], "SHW": [[null, null]], "JBHT": [["2015-07-01", null]], "UDR": [["2016-03-07", null]], "ROP": [[null, null]], "REG": [["2017-03-02", null]], "AAPL": [[null, null]], "INCY": [["2017-02-28", null]], "KIM": [[null, null]], "MPC": [["2011-06-30", null]], "INTC": [[null, null]], "STX": [["2012-07-02", null]], "EMR": [[null, null]], "DVN": [[null, null]], "IP": [[null, null]], "AXON": [["2023-05-04", null]], "EQIX": [["2015-03-23", null]], "RF": [[null, null]], "APD": [[null, null]], "SNDK": [[null, "2016-05-13"], ["2025-11-28", null]], "CARR": [["2020-04-03", null]], "ZBRA": [["2019-12-23", null]], "VST": [["2024-05-08", null]], "MAA": [["2016-12-02", null]], "BXP": [[null, null]], "LNT": [["2016-07-01", null]], "ED": [[null, null]], "EOG": [[null, null]], "HBAN": [[null, null]], "PEP": [[null, null]], "TMUS": [["2019-07-15", null]], "VLO": [[null, null]], "CRH": [["2025-12-22", null]], "DD": [[null, "2017-09-01"], ["2019-06-03", null]], "MTB": [[null, null]], "CB": [["2010-07-14", null]], "APP": [["2025-09-22", null]], "XYZ": [["2025-07-23", null]], "LII": [["2024-12-23", null]], "AMCR": [["2019-06-11", null]], "BEN": [[null, null]], "GL": [[null, null]], "NOW": [["2019-11-21", null]], "ROL": [["2018-10-01", null]], "CAH": [[null, null]], "FIS": [[null, null]], "CI": [[null, null]], "CCL": [["1998-12-11", null]], "VICI": [["2022-06-08", null]], "MAS": [[null, null]], "INVH": [["2022-09-19", null]], "EPAM": [["2021-12-14", null]], "MET": [[null, null]], "WYNN": [[null, null]], "F": [[null, null]], "HIG": [[null, null]], "PSA": [[null, null]], "ECL": [[null, null]], "PEG": [[null, null]], "PM": [[null, null]], "GPN": [["2016-04-25", null]], "MRNA": [["2021-07-21", null]], "BBY": [[null, null]], "SOLV": [["2024-04-01", null]], "TDY": [["2020-06-22", null]], "EXPE": [["2007-10-02", null]], "NRG": [[null, null]], "CTRA": [[null, "2026-05-07"]], "HOLX": [["2016-03-30", "2026-04-09"]], "MTCH": [["2021-09-20", "2026-03-23"]], "MOH": [["2022-03-02", "2026-03-23"]], "LW": [["2018-12-03", "2026-03-23"]], "PAYC": [["2020-01-28", "2026-03-23"]], "DAY": [[null, "2026-02-09"]], "LKQ": [["2016-05-23", "2025-12-22"]], "SOLS": [["2025-10-30", "2025-12-22"]], "MHK": [["2013-12-23", "2025-12-22"]], "K": [[null, "2025-12-11"]], "IPG": [[null, "2025-11-28"]], "EMN": [[null, "2025-11-04"]], "KMX": [["2010-06-28", "2025-10-31"]], "ENPH": [["2021-01-07", "2025-09-22"]], "CZR": [["2021-03-22", "2025-09-22"]], "MKTX": [["2019-07-01", "2025-09-22"]], "WBA": [[null, "2025-08-28"]], "HES": [[null, "2025-07-23"]], "ANSS": [["2017-06-19", "2025-07-18"]], "JNPR": [["2006-06-02", "2025-07-09"]], "DFS": [["2007-07-02", "2025-05-19"]], "FMC": [["2009-08-19", "2025-03-24"]], "CE": [["2018-12-24", "2025-03-24"]], "TFX": [["2019-01-18", "2025-03-24"]], "BWA": [["2011-12-16", "2025-03-24"]], "QRVO": [["2015-06-11", "2024-12-23"]], "AMTM": [["2024-09-30", "2024-12-23"]], "CTLT": [["2020-09-21", "2024-12-23"]], "MRO": [[null, "2024-11-26"]], "BBWI": [[null, "2024-10-01"]], "AAL": [["2015-03-23", "2024-09-23"]], "ETSY": [["2020-09-21", "2024-09-23"]], "BIO": [["2020-06-22", "2024-09-23"]], "ILMN": [["2015-11-19", "2024-06-24"]], "CMA": [[null, "2024-06-24"]], "RHI": [[null, "2024-06-24"]], "PXD": [[null, "2024-05-08"]], "XRAY": [[null, "2024-04-03"]], "VFC": [[null, "2024-04-03"]], "WHR": [[null, "2024-03-18"]], "ZION": [[null, "2024-03-18"]], "SEE": [[null, "2023-12-18"]], "ALK": [["2016-05-13", "2023-12-18"]], "SEDG": [["2021-12-20", "2023-12-18"]], "ATVI": [["2015-08-28", "2023-10-18"]], "OGN": [["2021-06-03", "2023-10-18"]], "DXC": [["2017-04-04", "2023-10-03"]], "LNC": [[null, "2023-09-18"]], "NWL": [[null, "2023-09-18"]], "AAP": [["2015-07-08", "2023-08-25"]], "DISH": [["2017-03-13", "2023-06-20"]], "FRC": [["2019-01-02", "2023-05-04"]], "LUMN": [[null, "2023-03-20"]], "SBNY": [["2021-12-20", "2023-03-15"]], "SIVB": [["2018-03-19", "2023-03-15"]], "VNO": [[null, "2023-01-05"]], "ABMD": [["2018-05-31", "2022-12-22"]], "FBHS": [["2016-06-22", "2022-12-19"]], "MBC": [["2022-12-15", "2022-12-19"]], "TWTR": [["2018-06-07", "2022-11-01"]], "NLSN": [["2013-07-08", "2022-10-12"]], "CTXS": [[null, "2022-10-03"]], "DRE": [["2017-07-26", "2022-10-03"]], "PVH": [["2013-02-15", "2022-09-19"]], "PENN": [["2021-03-22", "2022-09-19"]], "UAA": [[null, "2022-06-21"]], "IPGP": [["2018-03-07", "2022-06-21"]], "UA": [["2016-04-08", "2022-06-21"]], "CERN": [["2010-04-29", "2022-06-08"]], "DISCA": [[null, "2022-04-11"]], "DISCK": [["2014-08-06", "2022-04-11"]], "PBCT": [[null, "2022-04-04"]], "INFO": [["2017-06-02", "2022-03-02"]], "XLNX": [[null, "2022-02-15"]], "GPS": [[null, "2022-02-03"]], "LEG": [[null, "2021-12-20"]], "HBI": [["2015-03-23", "2021-12-20"]], "WU": [[null, "2021-12-20"]], "KSU": [["2013-05-23", "2021-12-14"]], "PRGO": [["2011-12-16", "2021-09-20"]], "UNM": [[null, "2021-09-20"]], "NOV": [[null, "2021-09-20"]], "MXIM": [[null, "2007-09-27"], ["2018-12-03", "2021-08-30"]], "ALXN": [["2012-05-21", "2021-07-21"]], "HFC": [["2018-06-18", "2021-06-04"]], "FLIR": [[null, "2021-05-14"]], "VAR": [[null, "2021-04-20"]], "XRX": [[null, "2021-03-22"]], "VNT": [["2020-10-09", "2021-03-22"]], "FLS": [[null, "2021-03-22"]], "SLG": [["2015-03-23", "2021-03-22"]], "FTI": [["2009-06-05", "2021-02-12"]], "CXO": [["2016-02-22", "2021-01-21"]], "TIF": [[null, "2021-01-07"]], "AIV": [[null, "2020-12-21"]], "NBL": [[null, "2020-10-12"]], "ETFC": [[null, "2020-10-07"]], "HRB": [[null, "2020-09-21"]], "COTY": [["2016-09-30", "2020-09-21"]], "KSS": [[null, "2020-09-21"]], "JWN": [[null, "2020-06-22"]], "ADS": [["2013-12-23", "2020-06-22"]], "HOG": [[null, "2020-06-22"]], "HP": [["2010-02-26", "2020-05-22"]], "CPRI": [[null, "2020-05-12"]], "AGN": [[null, "2020-05-12"]], "M": [[null, "2020-04-06"]], "RTN": [[null, "2020-04-06"]], "ARNC": [["2016-11-01", "2020-04-01"]], "XEC": [["2014-06-20", "2020-03-02"]], "WCG": [["2018-09-14", "2020-01-28"]], "MAC": [["2013-05-08", "2019-12-23"]], "AMG": [["2014-07-01", "2019-12-23"]], "TRIP": [["2011-12-20", "2019-12-23"]], "STI": [[null, "2019-12-09"]], "VIAB": [[null, "2019-12-05"]], "CELG": [[null, "2019-11-21"]], "NKTR": [["2018-03-19", "2019-10-03"]], "JEF": [[null, "2019-09-26"]], "TSS": [[null, "2019-09-23"]], "APC": [[null, "2019-08-09"]], "FL": [["2016-04-04", "2019-08-09"]], "RHT": [[null, "2019-07-15"]], "LLL": [[null, "2019-07-01"]], "BMS": [[null, "2014-12-05"], ["2019-06-07", "2019-06-11"]], "MAT": [[null, "2019-06-07"]], "DWDP": [["2017-09-01", "2019-06-03"]], "FLR": [[null, "2019-06-03"]], "BHF": [["2017-08-08", "2019-04-02"]], "GT": [[null, "2019-02-27"]], "NFX": [["2010-12-17", "2019-02-15"]], "SCG": [[null, "2019-01-02"]], "ESRX": [["2003-09-25", "2018-12-24"]], "COL": [[null, "2018-12-03"]], "SRCL": [[null, "2018-12-03"]], "AET": [[null, "2018-12-03"]], "CA": [[null, "2018-11-06"]], "EVHC": [["2016-12-02", "2018-10-11"]], "ANDV": [[null, "2018-10-01"]], "XL": [[null, "2018-09-14"]], "GGP": [["2013-12-10", "2018-08-28"]], "DPS": [[null, "2018-07-02"]], "TWX": [[null, "2018-06-20"]], "AYI": [["2016-05-03", "2018-06-18"]], "RRC": [["2007-12-20", "2018-06-18"]], "MON": [[null, "2018-06-07"]], "NAVI": [["2014-05-01", "2018-06-05"]], "WYN": [[null, "2018-05-31"]], "CSRA": [["2015-12-01", "2018-04-04"]], "SIG": [["2015-07-29", "2018-03-19"]], "PDCO": [[null, "2018-03-19"]], "CHK": [[null, "2018-03-19"]], "SNI": [[null, "2018-03-07"]], "BCR": [[null, "2018-01-03"]], "LVLT": [["2014-11-05", "2017-10-13"]], "SPLS": [[null, "2017-09-18"]], "WFM": [[null, "2017-08-29"]], "AN": [[null, "2017-08-08"]], "RIG": [["2013-10-29", "2017-07-26"]], "BBBY": [[null, "2017-07-26"]], "MUR": [[null, "2017-07-26"]], "MNK": [["2014-08-18", "2017-07-26"]], "RAI": [[null, "2017-07-26"]], "BHI": [[null, "2017-07-07"]], "R": [[null, "2017-06-19"]], "MJN": [["2009-12-18", "2017-06-19"]], "TDC": [["2007-10-01", "2017-06-19"]], "YHOO": [["1999-12-08", "2017-06-19"]], "TGNA": [[null, "2017-06-02"]], "DNB": [[null, "2017-04-05"]], "SWN": [[null, "2017-04-04"]], "URBN": [[null, "2017-03-20"]], "FTR": [[null, "2017-03-20"]], "HAR": [[null, "2017-03-16"]], "LLTC": [[null, "2017-03-13"]], "ENDP": [["2015-01-27", "2017-03-02"]], "PBI": [[null, "2017-03-01"]], "SE": [[null, "2017-02-28"]], "STJ": [[null, "2017-01-05"]], "OI": [[null, "2000-12-05"], ["2008-12-31", "2016-12-02"]], "LM": [[null, "2016-12-02"]], "AA": [[null, "2016-11-01"]], "DO": [[null, "2016-09-30"]], "HOT": [[null, "2016-09-22"]], "EMC": [[null, "2016-09-08"]], "TYC": [["2010-08-26", "2016-09-06"]], "CPGX": [["2015-07-02", "2016-07-05"]], "GAS": [[null, "2011-12-12"], ["2011-12-12", "2016-07-01"]], "TE": [[null, "2016-07-01"]], "CVC": [["2010-12-17", "2016-06-22"]], "BXLT": [["2015-07-01", "2016-06-03"]], "CCE": [[null, "2016-05-31"]], "ARG": [["2009-09-28", "2016-05-23"]], "TWC": [[null, "2016-05-18"]], "ADT": [["2012-10-01", "2016-05-03"]], "GME": [["2007-12-13", "2016-04-25"]], "THC": [[null, "2016-04-18"]], "CAM": [[null, "2016-04-04"]], "POM": [[null, "2016-03-30"]], "ESV": [["2012-07-31", "2016-03-30"]], "GMCR": [["2014-03-21", "2016-03-07"]], "CNX": [[null, "2016-03-04"]], "PCL": [[null, "2016-02-22"]], "PCP": [[null, "2016-02-01"]], "BRCM": [[null, "2016-02-01"]], "ACE": [[null, "2016-01-19"]], "FOSL": [["2012-04-03", "2016-01-05"]], "ALTR": [[null, "2015-12-29"]], "CMCSK": [["2015-09-18", "2015-12-15"]], "CSC": [[null, "2015-12-01"]], "SIAL": [[null, "2015-11-19"]], "GNW": [[null, "2015-11-18"]], "HCBK": [[null, "2015-11-02"]], "JOY": [[null, "2015-10-07"]], "HSP": [[null, "2015-09-02"]], "PLL": [[null, "2015-08-28"]], "DTV": [[null, "2015-07-29"]], "NE": [[null, "2015-07-20"]], "FDO": [[null, "2015-07-08"]], "KRFT": [["2012-10-02", "2015-07-06"]], "ATI": [[null, "2015-07-02"]], "QEP": [["2010-06-30", "2015-07-01"]], "TEG": [[null, "2015-07-01"]], "LO": [["2008-06-10", "2015-06-11"]], "WIN": [[null, "2015-04-07"]], "DNR": [[null, "2015-03-23"]], "NBR": [[null, "2015-03-23"]], "AVP": [[null, "2015-03-23"]], "CFN": [[null, "2015-03-18"]], "PETM": [["2012-10-10", "2015-03-12"]], "SWY": [[null, "2015-01-27"]], "COV": [[null, "2009-06-05"], ["2011-02-28", "2015-01-27"]], "BTU": [[null, "2014-09-20"]], "GHC": [[null, "2014-09-20"]], "RDC": [[null, "2014-08-18"]], "X": [[null, "2014-07-02"]], "FRX": [[null, "2014-07-01"]], "IGT": [[null, "2014-06-20"]], "LSI": [[null, "2014-05-08"]], "BEAM": [[null, "2014-05-01"]], "SLM": [[null, "2014-05-01"]], "CLF": [["2009-12-18", "2014-04-02"]], "WPX": [["2011-12-31", "2014-03-21"]], "LIFE": [[null, "2014-01-24"]], "ANF": [[null, "2013-12-23"]], "JDSU": [["2000-07-27", "2013-12-23"]], "MOLX": [[null, "2013-12-10"]], "JCP": [[null, "2013-12-02"]], "NYX": [[null, "2013-11-13"]], "SAI": [["2009-12-18", "2013-09-20"]], "BMC": [[null, "2013-09-10"]], "S": [[null, "2013-07-08"]], "APOL": [[null, "2013-07-01"]], "FHN": [[null, "2013-06-21"]], "HNZ": [[null, "2013-06-06"]], "DF": [[null, "2013-05-23"]], "CVH": [[null, "2013-05-08"]], "PCS": [["2009-06-29", "2013-04-30"]], "BIG": [[null, "2013-02-15"]], "FII": [[null, "2013-01-02"]], "TIE": [[null, "2012-12-21"]], "RRD": [[null, "2012-12-11"]], "CBE": [[null, "2009-09-28"], ["2011-11-18", "2012-12-03"]], "SUN": [[null, "2012-10-10"]], "ANR": [["2011-06-01", "2012-10-02"]], "KFT": [["2007-03-30", "2012-10-02"]], "LXK": [[null, "2012-10-01"]], "DV": [[null, "2012-10-01"]], "SHLD": [[null, "2012-09-05"]], "GR": [[null, "2012-07-31"]], "PGN": [[null, "2012-07-02"]], "SLE": [[null, "2012-06-29"]], "NVLS": [[null, "2012-06-05"]], "MMI": [["2011-01-03", "2012-05-21"]], "EP": [[null, "2012-05-17"]], "SVU": [[null, "2012-04-23"]], "MHS": [[null, "2012-04-03"]], "CPWR": [["1998-12-11", "2011-12-31"]], "TLAB": [[null, "2011-12-20"]], "AKS": [["2008-07-01", "2011-12-16"]], "MWW": [[null, "2011-12-16"]], "WFR": [[null, "2011-12-16"]], "JNS": [[null, "2011-11-18"]], "ITT": [[null, "2011-10-31"]], "CEPH": [[null, "2011-10-14"]], "NSM": [[null, "2011-09-23"]], "MI": [[null, "2011-07-05"]], "RSH": [[null, "2011-06-30"]], "MEE": [["2008-06-23", "2011-06-01"]], "NOVL": [[null, "2011-04-27"]], "GENZ": [[null, "2011-04-01"]], "MFE": [[null, "2011-02-28"]], "AYE": [[null, "1976-07-01"], ["2000-12-05", "2011-02-25"]], "MDP": [[null, "2011-01-03"]], "ODP": [[null, "2010-12-17"]], "NYT": [[null, "2010-12-17"]], "EK": [[null, "2010-12-17"]], "KG": [[null, "2010-12-17"]], "PTV": [[null, "2010-11-17"]], "SII": [[null, "2010-08-26"]], "MIL": [[null, "2010-07-14"]], "STR": [[null, "2010-06-30"]], "XTO": [[null, "2010-06-28"]], "BJS": [[null, "2010-04-29"]], "RX": [[null, "2010-02-26"]], "KBH": [[null, "2009-12-18"]], "CVG": [["2000-06-12", "2009-12-18"]], "MBI": [[null, "2009-12-18"]], "DYN": [[null, "2009-12-18"]], "SGP": [[null, "2009-11-03"]], "CTX": [[null, "2009-08-19"]], "ACAS": [[null, "2009-03-03"]], "JNY": [[null, "2009-03-03"]], "WB": [[null, "2008-12-31"]], "LEH": [[null, "2008-09-16"]], "FNM": [[null, "2008-09-12"]], "FRE": [[null, "2008-09-12"]], "CFC": [[null, "2008-07-01"]], "BC": [[null, "2008-06-23"]], "OMX": [[null, "2008-06-23"]], "ABK": [["2000-12-05", "2008-06-10"]], "TRB": [[null, "2007-12-20"]], "DJ": [[null, "2007-12-13"]], "AV": [[null, "2007-10-26"]], "SLR": [[null, "2007-10-02"]], "NCR": [[null, "2007-10-01"]], "FDC": [[null, "2007-09-26"]], "KSE": [[null, "2007-08-24"]], "ADCT": [[null, "2007-07-02"]], "TSG": [[null, "2007-03-30"]], "SBL": [["2000-12-05", "2007-01-10"]], "ABS": [[null, "2006-06-02"]], "GLK": [[null, "2005-07-01"]], "QTRN": [[null, "2003-09-25"]], "BS": [[null, "2000-12-05"]], "GRA": [[null, "2000-12-05"]], "CCK": [[null, "2000-12-05"]], "RAD": [[null, "2000-07-27"]], "TMC": [[null, "2000-06-12"]], "SMS": [[null, "2000-06-07"]], "LDW": [[null, "1999-12-08"]], "HPH": [[null, "1999-06-09"]], "GRN": [[null, "1998-12-11"]], "USL": [[null, "1997-06-17"]], "HNG": [[null, "1976-07-01"]]}} \ No newline at end of file +{"date": "2026-05-21", "intervals": {"KO": [[null, null]], "TECH": [["2021-08-30", null]], "DG": [["2012-12-03", null]], "FTV": [["2016-07-05", null]], "LDOS": [["2019-08-09", null]], "DVN": [[null, null]], "INCY": [["2017-02-28", null]], "PH": [[null, null]], "OTIS": [["2020-04-03", null]], "FDX": [[null, null]], "CEG": [[null, "2012-03-13"], ["2022-02-02", null]], "WELL": [[null, null]], "HPQ": [[null, null]], "CIEN": [[null, "2009-12-18"], ["2026-02-09", null]], "KR": [[null, null]], "WFC": [[null, null]], "PTC": [["2021-04-20", null]], "SNA": [[null, null]], "GEN": [[null, null]], "TPR": [[null, null]], "ABNB": [["2023-09-18", null]], "BX": [["2023-09-18", null]], "WEC": [[null, null]], "EA": [[null, null]], "WYNN": [[null, null]], "TRMB": [["2021-01-21", null]], "CTSH": [[null, null]], "NCLH": [["2017-10-13", null]], "CMCSA": [[null, null]], "BALL": [[null, null]], "LHX": [[null, null]], "REG": [["2017-03-02", null]], "CNP": [[null, null]], "CDW": [["2019-09-23", null]], "CPRT": [["2018-07-02", null]], "SLB": [[null, null]], "TXT": [[null, null]], "GNRC": [["2021-03-22", null]], "BK": [[null, null]], "EW": [["2011-03-31", null]], "BRK-B": [[null, null]], "LUV": [[null, null]], "UBER": [["2023-12-18", null]], "SW": [[null, null]], "IR": [["2020-03-02", null]], "ADSK": [[null, null]], "BXP": [[null, null]], "VEEV": [["2026-05-07", null]], "UNP": [[null, null]], "CTAS": [[null, null]], "FDS": [["2021-12-20", null]], "UNH": [[null, null]], "VMC": [[null, null]], "SMCI": [["2024-03-18", null]], "DLR": [["2016-05-18", null]], "ORCL": [[null, null]], "FOX": [["2015-09-18", "2019-03-19"], ["2019-03-19", null]], "ADP": [[null, null]], "NSC": [[null, null]], "NUE": [[null, null]], "CHRW": [[null, null]], "PPL": [[null, null]], "RMD": [["2017-07-26", null]], "PNR": [["2012-10-01", null]], "RJF": [["2017-03-20", null]], "DGX": [[null, null]], "FTNT": [["2018-10-11", null]], "AMGN": [[null, null]], "GM": [["2013-06-06", null]], "BKR": [["2017-07-07", null]], "MRK": [[null, null]], "NVDA": [[null, null]], "URI": [["2014-09-20", null]], "BLDR": [["2023-12-18", null]], "VST": [["2024-05-08", null]], "MTD": [["2016-09-06", null]], "ADI": [[null, null]], "RVTY": [[null, null]], "ROL": [["2018-10-01", null]], "NTAP": [[null, null]], "EL": [[null, null]], "COST": [[null, null]], "ORLY": [[null, null]], "ERIE": [["2024-09-23", null]], "DPZ": [["2020-05-12", null]], "ALGN": [["2017-06-19", null]], "STLD": [["2022-12-22", null]], "AIG": [[null, null]], "SCHW": [[null, null]], "TRGP": [["2022-10-12", null]], "CVS": [[null, null]], "JCI": [[null, null]], "KMB": [[null, null]], "MGM": [["2017-07-26", null]], "DOW": [[null, "2017-09-01"], ["2019-04-02", null]], "IQV": [[null, null]], "PFE": [[null, null]], "HLT": [["2017-06-19", null]], "JKHY": [["2018-11-13", null]], "EBAY": [[null, null]], "FITB": [[null, null]], "AVB": [["2007-01-10", null]], "TTD": [["2025-07-18", null]], "APD": [[null, null]], "LITE": [["2026-03-23", null]], "WAB": [["2019-02-27", null]], "NWS": [["2015-09-18", null]], "CRWD": [["2024-06-24", null]], "GL": [[null, null]], "WBD": [["2022-04-11", null]], "ALB": [["2016-07-01", null]], "WY": [[null, null]], "FRT": [["2016-02-01", null]], "MPC": [["2011-06-30", null]], "EIX": [[null, null]], "EG": [[null, null]], "KDP": [["2022-06-21", null]], "STE": [["2019-12-23", null]], "JBHT": [["2015-07-01", null]], "LYB": [["2012-09-05", null]], "CL": [[null, null]], "CVNA": [["2025-12-22", null]], "BKNG": [[null, null]], "AON": [[null, null]], "AXON": [["2023-05-04", null]], "SYY": [[null, null]], "ELV": [[null, null]], "MAS": [[null, null]], "GDDY": [["2024-06-24", null]], "CRH": [["2025-12-22", null]], "CVX": [[null, null]], "BBY": [[null, null]], "PNC": [[null, null]], "NDAQ": [[null, null]], "KEYS": [["2018-11-06", null]], "COF": [[null, null]], "AVY": [[null, null]], "MSCI": [["2018-04-04", null]], "HSY": [[null, null]], "CASY": [["2026-04-09", null]], "IFF": [[null, null]], "MMM": [[null, null]], "TAP": [[null, null]], "SPG": [[null, null]], "TJX": [[null, null]], "D": [[null, null]], "SBUX": [["2000-06-07", null]], "FSLR": [[null, "2017-03-20"], ["2022-12-19", null]], "MRNA": [["2021-07-21", null]], "EQR": [[null, null]], "JNJ": [[null, null]], "RCL": [["2014-12-05", null]], "AMCR": [["2019-06-11", null]], "MSI": [[null, null]], "XYL": [["2011-10-31", null]], "IBKR": [["2025-08-28", null]], "SNDK": [[null, "2016-05-13"], ["2025-11-28", null]], "UPS": [[null, null]], "FICO": [["2023-03-20", null]], "CAT": [[null, null]], "IP": [[null, null]], "KEY": [[null, null]], "VRTX": [["2013-09-20", null]], "STT": [[null, null]], "GWW": [[null, null]], "MPWR": [["2021-02-12", null]], "AJG": [["2016-05-31", null]], "COHR": [["2026-03-23", null]], "PRU": [[null, null]], "TDG": [["2016-06-03", null]], "TGT": [[null, null]], "BAX": [[null, null]], "WSM": [["2025-03-24", null]], "TMO": [[null, null]], "CCL": [["1998-12-11", null]], "SATS": [["2026-03-23", null]], "AES": [[null, null]], "CARR": [["2020-04-03", null]], "LMT": [[null, null]], "MCO": [[null, null]], "HD": [[null, null]], "ARE": [["2017-03-20", null]], "JBL": [[null, "2014-11-05"], ["2023-12-18", null]], "QCOM": [[null, null]], "GLW": [[null, null]], "BRO": [["2021-09-20", null]], "AVGO": [["2014-05-08", null]], "OXY": [[null, null]], "GPC": [[null, null]], "CME": [[null, null]], "BF-B": [[null, null]], "COP": [[null, null]], "CI": [[null, null]], "DELL": [[null, "2013-10-29"], ["2024-09-23", null]], "VRSN": [[null, null]], "PGR": [[null, null]], "CSGP": [["2022-09-19", null]], "CRL": [["2021-05-14", null]], "BSX": [[null, null]], "ABT": [[null, null]], "CPB": [[null, null]], "AWK": [["2016-03-04", null]], "HSIC": [["2015-03-18", null]], "VRT": [["2026-03-23", null]], "FAST": [["2008-09-12", null]], "PNW": [[null, null]], "VLTO": [["2023-10-02", null]], "GEHC": [["2023-01-04", null]], "TMUS": [["2019-07-15", null]], "CPAY": [[null, null]], "SWK": [[null, null]], "KMI": [["2012-05-17", null]], "TYL": [["2020-06-22", null]], "PEG": [[null, null]], "AZO": [[null, null]], "RF": [[null, null]], "MCHP": [[null, null]], "ED": [[null, null]], "TPL": [["2024-11-26", null]], "AFL": [[null, null]], "MET": [[null, null]], "MRSH": [[null, null]], "GIS": [[null, null]], "EPAM": [["2021-12-14", null]], "CAH": [[null, null]], "TSN": [[null, null]], "PG": [[null, null]], "MLM": [["2014-07-02", null]], "AOS": [["2017-07-26", null]], "XYZ": [["2025-07-23", null]], "PCAR": [[null, null]], "ZBRA": [["2019-12-23", null]], "EXPD": [[null, null]], "USB": [[null, null]], "ON": [["2022-06-21", null]], "NRG": [[null, null]], "AAPL": [[null, null]], "POOL": [["2020-10-07", null]], "CPT": [["2022-04-04", null]], "TRV": [[null, null]], "GS": [[null, null]], "ATO": [["2019-02-15", null]], "FFIV": [["2010-12-17", null]], "PODD": [["2023-03-15", null]], "EOG": [[null, null]], "CB": [["2010-07-14", null]], "AIZ": [[null, null]], "CMG": [["2011-04-27", null]], "ARES": [["2025-12-11", null]], "KHC": [["2015-07-06", null]], "REGN": [["2013-04-30", null]], "WMB": [[null, null]], "PCG": [[null, "2019-01-18"], ["2022-10-03", null]], "FIS": [[null, null]], "MKC": [[null, null]], "LNT": [["2016-07-01", null]], "TEL": [[null, "2009-06-25"], ["2011-10-14", null]], "PYPL": [["2015-07-20", null]], "PM": [[null, null]], "PLD": [[null, null]], "WTW": [[null, null]], "CBRE": [[null, null]], "CSCO": [[null, null]], "AME": [["2013-09-20", null]], "MDLZ": [["2012-10-02", null]], "ALL": [[null, null]], "VZ": [[null, null]], "MS": [[null, null]], "L": [[null, null]], "DASH": [["2025-03-24", null]], "XOM": [[null, null]], "MCK": [[null, null]], "VLO": [[null, null]], "CSX": [[null, null]], "DE": [[null, null]], "AMD": [[null, "2013-09-20"], ["2017-03-20", null]], "FE": [[null, null]], "PSKY": [[null, null]], "PKG": [["2017-07-26", null]], "CBOE": [["2017-03-01", null]], "KKR": [["2024-06-24", null]], "FCX": [[null, null]], "IBM": [[null, null]], "GEV": [["2024-04-02", null]], "JPM": [[null, null]], "T": [[null, null]], "CCI": [["2012-03-13", null]], "EQIX": [["2015-03-23", null]], "PEP": [[null, null]], "ABBV": [["2013-01-02", null]], "ECL": [[null, null]], "FOXA": [[null, "2019-03-19"], ["2019-03-19", null]], "WRB": [["2019-12-05", null]], "ETR": [[null, null]], "VTR": [["2009-03-03", null]], "SPGI": [[null, null]], "HOOD": [["2025-09-22", null]], "GE": [[null, null]], "V": [["2009-12-18", null]], "COO": [["2016-09-22", null]], "PPG": [[null, null]], "SYF": [["2015-11-18", null]], "CINF": [[null, null]], "ROK": [[null, null]], "NDSN": [["2022-02-15", null]], "EXC": [[null, null]], "PSA": [[null, null]], "ACGL": [["2022-11-01", null]], "TSLA": [["2020-12-21", null]], "RL": [[null, null]], "MCD": [[null, null]], "HUBB": [["2023-10-18", null]], "NWSA": [["2013-07-01", null]], "O": [["2015-04-07", null]], "NI": [[null, null]], "CHTR": [["2016-09-08", null]], "HRL": [["2009-03-03", null]], "MDT": [[null, null]], "SNPS": [["2017-03-16", null]], "UAL": [["2015-09-02", null]], "RSG": [[null, null]], "LVS": [["2019-10-03", null]], "CFG": [["2016-02-01", null]], "HUM": [[null, null]], "EVRG": [["2018-06-05", null]], "VRSK": [["2015-10-07", null]], "HII": [["2018-01-03", null]], "DHR": [[null, null]], "DTE": [[null, null]], "ADBE": [[null, null]], "EXE": [["2025-03-24", null]], "HPE": [["2015-11-02", null]], "WMT": [[null, null]], "TKO": [["2025-03-24", null]], "TTWO": [["2018-03-19", null]], "NEM": [[null, null]], "TSCO": [["2014-01-24", null]], "GILD": [[null, null]], "COIN": [["2025-05-19", null]], "DXCM": [["2020-05-12", null]], "BAC": [[null, null]], "WM": [[null, null]], "LII": [["2024-12-23", null]], "COR": [[null, null]], "CDNS": [["2017-09-18", null]], "EXPE": [["2007-10-02", null]], "CF": [[null, null]], "PAYX": [[null, null]], "CNC": [["2016-03-30", null]], "META": [[null, null]], "ADM": [[null, null]], "J": [[null, null]], "KIM": [[null, null]], "GOOGL": [["2014-04-03", null]], "BMY": [[null, null]], "HAS": [[null, null]], "MNST": [["2012-06-29", null]], "EQT": [[null, "2018-11-13"], ["2022-10-03", null]], "HAL": [[null, null]], "IDXX": [["2017-01-05", null]], "IEX": [["2019-08-09", null]], "SOLV": [["2024-04-01", null]], "PANW": [["2023-06-20", null]], "IT": [["2017-04-05", null]], "GD": [[null, null]], "ROP": [[null, null]], "APP": [["2025-09-22", null]], "SRE": [[null, null]], "SJM": [[null, null]], "LULU": [["2023-10-18", null]], "OMC": [[null, null]], "ISRG": [[null, null]], "PWR": [[null, null]], "TER": [[null, "2013-12-23"], ["2020-09-21", null]], "APTV": [[null, null]], "CMS": [[null, null]], "WST": [["2020-05-22", null]], "NXPI": [["2021-03-22", null]], "HBAN": [[null, null]], "TROW": [[null, null]], "IRM": [[null, null]], "DLTR": [["2011-12-16", null]], "ALLE": [["2013-12-02", null]], "DDOG": [["2025-07-09", null]], "PFG": [[null, null]], "CHD": [["2015-12-29", null]], "DHI": [[null, null]], "INTC": [[null, null]], "WDC": [[null, null]], "Q": [[null, "2011-03-31"], ["2025-11-03", null]], "TFC": [[null, null]], "LYV": [["2019-12-23", null]], "PSX": [["2012-04-23", null]], "BEN": [[null, null]], "DVA": [[null, null]], "HST": [[null, null]], "FANG": [["2018-12-03", null]], "LH": [[null, null]], "ACN": [["2011-07-05", null]], "GOOG": [[null, null]], "MTB": [[null, null]], "STZ": [["2005-07-01", null]], "ROST": [["2009-12-18", null]], "NOC": [[null, null]], "ETN": [[null, null]], "DAL": [["2013-09-10", null]], "LEN": [[null, null]], "CTVA": [["2019-06-03", null]], "MO": [[null, null]], "CMI": [[null, null]], "CAG": [[null, null]], "EFX": [[null, null]], "LOW": [[null, null]], "PLTR": [["2024-09-23", null]], "MAR": [[null, null]], "DD": [[null, "2017-09-01"], ["2019-06-03", null]], "MOS": [["2011-09-23", null]], "NOW": [["2019-11-21", null]], "DECK": [["2024-03-18", null]], "INVH": [["2022-09-19", null]], "ODFL": [["2019-12-09", null]], "AEP": [[null, null]], "EMR": [[null, null]], "FISV": [[null, null]], "CRM": [["2008-09-12", null]], "ZBH": [[null, null]], "YUM": [[null, null]], "INTU": [["2000-12-05", null]], "APA": [[null, null]], "SBAC": [["2017-09-01", null]], "AXP": [[null, null]], "NKE": [[null, null]], "SO": [[null, null]], "HIG": [[null, null]], "ITW": [[null, null]], "AMP": [[null, null]], "CLX": [[null, null]], "EXR": [["2016-01-19", null]], "MU": [[null, null]], "APH": [[null, null]], "OKE": [[null, null]], "AMAT": [[null, null]], "VTRS": [[null, null]], "BIIB": [[null, null]], "BG": [["2023-03-15", null]], "GRMN": [["2012-12-11", null]], "HWM": [["2020-04-01", null]], "DUK": [[null, null]], "GPN": [["2016-04-25", null]], "C": [[null, null]], "ESS": [["2014-04-02", null]], "MAA": [["2016-12-02", null]], "NEE": [[null, null]], "FIX": [["2025-12-22", null]], "ES": [[null, null]], "ICE": [["2007-09-26", null]], "AEE": [[null, null]], "A": [[null, null]], "BA": [[null, null]], "UHS": [["2014-09-20", null]], "DOC": [[null, null]], "ULTA": [["2016-04-18", null]], "HON": [[null, null]], "AMT": [[null, null]], "KVUE": [["2023-08-25", null]], "F": [[null, null]], "ZTS": [["2013-06-21", null]], "EME": [["2025-09-22", null]], "DRI": [[null, null]], "BLK": [["2011-04-01", null]], "HCA": [["2015-01-27", null]], "UDR": [["2016-03-07", null]], "TXN": [[null, null]], "IVZ": [[null, null]], "DIS": [["1976-07-01", null]], "MSFT": [[null, null]], "STX": [["2012-07-02", null]], "LRCX": [["2012-06-05", null]], "LIN": [[null, null]], "NVR": [["2019-09-26", null]], "NTRS": [[null, null]], "BR": [["2018-06-18", null]], "TDY": [["2020-06-22", null]], "SYK": [[null, null]], "DOV": [[null, null]], "MA": [[null, null]], "SWKS": [["2015-03-12", null]], "TT": [[null, null]], "AKAM": [[null, null]], "BDX": [[null, null]], "SHW": [[null, null]], "WDAY": [["2024-12-23", null]], "XEL": [[null, null]], "AMZN": [["2005-11-18", null]], "KLAC": [[null, null]], "NFLX": [["2010-12-17", null]], "VICI": [["2022-06-08", null]], "RTX": [[null, null]], "LLY": [[null, null]], "PHM": [[null, null]], "WAT": [[null, null]], "APO": [["2024-12-23", null]], "ANET": [["2018-08-28", null]], "CTRA": [[null, "2026-05-07"]], "HOLX": [["2016-03-30", "2026-04-09"]], "MTCH": [["2021-09-20", "2026-03-23"]], "MOH": [["2022-03-02", "2026-03-23"]], "LW": [["2018-12-03", "2026-03-23"]], "PAYC": [["2020-01-28", "2026-03-23"]], "DAY": [[null, "2026-02-09"]], "LKQ": [["2016-05-23", "2025-12-22"]], "SOLS": [["2025-10-30", "2025-12-22"]], "MHK": [["2013-12-23", "2025-12-22"]], "K": [[null, "2025-12-11"]], "IPG": [[null, "2025-11-28"]], "EMN": [[null, "2025-11-04"]], "KMX": [["2010-06-28", "2025-10-31"]], "ENPH": [["2021-01-07", "2025-09-22"]], "CZR": [["2021-03-22", "2025-09-22"]], "MKTX": [["2019-07-01", "2025-09-22"]], "WBA": [[null, "2025-08-28"]], "HES": [[null, "2025-07-23"]], "ANSS": [["2017-06-19", "2025-07-18"]], "JNPR": [["2006-06-02", "2025-07-09"]], "DFS": [["2007-07-02", "2025-05-19"]], "FMC": [["2009-08-19", "2025-03-24"]], "CE": [["2018-12-24", "2025-03-24"]], "TFX": [["2019-01-18", "2025-03-24"]], "BWA": [["2011-12-16", "2025-03-24"]], "QRVO": [["2015-06-11", "2024-12-23"]], "AMTM": [["2024-09-30", "2024-12-23"]], "CTLT": [["2020-09-21", "2024-12-23"]], "MRO": [[null, "2024-11-26"]], "BBWI": [[null, "2024-10-01"]], "AAL": [["2015-03-23", "2024-09-23"]], "ETSY": [["2020-09-21", "2024-09-23"]], "BIO": [["2020-06-22", "2024-09-23"]], "ILMN": [["2015-11-19", "2024-06-24"]], "CMA": [[null, "2024-06-24"]], "RHI": [[null, "2024-06-24"]], "PXD": [[null, "2024-05-08"]], "XRAY": [[null, "2024-04-03"]], "VFC": [[null, "2024-04-03"]], "WHR": [[null, "2024-03-18"]], "ZION": [[null, "2024-03-18"]], "SEE": [[null, "2023-12-18"]], "ALK": [["2016-05-13", "2023-12-18"]], "SEDG": [["2021-12-20", "2023-12-18"]], "ATVI": [["2015-08-28", "2023-10-18"]], "OGN": [["2021-06-03", "2023-10-18"]], "DXC": [["2017-04-04", "2023-10-03"]], "LNC": [[null, "2023-09-18"]], "NWL": [[null, "2023-09-18"]], "AAP": [["2015-07-08", "2023-08-25"]], "DISH": [["2017-03-13", "2023-06-20"]], "FRC": [["2019-01-02", "2023-05-04"]], "LUMN": [[null, "2023-03-20"]], "SBNY": [["2021-12-20", "2023-03-15"]], "SIVB": [["2018-03-19", "2023-03-15"]], "VNO": [[null, "2023-01-05"]], "ABMD": [["2018-05-31", "2022-12-22"]], "FBHS": [["2016-06-22", "2022-12-19"]], "MBC": [["2022-12-15", "2022-12-19"]], "TWTR": [["2018-06-07", "2022-11-01"]], "NLSN": [["2013-07-08", "2022-10-12"]], "CTXS": [[null, "2022-10-03"]], "DRE": [["2017-07-26", "2022-10-03"]], "PVH": [["2013-02-15", "2022-09-19"]], "PENN": [["2021-03-22", "2022-09-19"]], "UAA": [[null, "2022-06-21"]], "IPGP": [["2018-03-07", "2022-06-21"]], "UA": [["2016-04-08", "2022-06-21"]], "CERN": [["2010-04-29", "2022-06-08"]], "DISCA": [[null, "2022-04-11"]], "DISCK": [["2014-08-06", "2022-04-11"]], "PBCT": [[null, "2022-04-04"]], "INFO": [["2017-06-02", "2022-03-02"]], "XLNX": [[null, "2022-02-15"]], "GPS": [[null, "2022-02-03"]], "LEG": [[null, "2021-12-20"]], "HBI": [["2015-03-23", "2021-12-20"]], "WU": [[null, "2021-12-20"]], "KSU": [["2013-05-23", "2021-12-14"]], "PRGO": [["2011-12-16", "2021-09-20"]], "UNM": [[null, "2021-09-20"]], "NOV": [[null, "2021-09-20"]], "MXIM": [[null, "2007-09-27"], ["2018-12-03", "2021-08-30"]], "ALXN": [["2012-05-21", "2021-07-21"]], "HFC": [["2018-06-18", "2021-06-04"]], "FLIR": [[null, "2021-05-14"]], "VAR": [[null, "2021-04-20"]], "XRX": [[null, "2021-03-22"]], "VNT": [["2020-10-09", "2021-03-22"]], "FLS": [[null, "2021-03-22"]], "SLG": [["2015-03-23", "2021-03-22"]], "FTI": [["2009-06-05", "2021-02-12"]], "CXO": [["2016-02-22", "2021-01-21"]], "TIF": [[null, "2021-01-07"]], "AIV": [[null, "2020-12-21"]], "NBL": [[null, "2020-10-12"]], "ETFC": [[null, "2020-10-07"]], "HRB": [[null, "2020-09-21"]], "COTY": [["2016-09-30", "2020-09-21"]], "KSS": [[null, "2020-09-21"]], "JWN": [[null, "2020-06-22"]], "ADS": [["2013-12-23", "2020-06-22"]], "HOG": [[null, "2020-06-22"]], "HP": [["2010-02-26", "2020-05-22"]], "CPRI": [[null, "2020-05-12"]], "AGN": [[null, "2020-05-12"]], "M": [[null, "2020-04-06"]], "RTN": [[null, "2020-04-06"]], "ARNC": [["2016-11-01", "2020-04-01"]], "XEC": [["2014-06-20", "2020-03-02"]], "WCG": [["2018-09-14", "2020-01-28"]], "MAC": [["2013-05-08", "2019-12-23"]], "AMG": [["2014-07-01", "2019-12-23"]], "TRIP": [["2011-12-20", "2019-12-23"]], "STI": [[null, "2019-12-09"]], "VIAB": [[null, "2019-12-05"]], "CELG": [[null, "2019-11-21"]], "NKTR": [["2018-03-19", "2019-10-03"]], "JEF": [[null, "2019-09-26"]], "TSS": [[null, "2019-09-23"]], "APC": [[null, "2019-08-09"]], "FL": [["2016-04-04", "2019-08-09"]], "RHT": [[null, "2019-07-15"]], "LLL": [[null, "2019-07-01"]], "BMS": [[null, "2014-12-05"], ["2019-06-07", "2019-06-11"]], "MAT": [[null, "2019-06-07"]], "DWDP": [["2017-09-01", "2019-06-03"]], "FLR": [[null, "2019-06-03"]], "BHF": [["2017-08-08", "2019-04-02"]], "GT": [[null, "2019-02-27"]], "NFX": [["2010-12-17", "2019-02-15"]], "SCG": [[null, "2019-01-02"]], "ESRX": [["2003-09-25", "2018-12-24"]], "COL": [[null, "2018-12-03"]], "SRCL": [[null, "2018-12-03"]], "AET": [[null, "2018-12-03"]], "CA": [[null, "2018-11-06"]], "EVHC": [["2016-12-02", "2018-10-11"]], "ANDV": [[null, "2018-10-01"]], "XL": [[null, "2018-09-14"]], "GGP": [["2013-12-10", "2018-08-28"]], "DPS": [[null, "2018-07-02"]], "TWX": [[null, "2018-06-20"]], "AYI": [["2016-05-03", "2018-06-18"]], "RRC": [["2007-12-20", "2018-06-18"]], "MON": [[null, "2018-06-07"]], "NAVI": [["2014-05-01", "2018-06-05"]], "WYN": [[null, "2018-05-31"]], "CSRA": [["2015-12-01", "2018-04-04"]], "SIG": [["2015-07-29", "2018-03-19"]], "PDCO": [[null, "2018-03-19"]], "CHK": [[null, "2018-03-19"]], "SNI": [[null, "2018-03-07"]], "BCR": [[null, "2018-01-03"]], "LVLT": [["2014-11-05", "2017-10-13"]], "SPLS": [[null, "2017-09-18"]], "WFM": [[null, "2017-08-29"]], "AN": [[null, "2017-08-08"]], "RIG": [["2013-10-29", "2017-07-26"]], "BBBY": [[null, "2017-07-26"]], "MUR": [[null, "2017-07-26"]], "MNK": [["2014-08-18", "2017-07-26"]], "RAI": [[null, "2017-07-26"]], "BHI": [[null, "2017-07-07"]], "R": [[null, "2017-06-19"]], "MJN": [["2009-12-18", "2017-06-19"]], "TDC": [["2007-10-01", "2017-06-19"]], "YHOO": [["1999-12-08", "2017-06-19"]], "TGNA": [[null, "2017-06-02"]], "DNB": [[null, "2017-04-05"]], "SWN": [[null, "2017-04-04"]], "URBN": [[null, "2017-03-20"]], "FTR": [[null, "2017-03-20"]], "HAR": [[null, "2017-03-16"]], "LLTC": [[null, "2017-03-13"]], "ENDP": [["2015-01-27", "2017-03-02"]], "PBI": [[null, "2017-03-01"]], "SE": [[null, "2017-02-28"]], "STJ": [[null, "2017-01-05"]], "OI": [[null, "2000-12-05"], ["2008-12-31", "2016-12-02"]], "LM": [[null, "2016-12-02"]], "AA": [[null, "2016-11-01"]], "DO": [[null, "2016-09-30"]], "HOT": [[null, "2016-09-22"]], "EMC": [[null, "2016-09-08"]], "TYC": [["2010-08-26", "2016-09-06"]], "CPGX": [["2015-07-02", "2016-07-05"]], "GAS": [[null, "2011-12-12"], ["2011-12-12", "2016-07-01"]], "TE": [[null, "2016-07-01"]], "CVC": [["2010-12-17", "2016-06-22"]], "BXLT": [["2015-07-01", "2016-06-03"]], "CCE": [[null, "2016-05-31"]], "ARG": [["2009-09-28", "2016-05-23"]], "TWC": [[null, "2016-05-18"]], "ADT": [["2012-10-01", "2016-05-03"]], "GME": [["2007-12-13", "2016-04-25"]], "THC": [[null, "2016-04-18"]], "CAM": [[null, "2016-04-04"]], "POM": [[null, "2016-03-30"]], "ESV": [["2012-07-31", "2016-03-30"]], "GMCR": [["2014-03-21", "2016-03-07"]], "CNX": [[null, "2016-03-04"]], "PCL": [[null, "2016-02-22"]], "PCP": [[null, "2016-02-01"]], "BRCM": [[null, "2016-02-01"]], "ACE": [[null, "2016-01-19"]], "FOSL": [["2012-04-03", "2016-01-05"]], "ALTR": [[null, "2015-12-29"]], "CMCSK": [["2015-09-18", "2015-12-15"]], "CSC": [[null, "2015-12-01"]], "SIAL": [[null, "2015-11-19"]], "GNW": [[null, "2015-11-18"]], "HCBK": [[null, "2015-11-02"]], "JOY": [[null, "2015-10-07"]], "HSP": [[null, "2015-09-02"]], "PLL": [[null, "2015-08-28"]], "DTV": [[null, "2015-07-29"]], "NE": [[null, "2015-07-20"]], "FDO": [[null, "2015-07-08"]], "KRFT": [["2012-10-02", "2015-07-06"]], "ATI": [[null, "2015-07-02"]], "QEP": [["2010-06-30", "2015-07-01"]], "TEG": [[null, "2015-07-01"]], "LO": [["2008-06-10", "2015-06-11"]], "WIN": [[null, "2015-04-07"]], "DNR": [[null, "2015-03-23"]], "NBR": [[null, "2015-03-23"]], "AVP": [[null, "2015-03-23"]], "CFN": [[null, "2015-03-18"]], "PETM": [["2012-10-10", "2015-03-12"]], "SWY": [[null, "2015-01-27"]], "COV": [[null, "2009-06-05"], ["2011-02-28", "2015-01-27"]], "BTU": [[null, "2014-09-20"]], "GHC": [[null, "2014-09-20"]], "RDC": [[null, "2014-08-18"]], "X": [[null, "2014-07-02"]], "FRX": [[null, "2014-07-01"]], "IGT": [[null, "2014-06-20"]], "LSI": [[null, "2014-05-08"]], "BEAM": [[null, "2014-05-01"]], "SLM": [[null, "2014-05-01"]], "CLF": [["2009-12-18", "2014-04-02"]], "WPX": [["2011-12-31", "2014-03-21"]], "LIFE": [[null, "2014-01-24"]], "ANF": [[null, "2013-12-23"]], "JDSU": [["2000-07-27", "2013-12-23"]], "MOLX": [[null, "2013-12-10"]], "JCP": [[null, "2013-12-02"]], "NYX": [[null, "2013-11-13"]], "SAI": [["2009-12-18", "2013-09-20"]], "BMC": [[null, "2013-09-10"]], "S": [[null, "2013-07-08"]], "APOL": [[null, "2013-07-01"]], "FHN": [[null, "2013-06-21"]], "HNZ": [[null, "2013-06-06"]], "DF": [[null, "2013-05-23"]], "CVH": [[null, "2013-05-08"]], "PCS": [["2009-06-29", "2013-04-30"]], "BIG": [[null, "2013-02-15"]], "FII": [[null, "2013-01-02"]], "TIE": [[null, "2012-12-21"]], "RRD": [[null, "2012-12-11"]], "CBE": [[null, "2009-09-28"], ["2011-11-18", "2012-12-03"]], "SUN": [[null, "2012-10-10"]], "ANR": [["2011-06-01", "2012-10-02"]], "KFT": [["2007-03-30", "2012-10-02"]], "LXK": [[null, "2012-10-01"]], "DV": [[null, "2012-10-01"]], "SHLD": [[null, "2012-09-05"]], "GR": [[null, "2012-07-31"]], "PGN": [[null, "2012-07-02"]], "SLE": [[null, "2012-06-29"]], "NVLS": [[null, "2012-06-05"]], "MMI": [["2011-01-03", "2012-05-21"]], "EP": [[null, "2012-05-17"]], "SVU": [[null, "2012-04-23"]], "MHS": [[null, "2012-04-03"]], "CPWR": [["1998-12-11", "2011-12-31"]], "TLAB": [[null, "2011-12-20"]], "AKS": [["2008-07-01", "2011-12-16"]], "MWW": [[null, "2011-12-16"]], "WFR": [[null, "2011-12-16"]], "JNS": [[null, "2011-11-18"]], "ITT": [[null, "2011-10-31"]], "CEPH": [[null, "2011-10-14"]], "NSM": [[null, "2011-09-23"]], "MI": [[null, "2011-07-05"]], "RSH": [[null, "2011-06-30"]], "MEE": [["2008-06-23", "2011-06-01"]], "NOVL": [[null, "2011-04-27"]], "GENZ": [[null, "2011-04-01"]], "MFE": [[null, "2011-02-28"]], "AYE": [[null, "1976-07-01"], ["2000-12-05", "2011-02-25"]], "MDP": [[null, "2011-01-03"]], "ODP": [[null, "2010-12-17"]], "NYT": [[null, "2010-12-17"]], "EK": [[null, "2010-12-17"]], "KG": [[null, "2010-12-17"]], "PTV": [[null, "2010-11-17"]], "SII": [[null, "2010-08-26"]], "MIL": [[null, "2010-07-14"]], "STR": [[null, "2010-06-30"]], "XTO": [[null, "2010-06-28"]], "BJS": [[null, "2010-04-29"]], "RX": [[null, "2010-02-26"]], "KBH": [[null, "2009-12-18"]], "CVG": [["2000-06-12", "2009-12-18"]], "MBI": [[null, "2009-12-18"]], "DYN": [[null, "2009-12-18"]], "SGP": [[null, "2009-11-03"]], "CTX": [[null, "2009-08-19"]], "ACAS": [[null, "2009-03-03"]], "JNY": [[null, "2009-03-03"]], "WB": [[null, "2008-12-31"]], "LEH": [[null, "2008-09-16"]], "FNM": [[null, "2008-09-12"]], "FRE": [[null, "2008-09-12"]], "CFC": [[null, "2008-07-01"]], "BC": [[null, "2008-06-23"]], "OMX": [[null, "2008-06-23"]], "ABK": [["2000-12-05", "2008-06-10"]], "TRB": [[null, "2007-12-20"]], "DJ": [[null, "2007-12-13"]], "AV": [[null, "2007-10-26"]], "SLR": [[null, "2007-10-02"]], "NCR": [[null, "2007-10-01"]], "FDC": [[null, "2007-09-26"]], "KSE": [[null, "2007-08-24"]], "ADCT": [[null, "2007-07-02"]], "TSG": [[null, "2007-03-30"]], "SBL": [["2000-12-05", "2007-01-10"]], "ABS": [[null, "2006-06-02"]], "GLK": [[null, "2005-07-01"]], "QTRN": [[null, "2003-09-25"]], "BS": [[null, "2000-12-05"]], "GRA": [[null, "2000-12-05"]], "CCK": [[null, "2000-12-05"]], "RAD": [[null, "2000-07-27"]], "TMC": [[null, "2000-06-12"]], "SMS": [[null, "2000-06-07"]], "LDW": [[null, "1999-12-08"]], "HPH": [[null, "1999-06-09"]], "GRN": [[null, "1998-12-11"]], "USL": [[null, "1997-06-17"]], "HNG": [[null, "1976-07-01"]]}} \ No newline at end of file diff --git a/main.py b/main.py index 8a40e3e..fbfb5bf 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ import pandas as pd import data_manager import factor_attribution import metrics +import universe_history as uh from strategies.adaptive_momentum import AdaptiveMomentumStrategy from strategies.buy_and_hold import BuyAndHoldStrategy from strategies.dual_momentum import DualMomentumStrategy @@ -30,6 +31,8 @@ def backtest( initial_capital: float = 100_000, transaction_cost: float = 0.001, fixed_fee: float = 0.0, + fee_base: float = 0.0, + fee_per_share: float = 0.0, open_data: pd.DataFrame | None = None, ) -> pd.Series: """ @@ -46,14 +49,17 @@ def backtest( transaction_cost : float One-way cost per unit of turnover (e.g. 0.001 = 10 bps). fixed_fee : float - Fixed dollar cost per individual trade (each buy or sell). + Floor of the per-trade fee (e.g. 2.0 = $2 minimum per buy/sell). + With fee_per_share=0 (default), this is also the actual per-trade fee. + fee_base : float + Fixed component of a per-share tiered fee schedule. The actual + per-trade fee is ``max(fixed_fee, fee_base + fee_per_share * shares)``. + fee_per_share : float + Per-share variable component of the tiered fee (e.g. 0.009 = $0.009/share). + With fee_base=1.88 + fee_per_share=0.009 + fixed_fee=2.0 you get an + IBKR-style schedule: max(2, 1.88 + 0.009 * shares). open_data : pd.DataFrame, optional - Open prices. When provided, enables open-to-close execution mode: - - Morning: observe open prices → run strategy → decide weights - - Evening: execute all trades at close prices - Strategies have an internal shift(1) designed for close prices. - Since open prices are observable same-day (before close), we undo - that shift so signals use today's open and execute at today's close. + Open prices. When provided, enables open-to-close execution mode. Returns ------- @@ -86,13 +92,32 @@ def backtest( turnover = positions.diff().abs().sum(axis=1).fillna(0.0) portfolio_returns -= turnover * transaction_cost - # Fixed per-trade fee: count positions with non-zero weight change - if fixed_fee > 0: + # Per-trade fee. Supports both flat ($2/trade) and tiered (IBKR-style) + # schedules: fee = max(fixed_fee, fee_base + fee_per_share * shares). + if fixed_fee > 0 or fee_base > 0 or fee_per_share > 0: weight_changes = positions.diff().fillna(0.0) - n_trades = (weight_changes.abs() > 1e-8).sum(axis=1) - # Build running equity to convert dollar fees to return impact equity_running = (1 + portfolio_returns).cumprod() * initial_capital - fee_impact = (n_trades * fixed_fee) / equity_running.shift(1).fillna(initial_capital) + eq_prev = equity_running.shift(1).fillna(initial_capital) + + if fee_per_share > 0: + # Convert per-ticker weight change into share count traded. + # dollar_traded[i, t] = |w[i,t] - w[i,t-1]| * equity[t-1] + # shares_traded[i, t] = dollar_traded / price[i, t] + dollar_traded = weight_changes.abs().mul(eq_prev, axis=0) + shares_traded = dollar_traded.div(data).replace( + [np.inf, -np.inf], 0.0, + ).fillna(0.0) + per_trade_fee = (fee_base + fee_per_share * shares_traded).clip( + lower=fixed_fee, + ) + trade_mask = weight_changes.abs() > 1e-8 + per_trade_fee = per_trade_fee.where(trade_mask, 0.0) + daily_fee = per_trade_fee.sum(axis=1) + else: + n_trades = (weight_changes.abs() > 1e-8).sum(axis=1) + daily_fee = n_trades * fixed_fee + + fee_impact = daily_fee / eq_prev portfolio_returns -= fee_impact equity = (1 + portfolio_returns).cumprod() * initial_capital @@ -184,7 +209,16 @@ def main() -> None: tickers = universe["fetch"]() benchmark = universe["benchmark"] benchmark_label = universe["benchmark_label"] - all_tickers = sorted(set(tickers + [benchmark])) + + # PIT universe: include all historical index members for US market + pit_intervals = None + if args.market == "us": + pit_intervals = uh.load_sp500_history() + historical_tickers = uh.all_tickers_ever(pit_intervals) + all_tickers = sorted(set(tickers + historical_tickers + [benchmark])) + print(f"--- PIT universe: {len(all_tickers)} tickers (current + historical members) ---") + else: + all_tickers = sorted(set(tickers + [benchmark])) result = data_manager.update(args.market, all_tickers, with_open=use_open) if use_open: @@ -200,8 +234,18 @@ def main() -> None: open_data = open_data[open_data.index >= cutoff] print(f"--- Sliced to last {args.years} years: {data.index[0].date()} to {data.index[-1].date()} ---") - # Filter tickers to only those in the data - tickers = [t for t in tickers if t in data.columns] + # Apply PIT mask: NaN out prices for non-member dates + if pit_intervals is not None: + print("--- Applying PIT membership mask (survivorship-bias fix) ---") + data = uh.mask_prices(data, pit_intervals) + if open_data is not None: + open_data = uh.mask_prices(open_data, pit_intervals) + + # Filter tickers to only those with any valid data + if pit_intervals is not None: + tickers = [t for t in data.columns if t != benchmark and data[t].notna().any()] + else: + tickers = [t for t in tickers if t in data.columns] print(f"--- Universe: {len(tickers)} stocks + {benchmark} benchmark ---") top_n = args.top_n if args.top_n else max(5, len(tickers) // 10) diff --git a/metrics.py b/metrics.py index 0b10495..c306285 100644 --- a/metrics.py +++ b/metrics.py @@ -52,6 +52,21 @@ def win_rate(returns: pd.Series) -> float: return (active > 0).sum() / len(active) +def raw_summary(equity: pd.Series) -> dict: + """Return numeric metrics suitable for JSON serialization.""" + returns = equity.pct_change().dropna() + return { + "totalReturn": float(total_return(equity)), + "annualizedReturn": float(annualized_return(equity)), + "annualizedVolatility": float(annualized_volatility(returns)), + "sharpeRatio": float(sharpe_ratio(returns)), + "sortinoRatio": float(sortino_ratio(returns)), + "maxDrawdown": float(max_drawdown(equity)), + "calmarRatio": float(calmar_ratio(equity)), + "winRate": float(win_rate(returns)), + } + + def summary(equity: pd.Series, name: str = "Strategy") -> dict: returns = equity.pct_change().dropna() metrics = { diff --git a/strategies/buy_and_hold.py b/strategies/buy_and_hold.py index d058214..45e8a5e 100644 --- a/strategies/buy_and_hold.py +++ b/strategies/buy_and_hold.py @@ -12,4 +12,4 @@ class BuyAndHoldStrategy(Strategy): """ tickers = data.columns weights = pd.DataFrame(1 / len(tickers), index=data.index, columns=tickers) - return weights + return weights.shift(1).fillna(0.0) diff --git a/strategies/dual_momentum.py b/strategies/dual_momentum.py index af8a77f..c4569f6 100644 --- a/strategies/dual_momentum.py +++ b/strategies/dual_momentum.py @@ -30,9 +30,9 @@ class DualMomentumStrategy(Strategy): all_positive = (short_mom > 0) & (med_mom > 0) & (long_mom > 0) # Composite score: average percentile rank across timeframes - short_rank = short_mom.rank(axis=1, pct=True, na_option="bottom") - med_rank = med_mom.rank(axis=1, pct=True, na_option="bottom") - long_rank = long_mom.rank(axis=1, pct=True, na_option="bottom") + short_rank = short_mom.rank(axis=1, pct=True, na_option="keep") + med_rank = med_mom.rank(axis=1, pct=True, na_option="keep") + long_rank = long_mom.rank(axis=1, pct=True, na_option="keep") composite = (short_rank + med_rank + long_rank) / 3 # Only consider stocks passing absolute filter diff --git a/strategies/ensemble_alpha.py b/strategies/ensemble_alpha.py index cced1a9..f0b5f1a 100644 --- a/strategies/ensemble_alpha.py +++ b/strategies/ensemble_alpha.py @@ -84,17 +84,6 @@ class EnsembleAlphaStrategy(Strategy): row_sums = raw.sum(axis=1).replace(0, np.nan) signals = raw.div(row_sums, axis=0).fillna(0.0) - # === Tail-risk protection === - if self.tail_protection: - # Portfolio equity proxy: equal-weight market return - mkt_ret = ret.mean(axis=1) - mkt_eq = (1 + mkt_ret).cumprod() - mkt_dd = mkt_eq / mkt_eq.cummax() - 1 - in_tail = mkt_dd < self.tail_threshold - scale = pd.Series(1.0, index=data.index) - scale[in_tail] = self.tail_scale - signals = signals.mul(scale, axis=0) - # === Monthly rebalance === warmup = 252 rebal_mask = pd.Series(False, index=data.index) @@ -105,6 +94,20 @@ class EnsembleAlphaStrategy(Strategy): signals = signals.ffill().fillna(0.0) signals.iloc[:warmup] = 0.0 + # === Tail-risk protection (rebal-gated; NaN-safe market mean) === + # Apply AFTER ffill so the scale changes only at rebal points, + # otherwise daily flips force half-out/half-in trades that burn + # the account through fixed per-trade fees. + if self.tail_protection: + mkt_ret = ret.mean(axis=1, skipna=True) + mkt_eq = (1 + mkt_ret.fillna(0.0)).cumprod() + mkt_dd = mkt_eq / mkt_eq.cummax() - 1 + in_tail = mkt_dd < self.tail_threshold + scale_raw = pd.Series(1.0, index=data.index) + scale_raw[in_tail] = self.tail_scale + scale = scale_raw.where(rebal_mask, np.nan).ffill().fillna(1.0) + signals = signals.mul(scale, axis=0) + return signals.shift(1).fillna(0.0) @@ -162,16 +165,6 @@ class EnhancedFactorComboStrategy(Strategy): row_sums = raw.sum(axis=1).replace(0, np.nan) signals = raw.div(row_sums, axis=0).fillna(0.0) - # Tail protection - if self.tail_protection: - mkt_ret = ret.mean(axis=1) - mkt_eq = (1 + mkt_ret).cumprod() - mkt_dd = mkt_eq / mkt_eq.cummax() - 1 - in_tail = mkt_dd < -0.15 - scale = pd.Series(1.0, index=data.index) - scale[in_tail] = 0.5 - signals = signals.mul(scale, axis=0) - # Monthly rebalance warmup = 252 rebal_mask = pd.Series(False, index=data.index) @@ -182,6 +175,17 @@ class EnhancedFactorComboStrategy(Strategy): signals = signals.ffill().fillna(0.0) signals.iloc[:warmup] = 0.0 + # Tail protection (rebal-gated to avoid daily-flip turnover) + if self.tail_protection: + mkt_ret = ret.mean(axis=1, skipna=True) + mkt_eq = (1 + mkt_ret.fillna(0.0)).cumprod() + mkt_dd = mkt_eq / mkt_eq.cummax() - 1 + in_tail = mkt_dd < -0.15 + scale_raw = pd.Series(1.0, index=data.index) + scale_raw[in_tail] = 0.5 + scale = scale_raw.where(rebal_mask, np.nan).ffill().fillna(1.0) + signals = signals.mul(scale, axis=0) + return signals.shift(1).fillna(0.0) @@ -230,31 +234,41 @@ class RiskManagedEnsembleStrategy(Strategy): # Step 1: Get raw signals from the ensemble (already shifted by 1) raw = self.ensemble.generate_signals(data) - # Step 2: Compute MARKET returns (equal-weight of all stocks) - daily_rets = data.pct_change().fillna(0.0) - mkt_rets = daily_rets.mean(axis=1) + # Step 2: Compute MARKET returns over valid (non-masked) columns. + # `daily_rets` keeps NaN for PIT-masked tickers so they don't dilute + # the cross-sectional mean to ~0. + daily_rets = data.pct_change() + mkt_rets = daily_rets.mean(axis=1, skipna=True) # Step 3: Market drawdown dampener - mkt_eq = (1 + mkt_rets).cumprod() - mkt_dd = mkt_eq / mkt_eq.cummax() - 1 # always ≤ 0 - # Linear: at DD=0 → 1.0, at DD=-dd_denom → dd_floor - dd_scale = (1.0 + mkt_dd / self.dd_denom).clip(lower=self.dd_floor, upper=1.0) - dd_scale_lagged = dd_scale.shift(1).fillna(1.0) # PIT + mkt_eq = (1 + mkt_rets.fillna(0.0)).cumprod() + mkt_dd = mkt_eq / mkt_eq.cummax() - 1 + dd_scale_raw = (1.0 + mkt_dd / self.dd_denom).clip( + lower=self.dd_floor, upper=1.0, + ) - # Step 4: Vol spike guard (uses portfolio's own vol for specificity) + # Step 4: Vol spike guard from portfolio returns (NaN-aware sum) if self.vol_spike_guard: - port_rets = (raw * daily_rets).sum(axis=1) + port_rets = (raw * daily_rets).sum(axis=1, min_count=1).fillna(0.0) short_vol = port_rets.rolling(self.vol_spike_window, min_periods=5).std() * np.sqrt(252) vol_90th = short_vol.rolling(self.vol_spike_lookback, min_periods=126).quantile(0.90) in_spike = short_vol > vol_90th - vol_scale = pd.Series(1.0, index=data.index) - vol_scale[in_spike] = self.vol_spike_floor - vol_scale_lagged = vol_scale.shift(1).fillna(1.0) # PIT + vol_scale_raw = pd.Series(1.0, index=data.index) + vol_scale_raw[in_spike] = self.vol_spike_floor else: - vol_scale_lagged = 1.0 + vol_scale_raw = pd.Series(1.0, index=data.index) + + # Step 5: Combined scaling, sampled at the inner ensemble's rebal + # cadence so we don't trade in/out daily (which would incur huge + # fixed-fee costs). + combined = (dd_scale_raw * vol_scale_raw).shift(1).fillna(1.0) + rebal_freq = getattr(self.ensemble, "rebal_freq", 21) + warmup = 252 + rebal_mask = pd.Series(False, index=data.index) + rebal_indices = list(range(warmup, len(data), rebal_freq)) + rebal_mask.iloc[rebal_indices] = True + final_scale = combined.where(rebal_mask, np.nan).ffill().fillna(1.0) - # Step 5: Combined scaling - final_scale = dd_scale_lagged * vol_scale_lagged return raw.mul(final_scale, axis=0) @@ -342,26 +356,31 @@ class SharpeBoostedEnsembleStrategy(Strategy): signals = signals.shift(1).fillna(0.0) # PIT: 1-day execution lag # === Asymmetric vol scaling === - # Only reduce exposure when vol is high AND returns are negative - # High vol + positive returns = riding a trend, don't cut - daily_rets = data.pct_change().fillna(0.0) - port_rets = (signals * daily_rets).sum(axis=1) + # NB: scales are RE-EVALUATED only on rebalance days. Daily flips of + # asym/dd scales would force half-in/half-out trades each session, + # burning the account through fixed per-trade fees ($2 US / $5 CN). + # Use cross-sectional mean of non-masked returns so PIT-masked + # NaN→0 fills don't dilute the market signal. + daily_rets = data.pct_change() + port_rets = (signals * daily_rets).sum(axis=1, min_count=1).fillna(0.0) short_vol = port_rets.rolling(20, min_periods=10).std() * np.sqrt(252) vol_median = short_vol.rolling(252, min_periods=126).median() recent_ret = port_rets.rolling(20, min_periods=10).sum() high_vol_neg = (short_vol > vol_median * 1.5) & (recent_ret < 0) - asym_scale = pd.Series(1.0, index=data.index) - asym_scale[high_vol_neg] = self.asym_vol_floor - signals = signals.mul(asym_scale.shift(1).fillna(1.0), axis=0) # PIT + asym_scale_raw = pd.Series(1.0, index=data.index) + asym_scale_raw[high_vol_neg] = self.asym_vol_floor - # === Light market-DD dampener === - # Uses market (not strategy) drawdown to avoid negative feedback loop - mkt_rets = daily_rets.mean(axis=1) - mkt_eq = (1 + mkt_rets).cumprod() + # === Market-DD dampener (rebal-gated, NaN-aware market mean) === + mkt_rets = daily_rets.mean(axis=1, skipna=True) + mkt_eq = (1 + mkt_rets.fillna(0.0)).cumprod() mkt_dd = mkt_eq / mkt_eq.cummax() - 1 - dd_scale = (1.0 + mkt_dd / self.dd_denom).clip( + dd_scale_raw = (1.0 + mkt_dd / self.dd_denom).clip( lower=self.dd_floor, upper=1.0 ) - signals = signals.mul(dd_scale.shift(1).fillna(1.0), axis=0) # PIT + + # Sample scales at rebal points only, then step-hold between rebals. + combined = (asym_scale_raw * dd_scale_raw).shift(1).fillna(1.0) + rebal_scale = combined.where(rebal_mask, np.nan).ffill().fillna(1.0) + signals = signals.mul(rebal_scale, axis=0) return signals diff --git a/strategies/trend_rider_v6.py b/strategies/trend_rider_v6.py index cc779ee..cf967ee 100644 --- a/strategies/trend_rider_v6.py +++ b/strategies/trend_rider_v6.py @@ -89,11 +89,13 @@ class TrendRiderV6(TrendRiderV5): def _resolve_universe(self, prices: pd.DataFrame) -> list[str]: if self.stock_universe is not None: return [s for s in self.stock_universe if s in prices.columns] - # Heuristic: stocks are columns NOT in our known ETF/leveraged set - non_stock = (set(self.core_equity) - | set(self.leveraged_equity) + # Heuristic: stocks are columns NOT in our known ETF/leveraged set. + # We inherit V3's risk_on (e.g. TQQQ/UPRO) and risk_off (GLD/DBC), + # plus V6's risk_off_basket + moderate_anchor + signal + overlay sym. + non_stock = (set(self.risk_on) | set(self.risk_off) - | {self.signal, *self.risk_off_basket, self.moderate_anchor}) + | {self.signal, self.moderate_anchor, + self.leverage_overlay_symbol, *self.risk_off_basket}) return [c for c in prices.columns if c not in non_stock] def _stock_top_n_weights(self, prices: pd.DataFrame, universe: list[str]) -> pd.DataFrame: