|
1 |
+"""Static reference table of futures roots (lake / FirstRate root codes). |
|
2 |
+ |
|
3 |
+Values come from the exchange contract specifications (CME Group, ICE, Eurex, Euronext, Cboe). |
|
4 |
+Fields left `None` are *not* known with certainty and stay null — the API never invents values. |
|
5 |
+Roots present in the lake but absent here get a `derived` entry (name from meta/futures/futures.csv, |
|
6 |
+`expiry_rule="data"`). |
|
7 |
+ |
|
8 |
+RTH windows are US/Eastern clock times used by the `session=rth|eth` filter; default 09:30–16:00. |
|
9 |
+ |
|
10 |
+Author: Simon-Pierre Boucher <contact@spboucher.ai> |
|
11 |
+""" |
|
12 |
+from __future__ import annotations |
|
13 |
+ |
|
14 |
+from dataclasses import asdict, dataclass, field |
|
15 |
+ |
|
16 |
+from .symbols import ALIASES_OF_ROOT |
|
17 |
+ |
|
18 |
+ALL_MONTHS = "FGHJKMNQUVXZ" |
|
19 |
+QUARTERLY = "HMUZ" |
|
20 |
+DEFAULT_RTH = ("09:30", "16:00") |
|
21 |
+ |
|
22 |
+ |
|
23 |
+@dataclass(frozen=True) |
|
24 |
+class RootSpec: |
|
25 |
+ root: str |
|
26 |
+ name: str | None |
|
27 |
+ exchange: str | None |
|
28 |
+ asset_class: str | None |
|
29 |
+ currency: str | None = None |
|
30 |
+ contract_size: float | None = None |
|
31 |
+ contract_size_unit: str | None = None |
|
32 |
+ tick_size: float | None = None |
|
33 |
+ tick_value: float | None = None |
|
34 |
+ settlement_type: str | None = None # cash | physical |
|
35 |
+ month_cycle: str | None = None |
|
36 |
+ expiry_rule: str = "data" |
|
37 |
+ first_notice_rule: str | None = None # key in expiry.FIRST_NOTICE_RULES |
|
38 |
+ calendar: str = "us" # us | eurex (business-day calendar used by the rules) |
|
39 |
+ rth: tuple[str, str] = DEFAULT_RTH # US/Eastern |
|
40 |
+ source: str = "reference" |
|
41 |
+ aliases: list[str] = field(default_factory=list) |
|
42 |
+ |
|
43 |
+ def as_dict(self) -> dict: |
|
44 |
+ d = asdict(self) |
|
45 |
+ d["rth_start"], d["rth_end"] = self.rth |
|
46 |
+ del d["rth"] |
|
47 |
+ return d |
|
48 |
+ |
|
49 |
+ |
|
50 |
+def _s(root: str, name: str, exchange: str, asset_class: str, currency: str = "USD", **kw) -> RootSpec: |
|
51 |
+ kw.setdefault("aliases", ALIASES_OF_ROOT.get(root, [])) |
|
52 |
+ return RootSpec(root=root, name=name, exchange=exchange, asset_class=asset_class, currency=currency, **kw) |
|
53 |
+ |
|
54 |
+ |
|
55 |
+_EQ = dict(asset_class="equity_index", settlement_type="cash", month_cycle=QUARTERLY, expiry_rule="third_friday") |
|
56 |
+_EQX = {**_EQ, "expiry_rule": "third_friday_eurex", "calendar": "eurex", "rth": ("03:00", "11:30")} |
|
57 |
+_EN = dict(asset_class="energy", month_cycle=ALL_MONTHS, rth=("09:00", "14:30")) |
|
58 |
+_MT = dict(asset_class="metals", settlement_type="physical", expiry_rule="metals_rule", |
|
59 |
+ first_notice_rule="prior_month_last_business_day", rth=("08:20", "13:30")) |
|
60 |
+_TR = dict(asset_class="rates", settlement_type="physical", month_cycle=QUARTERLY, expiry_rule="treasury_rule", |
|
61 |
+ first_notice_rule="prior_month_last_business_day", rth=("08:20", "15:00")) |
|
62 |
+_GR = dict(asset_class="ags", settlement_type="physical", expiry_rule="grains_rule", |
|
63 |
+ first_notice_rule="prior_month_last_business_day", rth=("09:30", "14:20")) |
|
64 |
+_FX = dict(asset_class="fx", settlement_type="physical", month_cycle=QUARTERLY, expiry_rule="fx_rule", rth=("08:20", "15:00")) |
|
65 |
+_BUND = dict(asset_class="rates", settlement_type="physical", month_cycle=QUARTERLY, expiry_rule="bund_rule", |
|
66 |
+ calendar="eurex", rth=("02:00", "16:00")) |
|
67 |
+ |
|
68 |
+SPECS: list[RootSpec] = [ |
|
69 |
+ # ---- equity index (CME / CBOT) -------------------------------------------------------------------- |
|
70 |
+ _s("ES", "E-mini S&P 500", "CME", contract_size=50, contract_size_unit="USD x index", tick_size=0.25, tick_value=12.5, **_EQ), |
|
71 |
+ _s("NQ", "E-mini Nasdaq-100", "CME", contract_size=20, contract_size_unit="USD x index", tick_size=0.25, tick_value=5.0, **_EQ), |
|
72 |
+ _s("YM", "E-mini Dow ($5)", "CBOT", contract_size=5, contract_size_unit="USD x index", tick_size=1.0, tick_value=5.0, **_EQ), |
|
73 |
+ _s("RTY", "E-mini Russell 2000", "CME", contract_size=50, contract_size_unit="USD x index", tick_size=0.10, tick_value=5.0, **_EQ), |
|
74 |
+ _s("MES", "Micro E-mini S&P 500", "CME", contract_size=5, contract_size_unit="USD x index", tick_size=0.25, tick_value=1.25, **_EQ), |
|
75 |
+ _s("MNQ", "Micro E-mini Nasdaq-100", "CME", contract_size=2, contract_size_unit="USD x index", tick_size=0.25, tick_value=0.5, **_EQ), |
|
76 |
+ _s("M2K", "Micro E-mini Russell 2000", "CME", contract_size=5, contract_size_unit="USD x index", tick_size=0.10, tick_value=0.5, **_EQ), |
|
77 |
+ _s("EW", "E-mini S&P MidCap 400", "CME", contract_size=100, contract_size_unit="USD x index", tick_size=0.10, tick_value=10.0, **_EQ), |
|
78 |
+ _s("ESG", "E-mini S&P 500 ESG", "CME", contract_size=50, contract_size_unit="USD x index", tick_size=0.25, tick_value=12.5, **_EQ), |
|
79 |
+ _s("XAE", "E-mini Energy Select Sector", "CME", **_EQ), |
|
80 |
+ _s("XAF", "E-mini Financial Select Sector", "CME", **_EQ), |
|
81 |
+ _s("XAI", "E-mini Industrial Select Sector", "CME", **_EQ), |
|
82 |
+ _s("NKD", "Nikkei 225 (USD)", "CME", contract_size=5, contract_size_unit="USD x index", tick_size=5.0, tick_value=25.0, |
|
83 |
+ asset_class="equity_index", settlement_type="cash", month_cycle=QUARTERLY, expiry_rule="second_friday_minus_1"), |
|
84 |
+ _s("NIY", "Nikkei 225 (JPY)", "CME", currency="JPY", contract_size=500, contract_size_unit="JPY x index", tick_size=5.0, tick_value=2500.0, |
|
85 |
+ asset_class="equity_index", settlement_type="cash", month_cycle=QUARTERLY, expiry_rule="second_friday_minus_1"), |
|
86 |
+ _s("GSCI", "S&P GSCI", "CME", contract_size=250, contract_size_unit="USD x index", tick_size=0.05, tick_value=12.5, |
|
87 |
+ asset_class="equity_index", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
88 |
+ _s("MFS", "Mini MSCI EAFE", "ICE US", contract_size=50, contract_size_unit="USD x index", tick_size=0.05, tick_value=2.5, **_EQ), |
|
89 |
+ _s("MME", "Mini MSCI Emerging Markets", "ICE US", contract_size=50, contract_size_unit="USD x index", tick_size=0.05, tick_value=2.5, **_EQ), |
|
90 |
+ # ---- equity index (Europe) ------------------------------------------------------------------------ |
|
91 |
+ _s("FDAX", "DAX", "EUREX", currency="EUR", contract_size=25, contract_size_unit="EUR x index", tick_size=1.0, tick_value=25.0, **_EQX), |
|
92 |
+ _s("FDXM", "Mini-DAX", "EUREX", currency="EUR", contract_size=5, contract_size_unit="EUR x index", tick_size=1.0, tick_value=5.0, **_EQX), |
|
93 |
+ _s("FDXS", "Micro-DAX", "EUREX", currency="EUR", contract_size=1, contract_size_unit="EUR x index", tick_size=1.0, tick_value=1.0, **_EQX), |
|
94 |
+ _s("FESX", "Euro Stoxx 50", "EUREX", currency="EUR", contract_size=10, contract_size_unit="EUR x index", tick_size=1.0, tick_value=10.0, **_EQX), |
|
95 |
+ _s("FXXP", "Stoxx Europe 600", "EUREX", currency="EUR", contract_size=50, contract_size_unit="EUR x index", tick_size=0.10, tick_value=5.0, **_EQX), |
|
96 |
+ _s("FSMX", "Mini-MDAX", "EUREX", currency="EUR", **_EQX), |
|
97 |
+ _s("FTDX", "TecDAX", "EUREX", currency="EUR", **_EQX), |
|
98 |
+ _s("FDIV", "DivDAX", "EUREX", currency="EUR", **_EQX), |
|
99 |
+ _s("FMWO", "MSCI World", "EUREX", currency="USD", **_EQX), |
|
100 |
+ _s("MURA", "MSCI China", "EUREX", currency="USD", **_EQX), |
|
101 |
+ _s("ZRPA", "MSCI Europe", "EUREX", currency="EUR", **_EQX), |
|
102 |
+ _s("ZTWA", "MSCI Emerging Markets Asia", "EUREX", currency="USD", **_EQX), |
|
103 |
+ _s("FVSA", "VSTOXX", "EUREX", currency="EUR", contract_size=100, contract_size_unit="EUR x index", tick_size=0.05, tick_value=5.0, |
|
104 |
+ asset_class="volatility", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="vx_rule", calendar="eurex", rth=("03:00", "11:30")), |
|
105 |
+ _s("FCE", "CAC 40", "Euronext", currency="EUR", contract_size=10, contract_size_unit="EUR x index", tick_size=0.5, tick_value=5.0, |
|
106 |
+ **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
107 |
+ _s("MFC", "Mini CAC 40", "Euronext", currency="EUR", contract_size=1, contract_size_unit="EUR x index", tick_size=0.5, tick_value=0.5, |
|
108 |
+ **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
109 |
+ _s("FTI", "AEX", "Euronext", currency="EUR", contract_size=200, contract_size_unit="EUR x index", tick_size=0.05, tick_value=10.0, |
|
110 |
+ **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
111 |
+ _s("MAX", "Mini AEX", "Euronext", currency="EUR", contract_size=20, contract_size_unit="EUR x index", tick_size=0.05, tick_value=1.0, |
|
112 |
+ **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
113 |
+ _s("BFX", "BEL 20", "Euronext", currency="EUR", **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
114 |
+ _s("PSI", "PSI 20", "Euronext", currency="EUR", **{**_EQX, "month_cycle": ALL_MONTHS}), |
|
115 |
+ _s("FTUK", "FTSE 100", "ICE Europe", currency="GBP", contract_size=10, contract_size_unit="GBP x index", tick_size=0.5, tick_value=5.0, |
|
116 |
+ **{**_EQX, "rth": ("03:00", "11:30")}), |
|
117 |
+ # ---- energy (NYMEX / ICE) ------------------------------------------------------------------------- |
|
118 |
+ _s("CL", "Crude Oil WTI", "NYMEX", contract_size=1000, contract_size_unit="barrels", tick_size=0.01, tick_value=10.0, |
|
119 |
+ settlement_type="physical", expiry_rule="cl_rule", first_notice_rule="cl", **_EN), |
|
120 |
+ _s("MCL", "Micro WTI Crude Oil", "NYMEX", contract_size=100, contract_size_unit="barrels", tick_size=0.01, tick_value=1.0, |
|
121 |
+ settlement_type="cash", expiry_rule="cl_minus_1", **_EN), |
|
122 |
+ _s("BZ", "Brent Last Day Financial", "NYMEX", contract_size=1000, contract_size_unit="barrels", tick_size=0.01, tick_value=10.0, |
|
123 |
+ settlement_type="cash", expiry_rule="bz_rule", **_EN), |
|
124 |
+ _s("B", "Brent Crude", "ICE Europe", contract_size=1000, contract_size_unit="barrels", tick_size=0.01, tick_value=10.0, |
|
125 |
+ settlement_type="cash", expiry_rule="bz_rule", **{**_EN, "rth": ("03:00", "14:30")}), |
|
126 |
+ _s("NG", "Henry Hub Natural Gas", "NYMEX", contract_size=10000, contract_size_unit="MMBtu", tick_size=0.001, tick_value=10.0, |
|
127 |
+ settlement_type="physical", expiry_rule="ng_rule", **_EN), |
|
128 |
+ _s("QG", "E-mini Natural Gas", "NYMEX", contract_size=2500, contract_size_unit="MMBtu", tick_size=0.005, tick_value=12.5, |
|
129 |
+ settlement_type="cash", expiry_rule="ng_minus_1", **_EN), |
|
130 |
+ _s("HH", "Natural Gas Last Day Financial", "NYMEX", contract_size=10000, contract_size_unit="MMBtu", tick_size=0.001, tick_value=10.0, |
|
131 |
+ settlement_type="cash", expiry_rule="ng_rule", **_EN), |
|
132 |
+ _s("HO", "NY Harbor ULSD", "NYMEX", contract_size=42000, contract_size_unit="gallons", tick_size=0.0001, tick_value=4.2, |
|
133 |
+ settlement_type="physical", expiry_rule="prior_month_last_business_day", **_EN), |
|
134 |
+ _s("RB", "RBOB Gasoline", "NYMEX", contract_size=42000, contract_size_unit="gallons", tick_size=0.0001, tick_value=4.2, |
|
135 |
+ settlement_type="physical", expiry_rule="prior_month_last_business_day", **_EN), |
|
136 |
+ _s("TTF", "Dutch TTF Natural Gas", "CME", currency="EUR", settlement_type="cash", **_EN), |
|
137 |
+ # ---- metals (COMEX / NYMEX) ----------------------------------------------------------------------- |
|
138 |
+ _s("GC", "Gold", "COMEX", contract_size=100, contract_size_unit="troy oz", tick_size=0.10, tick_value=10.0, month_cycle="GJMQVZ", **_MT), |
|
139 |
+ _s("SI", "Silver", "COMEX", contract_size=5000, contract_size_unit="troy oz", tick_size=0.005, tick_value=25.0, month_cycle="FHKNUZ", **_MT), |
|
140 |
+ _s("HG", "Copper", "COMEX", contract_size=25000, contract_size_unit="lbs", tick_size=0.0005, tick_value=12.5, month_cycle="HKNUZ", **_MT), |
|
141 |
+ _s("PL", "Platinum", "NYMEX", contract_size=50, contract_size_unit="troy oz", tick_size=0.10, tick_value=5.0, month_cycle="FJNV", **_MT), |
|
142 |
+ _s("PA", "Palladium", "NYMEX", contract_size=100, contract_size_unit="troy oz", tick_size=0.50, tick_value=50.0, month_cycle="HMUZ", **_MT), |
|
143 |
+ _s("MGC", "Micro Gold", "COMEX", contract_size=10, contract_size_unit="troy oz", tick_size=0.10, tick_value=1.0, month_cycle="GJMQVZ", **_MT), |
|
144 |
+ _s("SIL", "Micro Silver", "COMEX", contract_size=1000, contract_size_unit="troy oz", tick_size=0.005, tick_value=5.0, month_cycle="FHKNUZ", **_MT), |
|
145 |
+ _s("ALI", "Aluminum", "COMEX", contract_size=25, contract_size_unit="metric tons", tick_size=0.25, tick_value=6.25, month_cycle=ALL_MONTHS, **_MT), |
|
146 |
+ _s("HRC", "U.S. Midwest Domestic Hot-Rolled Coil Steel", "COMEX", contract_size=20, contract_size_unit="short tons", tick_size=1.0, tick_value=20.0, |
|
147 |
+ asset_class="metals", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_business_day"), |
|
148 |
+ # ---- rates (CBOT / CME / Eurex / ICE) ------------------------------------------------------------- |
|
149 |
+ _s("ZN", "10-Year T-Note", "CBOT", contract_size=100000, contract_size_unit="USD face value", tick_size=0.015625, tick_value=15.625, **_TR), |
|
150 |
+ _s("US", "30-Year T-Bond", "CBOT", contract_size=100000, contract_size_unit="USD face value", tick_size=0.03125, tick_value=31.25, **_TR), |
|
151 |
+ _s("UB", "Ultra T-Bond", "CBOT", contract_size=100000, contract_size_unit="USD face value", tick_size=0.03125, tick_value=31.25, **_TR), |
|
152 |
+ _s("TN", "Ultra 10-Year T-Note", "CBOT", contract_size=100000, contract_size_unit="USD face value", tick_size=0.015625, tick_value=15.625, **_TR), |
|
153 |
+ _s("ZF", "5-Year T-Note", "CBOT", contract_size=100000, contract_size_unit="USD face value", tick_size=0.0078125, tick_value=7.8125, |
|
154 |
+ **{**_TR, "expiry_rule": "last_business_day"}), |
|
155 |
+ _s("ZT", "2-Year T-Note", "CBOT", contract_size=200000, contract_size_unit="USD face value", tick_size=0.00390625, tick_value=7.8125, |
|
156 |
+ **{**_TR, "expiry_rule": "last_business_day"}), |
|
157 |
+ _s("ZQ", "30-Day Fed Funds", "CBOT", contract_size=5000000, contract_size_unit="USD notional", tick_size=0.005, tick_value=20.835, |
|
158 |
+ asset_class="rates", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_business_day", rth=("08:20", "15:00")), |
|
159 |
+ _s("SR3", "3-Month SOFR", "CME", contract_size=2500, contract_size_unit="USD x index", tick_size=0.0025, tick_value=6.25, |
|
160 |
+ asset_class="rates", settlement_type="cash", month_cycle=QUARTERLY, expiry_rule="sr3_rule", rth=("08:20", "15:00")), |
|
161 |
+ _s("SR1", "1-Month SOFR", "CME", contract_size=4167, contract_size_unit="USD x index", tick_size=0.0025, tick_value=10.4175, |
|
162 |
+ asset_class="rates", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_business_day", rth=("08:20", "15:00")), |
|
163 |
+ _s("FGBL", "Euro-Bund", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
164 |
+ _s("FGBM", "Euro-Bobl", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
165 |
+ _s("FGBS", "Euro-Schatz", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.005, tick_value=5.0, **_BUND), |
|
166 |
+ _s("FGBX", "Euro-Buxl", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.02, tick_value=20.0, **_BUND), |
|
167 |
+ _s("FOAT", "Euro-OAT", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
168 |
+ _s("FBTP", "Euro-BTP", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
169 |
+ _s("FBTS", "Short-Term Euro-BTP", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
170 |
+ _s("FBON", "Euro-Bono", "EUREX", currency="EUR", contract_size=100000, contract_size_unit="EUR face value", tick_size=0.01, tick_value=10.0, **_BUND), |
|
171 |
+ _s("FEU3", "Three-Month Euribor", "EUREX", currency="EUR", asset_class="rates", settlement_type="cash", month_cycle=QUARTERLY, calendar="eurex"), |
|
172 |
+ _s("G", "Long Gilt", "ICE Europe", currency="GBP", contract_size=100000, contract_size_unit="GBP face value", tick_size=0.01, tick_value=10.0, |
|
173 |
+ asset_class="rates", settlement_type="physical", month_cycle=QUARTERLY), |
|
174 |
+ _s("L", "3-Month Sterling", "ICE Europe", currency="GBP", asset_class="rates", settlement_type="cash", month_cycle=QUARTERLY), |
|
175 |
+ _s("ER", "3-Month Euribor", "ICE Europe", currency="EUR", asset_class="rates", settlement_type="cash", month_cycle=QUARTERLY), |
|
176 |
+ _s("SO3", "3-Month SONIA", "ICE Europe", currency="GBP", asset_class="rates", settlement_type="cash", month_cycle=QUARTERLY), |
|
177 |
+ # ---- grains / ags (CBOT, ICE) --------------------------------------------------------------------- |
|
178 |
+ _s("ZC", "Corn", "CBOT", contract_size=5000, contract_size_unit="bushels", tick_size=0.25, tick_value=12.5, month_cycle="HKNUZ", **_GR), |
|
179 |
+ _s("ZS", "Soybeans", "CBOT", contract_size=5000, contract_size_unit="bushels", tick_size=0.25, tick_value=12.5, month_cycle="FHKNQUX", **_GR), |
|
180 |
+ _s("ZW", "Wheat (SRW)", "CBOT", contract_size=5000, contract_size_unit="bushels", tick_size=0.25, tick_value=12.5, month_cycle="HKNUZ", **_GR), |
|
181 |
+ _s("KE", "KC Hard Red Winter Wheat", "CBOT", contract_size=5000, contract_size_unit="bushels", tick_size=0.25, tick_value=12.5, month_cycle="HKNUZ", **_GR), |
|
182 |
+ _s("ZM", "Soybean Meal", "CBOT", contract_size=100, contract_size_unit="short tons", tick_size=0.10, tick_value=10.0, month_cycle="FHKNQUVZ", **_GR), |
|
183 |
+ _s("ZL", "Soybean Oil", "CBOT", contract_size=60000, contract_size_unit="lbs", tick_size=0.01, tick_value=6.0, month_cycle="FHKNQUVZ", **_GR), |
|
184 |
+ _s("ZO", "Oats", "CBOT", contract_size=5000, contract_size_unit="bushels", tick_size=0.25, tick_value=12.5, month_cycle="HKNUZ", **_GR), |
|
185 |
+ _s("ZR", "Rough Rice", "CBOT", contract_size=2000, contract_size_unit="cwt", tick_size=0.005, tick_value=10.0, month_cycle="FHKNUX", **_GR), |
|
186 |
+ _s("XC", "Mini Corn", "CBOT", contract_size=1000, contract_size_unit="bushels", tick_size=0.125, tick_value=1.25, month_cycle="HKNUZ", **_GR), |
|
187 |
+ _s("RS", "Canola", "ICE US", currency="CAD", contract_size=20, contract_size_unit="metric tons", tick_size=0.10, tick_value=2.0, month_cycle="FHKNX", **_GR), |
|
188 |
+ _s("EBM", "Milling Wheat", "Euronext", currency="EUR", contract_size=50, contract_size_unit="metric tons", tick_size=0.25, tick_value=12.5, |
|
189 |
+ asset_class="ags", settlement_type="physical", month_cycle="HKUZ", calendar="eurex"), |
|
190 |
+ _s("LBS", "Random Length Lumber", "CME", contract_size=110000, contract_size_unit="board feet", tick_size=0.10, tick_value=11.0, |
|
191 |
+ asset_class="ags", settlement_type="physical", month_cycle="FHKNUX"), |
|
192 |
+ # ---- livestock / dairy (CME) ---------------------------------------------------------------------- |
|
193 |
+ _s("LE", "Live Cattle", "CME", contract_size=40000, contract_size_unit="lbs", tick_size=0.025, tick_value=10.0, |
|
194 |
+ asset_class="livestock", settlement_type="physical", month_cycle="GJMQVZ", expiry_rule="last_business_day", rth=("09:30", "14:05")), |
|
195 |
+ _s("HE", "Lean Hogs", "CME", contract_size=40000, contract_size_unit="lbs", tick_size=0.025, tick_value=10.0, |
|
196 |
+ asset_class="livestock", settlement_type="cash", month_cycle="GJKMNQVZ", expiry_rule="he_rule", rth=("09:30", "14:05")), |
|
197 |
+ _s("GF", "Feeder Cattle", "CME", contract_size=50000, contract_size_unit="lbs", tick_size=0.025, tick_value=12.5, |
|
198 |
+ asset_class="livestock", settlement_type="cash", month_cycle="FHJKQUVX", expiry_rule="gf_rule", rth=("09:30", "14:05")), |
|
199 |
+ _s("PRK", "Pork Cutout", "CME", contract_size=40000, contract_size_unit="lbs", tick_size=0.025, tick_value=10.0, |
|
200 |
+ asset_class="livestock", settlement_type="cash", month_cycle="GJKMNQVZ", expiry_rule="he_rule", rth=("09:30", "14:05")), |
|
201 |
+ _s("DC", "Class III Milk", "CME", contract_size=200000, contract_size_unit="lbs", tick_size=0.01, tick_value=20.0, |
|
202 |
+ asset_class="ags", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
203 |
+ _s("CB", "Cash-Settled Butter", "CME", contract_size=20000, contract_size_unit="lbs", asset_class="ags", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
204 |
+ _s("CSC", "Cash-Settled Cheese", "CME", contract_size=20000, contract_size_unit="lbs", asset_class="ags", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
205 |
+ # ---- softs (ICE) ---------------------------------------------------------------------------------- |
|
206 |
+ _s("KC", "Coffee C", "ICE US", contract_size=37500, contract_size_unit="lbs", tick_size=0.05, tick_value=18.75, |
|
207 |
+ asset_class="softs", settlement_type="physical", month_cycle="HKNUZ", expiry_rule="kc_rule", first_notice_rule="kc", rth=("04:15", "13:30")), |
|
208 |
+ _s("SB", "Sugar No. 11", "ICE US", contract_size=112000, contract_size_unit="lbs", tick_size=0.01, tick_value=11.2, |
|
209 |
+ asset_class="softs", settlement_type="physical", month_cycle="HKNV", expiry_rule="prior_month_last_business_day", rth=("03:30", "13:00")), |
|
210 |
+ _s("CC", "Cocoa", "ICE US", contract_size=10, contract_size_unit="metric tons", tick_size=1.0, tick_value=10.0, |
|
211 |
+ asset_class="softs", settlement_type="physical", month_cycle="HKNUZ", expiry_rule="cc_rule", rth=("04:45", "13:30")), |
|
212 |
+ _s("CT", "Cotton No. 2", "ICE US", contract_size=50000, contract_size_unit="lbs", tick_size=0.01, tick_value=5.0, |
|
213 |
+ asset_class="softs", settlement_type="physical", month_cycle="HKNVZ", expiry_rule="ct_rule", rth=("21:00", "14:20")), |
|
214 |
+ _s("OJ", "FCOJ-A", "ICE US", contract_size=15000, contract_size_unit="lbs", tick_size=0.05, tick_value=7.5, |
|
215 |
+ asset_class="softs", settlement_type="physical", month_cycle="FHKNUX", expiry_rule="oj_rule", rth=("08:00", "14:00")), |
|
216 |
+ _s("C", "London Cocoa", "ICE Europe", currency="GBP", contract_size=10, contract_size_unit="metric tons", tick_size=1.0, tick_value=10.0, |
|
217 |
+ asset_class="softs", settlement_type="physical", month_cycle="HKNUZ", expiry_rule="cc_rule", rth=("04:45", "12:30")), |
|
218 |
+ _s("RM", "Robusta Coffee", "ICE Europe", contract_size=10, contract_size_unit="metric tons", tick_size=1.0, tick_value=10.0, |
|
219 |
+ asset_class="softs", settlement_type="physical", month_cycle="FHKNUX", rth=("04:00", "12:30")), |
|
220 |
+ # ---- FX (CME, ICE) -------------------------------------------------------------------------------- |
|
221 |
+ _s("E6", "Euro FX", "CME", contract_size=125000, contract_size_unit="EUR", tick_size=0.00005, tick_value=6.25, **_FX), |
|
222 |
+ _s("J1", "Japanese Yen", "CME", contract_size=12500000, contract_size_unit="JPY", tick_size=0.0000005, tick_value=6.25, **_FX), |
|
223 |
+ _s("B6", "British Pound", "CME", contract_size=62500, contract_size_unit="GBP", tick_size=0.0001, tick_value=6.25, **_FX), |
|
224 |
+ _s("A6", "Australian Dollar", "CME", contract_size=100000, contract_size_unit="AUD", tick_size=0.00005, tick_value=5.0, **_FX), |
|
225 |
+ _s("AD", "Canadian Dollar", "CME", contract_size=100000, contract_size_unit="CAD", tick_size=0.00005, tick_value=5.0, **_FX), |
|
226 |
+ _s("E1", "Swiss Franc", "CME", contract_size=125000, contract_size_unit="CHF", tick_size=0.00005, tick_value=6.25, **_FX), |
|
227 |
+ _s("N6", "New Zealand Dollar", "CME", contract_size=100000, contract_size_unit="NZD", tick_size=0.00005, tick_value=5.0, **_FX), |
|
228 |
+ _s("MP", "Mexican Peso", "CME", contract_size=500000, contract_size_unit="MXN", tick_size=0.00001, tick_value=5.0, **{**_FX, "month_cycle": ALL_MONTHS}), |
|
229 |
+ _s("T6", "South African Rand", "CME", contract_size=500000, contract_size_unit="ZAR", tick_size=0.00001, tick_value=5.0, **{**_FX, "month_cycle": ALL_MONTHS}), |
|
230 |
+ _s("BR", "Brazilian Real", "CME", contract_size=100000, contract_size_unit="BRL", tick_size=0.00005, tick_value=5.0, |
|
231 |
+ asset_class="fx", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="prior_month_last_business_day", rth=("08:20", "15:00")), |
|
232 |
+ _s("E7", "E-mini Euro FX", "CME", contract_size=62500, contract_size_unit="EUR", tick_size=0.0001, tick_value=6.25, **_FX), |
|
233 |
+ _s("J7", "E-mini Japanese Yen", "CME", contract_size=6250000, contract_size_unit="JPY", tick_size=0.000001, tick_value=6.25, **_FX), |
|
234 |
+ _s("NOK", "Norwegian Krone", "CME", contract_size=2000000, contract_size_unit="NOK", tick_size=0.00001, tick_value=20.0, **_FX), |
|
235 |
+ _s("SEK", "Swedish Krona", "CME", contract_size=2000000, contract_size_unit="SEK", tick_size=0.00001, tick_value=20.0, **_FX), |
|
236 |
+ _s("RP", "Euro / British Pound", "CME", currency="GBP", contract_size=125000, contract_size_unit="EUR", tick_size=0.00005, tick_value=6.25, **_FX), |
|
237 |
+ _s("RY", "Euro / Japanese Yen", "CME", currency="JPY", contract_size=125000, contract_size_unit="EUR", tick_size=0.01, tick_value=1250.0, **_FX), |
|
238 |
+ _s("PJY", "British Pound / Japanese Yen", "CME", currency="JPY", contract_size=125000, contract_size_unit="GBP", tick_size=0.01, tick_value=1250.0, **_FX), |
|
239 |
+ _s("CNH", "USD / Offshore RMB", "CME", currency="CNH", contract_size=100000, contract_size_unit="USD", tick_size=0.0001, tick_value=10.0, |
|
240 |
+ asset_class="fx", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="fx_rule", rth=("08:20", "15:00")), |
|
241 |
+ _s("KRW", "Korean Won", "CME", contract_size=125000000, contract_size_unit="KRW", asset_class="fx", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
242 |
+ _s("SIR", "Indian Rupee", "CME", contract_size=5000000, contract_size_unit="INR", asset_class="fx", settlement_type="cash", month_cycle=ALL_MONTHS), |
|
243 |
+ _s("DX", "US Dollar Index", "ICE US", contract_size=1000, contract_size_unit="USD x index", tick_size=0.005, tick_value=5.0, |
|
244 |
+ asset_class="fx", settlement_type="cash", month_cycle=QUARTERLY, expiry_rule="fx_rule", rth=("08:20", "15:00")), |
|
245 |
+ # ---- volatility (Cboe) ---------------------------------------------------------------------------- |
|
246 |
+ _s("VX", "VIX Futures", "CFE", contract_size=1000, contract_size_unit="USD x index", tick_size=0.05, tick_value=50.0, |
|
247 |
+ asset_class="volatility", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="vx_rule"), |
|
248 |
+ _s("VXM", "Mini VIX Futures", "CFE", contract_size=100, contract_size_unit="USD x index", tick_size=0.05, tick_value=5.0, |
|
249 |
+ asset_class="volatility", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="vx_rule"), |
|
250 |
+ # ---- crypto (CME) --------------------------------------------------------------------------------- |
|
251 |
+ _s("BTC", "Bitcoin", "CME", contract_size=5, contract_size_unit="BTC", tick_size=5.0, tick_value=25.0, |
|
252 |
+ asset_class="crypto", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_friday", rth=("08:00", "17:00")), |
|
253 |
+ _s("MBT", "Micro Bitcoin", "CME", contract_size=0.1, contract_size_unit="BTC", tick_size=5.0, tick_value=0.5, |
|
254 |
+ asset_class="crypto", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_friday", rth=("08:00", "17:00")), |
|
255 |
+ _s("MET", "Micro Ether", "CME", contract_size=0.1, contract_size_unit="ETH", tick_size=0.5, tick_value=0.05, |
|
256 |
+ asset_class="crypto", settlement_type="cash", month_cycle=ALL_MONTHS, expiry_rule="last_friday", rth=("08:00", "17:00")), |
|
257 |
+] |
|
258 |
+ |
|
259 |
+SPEC_BY_ROOT: dict[str, RootSpec] = {s.root: s for s in SPECS} |
|
260 |
+ |
|
261 |
+# Roots seen in the lake without a reference entry (2026-09): CPO, FBTM, FID, FNMY, FOAM, JB, JG, NK, RU, |
|
262 |
+# ST, TWN, ZK — unknown products (not in meta/futures/futures.csv either). They get `derived` specs. |
|
263 |
+UNKNOWN_LAKE_ROOTS = ("CPO", "FBTM", "FID", "FNMY", "FOAM", "JB", "JG", "NK", "RU", "ST", "TWN", "ZK") |
|
264 |
+ |
|
265 |
+ |
|
266 |
+def derived_spec(root: str, name: str | None = None, exchange: str | None = None) -> RootSpec: |
|
267 |
+ """Placeholder spec for a root that exists in the lake but not in the reference table.""" |
|
268 |
+ return RootSpec(root=root, name=name, exchange=exchange, asset_class=None, expiry_rule="data", source="derived", |
|
269 |
+ aliases=ALIASES_OF_ROOT.get(root, [])) |
|
270 |
+ |
|
271 |
+ |
|
272 |
+def spec_for(root: str) -> RootSpec: |
|
273 |
+ return SPEC_BY_ROOT.get(root) or derived_spec(root) |
|
274 |
+ |
|
275 |
+ |
|
276 |
+def rth_window(root: str) -> tuple[str, str]: |
|
277 |
+ return spec_for(root).rth |