spb/hfmarketdata
Public
Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)
JavaScript 53.7%
Python 38.3%
CSS 4.6%
TypeScript 3.1%
1"""Unit tests — contract symbol parsing and root aliases."""2from __future__ import annotations34import pytest5from core.errors import ApiError6from futures.symbols import (7 ALIASES_OF_ROOT,8 ROOT_ALIASES,9 canonical_symbol,10 expand_year,11 normalize_root,12 parse_symbol,13 symbol_from_file_stem,14)151617@pytest.mark.parametrize("raw, root, mc, year", [18 ("ESZ25", "ES", "Z", 2025),19 ("ESZ2025", "ES", "Z", 2025),20 ("ES_Z25", "ES", "Z", 2025),21 ("ES-Z25", "ES", "Z", 2025),22 ("esz25", "ES", "Z", 2025),23 (" esz2025 ", "ES", "Z", 2025),24 ("CLF26", "CL", "F", 2026),25 ("M2KH25", "M2K", "H", 2025),26 ("FDAXZ2024", "FDAX", "Z", 2024),27 ("SR3Z24", "SR3", "Z", 2024),28 ("ZKZ25", "ZK", "Z", 2025), # root ending with a month letter29 ("HHZ25", "HH", "Z", 2025),30 ("CZ25", "C", "Z", 2025), # 1-char root (London cocoa)31 ("USZ24", "US", "Z", 2024),32 ("ESZ99", "ES", "Z", 1999),33 ("ESZ79", "ES", "Z", 2079),34 ("ESZ80", "ES", "Z", 1980),35])36def test_parse_symbol(raw, root, mc, year):37 cs = parse_symbol(raw)38 assert (cs.root, cs.month_code, cs.year) == (root, mc, year)39 assert cs.short == f"{root}{mc}{year % 100:02d}"40 assert cs.long == f"{root}{mc}{year}"41 assert cs.file_stem == f"{root}_{mc}{year % 100:02d}"424344@pytest.mark.parametrize("raw, root", [45 ("6EZ25", "E6"), ("6JZ25", "J1"), ("6BZ25", "B6"), ("6AZ25", "A6"), ("6CZ25", "AD"), ("6SZ25", "E1"),46 ("6NZ25", "N6"), ("6MZ25", "MP"), ("6LZ25", "BR"), ("6ZZ25", "T6"), ("ZBZ25", "US"), ("E6Z25", "E6"),47])48def test_aliases_resolve_to_lake_roots(raw, root):49 assert parse_symbol(raw).root == root50 assert canonical_symbol(raw) == f"{root}Z25"515253def test_alias_tables_are_consistent():54 for alias, root in ROOT_ALIASES.items():55 assert alias in ALIASES_OF_ROOT[root]56 assert normalize_root(alias) == root57 assert normalize_root(alias.lower()) == root58 assert normalize_root("es") == "ES"59 assert "6E" in ALIASES_OF_ROOT["E6"] and "ZB" in ALIASES_OF_ROOT["US"]606162@pytest.mark.parametrize("bad", ["", "ES", "ESA25", "ESZ5", "ESZ2025X", "TOOLONGZ25", "ES Z 25", "Z25", "ES25", "ESZ125",63 "ES_Z_25", "ÉSZ25", "BOGUS", "ESZ1800"])64def test_invalid_symbols_raise_400(bad):65 with pytest.raises(ApiError) as e:66 parse_symbol(bad)67 assert e.value.status == 400 and e.value.code == "INVALID_CONTRACT_SYMBOL"68 assert e.value.payload()["error"]["docs"].endswith("#invalid_contract_symbol")697071def test_expand_year():72 assert expand_year(0) == 2000 and expand_year(79) == 2079 and expand_year(80) == 1980 and expand_year(99) == 199973 assert expand_year(2031) == 2031747576def test_symbol_from_file_stem():77 cs = symbol_from_file_stem("ES_Z24_1day")78 assert cs is not None and cs.short == "ESZ24" and cs.year == 202479 assert symbol_from_file_stem("ES_Z24").short == "ESZ24"80 assert symbol_from_file_stem("ES_1day") is None81 assert symbol_from_file_stem("AAPL") is None82 assert symbol_from_file_stem("ES_ZZ4_1day") is None83