섹터 유니버스 분리와 월간 갱신 정합화

This commit is contained in:
2026-06-15 02:29:29 +09:00
parent e2820065d1
commit 82ca4ddbfd
11 changed files with 1658 additions and 43 deletions
+96
View File
@@ -174,6 +174,28 @@ def normalize_legacy_source_markers(sheet: str, records: list[dict[str, Any]]) -
source = record.get("Source")
if isinstance(source, str) and "sector_targets.json" in source:
record["Source"] = source.replace("sector_targets.json", "sector_universe")
source_url = str(record.get("Source_URL") or "").strip()
transport_mode = str(record.get("Transport_Mode") or "").strip()
if record.get("Source") in (None, "", "DEFAULT_TEMPLATE"):
if "finance.naver.com/item/main.naver?code=" in source_url:
record["Source"] = "NAVER_ETF_PAGE"
if not transport_mode:
record["Transport_Mode"] = "HTML_SERVER_RENDERED"
elif source_url:
record["Source"] = "SHEET_INPUT"
if not transport_mode:
record["Transport_Mode"] = "MANUAL_OR_TEMPLATE"
else:
record["Source"] = "SHEET_INPUT"
if not transport_mode:
record["Transport_Mode"] = "MANUAL_OR_TEMPLATE"
elif record.get("Source") == "NAVER_ETF_PAGE_FAIL_LAYOUT_CHANGED" and not transport_mode:
record["Transport_Mode"] = "LAYOUT_CHANGED"
elif record.get("Source") == "REPRESENTATIVE_STOCK_PROXY" and not transport_mode:
record["Transport_Mode"] = "HTML_SERVER_RENDERED"
sector = str(record.get("Sector") or "").strip()
if sector:
record["Sector_Check"] = sector
return records
@@ -1428,6 +1450,80 @@ def convert_xlsx_to_json(xlsx_path: Path, output_path: Path) -> None:
result["data"][sheet] = normalize_legacy_source_markers(sheet, dataframe_records(df))
result["metadata"]["sheets_included"].append(sheet)
sector_source_map: dict[str, str] = {}
sector_universe_rows = result["data"].get("sector_universe")
if isinstance(sector_universe_rows, list):
for row in sector_universe_rows:
if not isinstance(row, dict):
continue
sector = str(row.get("Sector") or "").strip()
if not sector:
continue
source = str(row.get("Source") or "").strip() or "SHEET_INPUT"
sector_source_map.setdefault(sector, source)
sector_flow_rows = result["data"].get("sector_flow")
if isinstance(sector_flow_rows, list):
split_finance_map = {
"금융/은행": [
("은행", "091170", "KODEX 은행"),
("증권", "0111J0", "HANARO 증권고배당TOP3플러스"),
("지주회사", "307520", "TIGER 지주회사"),
]
}
normalized_rows: list[dict[str, Any]] = []
for row in sector_flow_rows:
if not isinstance(row, dict):
continue
sector = str(row.get("Sector") or "").strip()
if not sector:
continue
source = str(row.get("Universe_Source") or "").strip() or sector_source_map.get(sector, "SHEET_INPUT")
row["Universe_Source"] = source
if sector in split_finance_map:
for split_sector, split_ticker, split_name in split_finance_map[sector]:
cloned = dict(row)
cloned["Sector"] = split_sector
cloned["Proxy_Ticker"] = split_ticker
cloned["Proxy_Name"] = split_name
cloned["Proxy_Type"] = "ETF"
cloned["ETF_Code"] = split_ticker
cloned["Reason"] = "PRE_SPLIT_FINANCE_FLOW_CARRYOVER"
cloned["Universe_Source"] = "NAVER_ETF_PAGE"
normalized_rows.append(cloned)
else:
normalized_rows.append(row)
result["data"]["sector_flow"] = normalized_rows
sector_flow_history_rows = result["data"].get("sector_flow_history")
if isinstance(sector_flow_history_rows, list):
split_finance_map = {
"금융/은행": [
("은행", "091170", "KODEX 은행"),
("증권", "0111J0", "HANARO 증권고배당TOP3플러스"),
("지주회사", "307520", "TIGER 지주회사"),
]
}
normalized_history: list[dict[str, Any]] = []
for row in sector_flow_history_rows:
if not isinstance(row, dict):
continue
sector = str(row.get("Sector") or "").strip()
if not sector:
continue
if sector in split_finance_map:
for split_sector, split_ticker, split_name in split_finance_map[sector]:
cloned = dict(row)
cloned["Sector"] = split_sector
cloned["Proxy_Ticker"] = split_ticker
cloned["Proxy_Name"] = split_name
cloned["Proxy_Type"] = "ETF"
cloned["Reason"] = "PRE_SPLIT_FINANCE_FLOW_CARRYOVER"
normalized_history.append(cloned)
else:
normalized_history.append(row)
result["data"]["sector_flow_history"] = normalized_history
# harness_context 시트가 없으면 메타에 경고 기록
if "_harness_context" not in result["data"]:
result["metadata"]["harness_context_missing"] = (