Source code for pyqqq.utils.futures_code

"""지수선물 근월물(최근월물) 단축코드 생성 유틸리티"""

import datetime as dtm

# 상품별 단축코드 구성 요소. xy는 프리픽스의 뒤 2자리 (구코드 1XY / 신코드 AXY 공통),
# quarterly는 분기월물(3/6/9/12월)만 상장되는지 여부
PRODUCTS = {
    "코스피200": {"xy": "01", "quarterly": True},
    "미니코스피200": {"xy": "05", "quarterly": False},
    "코스닥150": {"xy": "06", "quarterly": True},
}

# 구코드 연도문자. 코드 체계는 조회 날짜가 아니라 "만기 연도"로 결정된다:
# 만기 2025년 이하 월물 = 구코드만, 2026년 이상 월물 = 신코드만 존재
OLD_YEAR_CHARS = {2024: "V", 2025: "W"}


def second_thursday(year: int, month: int) -> dtm.date:
    """만기일: 결제월의 두 번째 목요일"""
    first = dtm.date(year, month, 1)
    return first + dtm.timedelta(days=(3 - first.weekday()) % 7 + 7)


def front_month(date: dtm.date, quarterly: bool) -> tuple:
    """조회 일자의 최근월물 (year, month). 만기일 당일까지는 해당 월물을 유지한다."""
    y, m = date.year, date.month
    while True:
        if (not quarterly or m in (3, 6, 9, 12)) and date <= second_thursday(y, m):
            return y, m
        m += 1
        if m > 12:
            m, y = 1, y + 1


[docs] def get_front_month_futures_code(product: str, date: dtm.date) -> str: """ 지수선물 상품의 특정 일자 기준 근월물(최근월물) 단축코드를 생성합니다. 만기일(결제월 두 번째 목요일) 당일까지는 해당 월물 코드를 유지하고, 다음 날부터 다음 월물로 넘어갑니다. 코드 체계는 월물의 만기 연도로 결정됩니다. (만기 2025년 이하 = 구코드 1XY..., 2026년 이상 = 신코드 AXY...) Args: product (str): 상품 이름. 코스피200, 미니코스피200, 코스닥150 중 하나 date (datetime.date): 기준 일자 Returns: str: 근월물 단축코드 (예: "A01609", "101W09") Raises: ValueError: 지원하지 않는 상품 이름인 경우 Examples: >>> get_front_month_futures_code("코스피200", datetime.date(2026, 8, 5)) 'A01609' >>> get_front_month_futures_code("미니코스피200", datetime.date(2026, 8, 5)) 'A05608' >>> get_front_month_futures_code("코스피200", datetime.date(2025, 7, 21)) '101W09' """ assert type(date) is dtm.date, "date must be a datetime.date object" if product not in PRODUCTS: raise ValueError(f"지원하지 않는 상품입니다: {product} (코스피200, 미니코스피200, 코스닥150 중 하나여야 합니다)") entry = PRODUCTS[product] year, month = front_month(date, entry["quarterly"]) if year in OLD_YEAR_CHARS: return f"1{entry['xy']}{OLD_YEAR_CHARS[year]}{month:02d}" return f"A{entry['xy']}{year % 10}{month:02d}"