|
|
|
@ -6,7 +6,7 @@ import re
|
|
|
|
import uuid
|
|
|
|
import uuid
|
|
|
|
import json
|
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
import logging
|
|
|
|
from datetime import datetime
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from collections import defaultdict
|
|
|
|
from collections import defaultdict
|
|
|
|
from pathlib import Path
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
@ -194,6 +194,48 @@ def _normalize_time(time_val) -> str:
|
|
|
|
return s
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def recalculate_trade_date(trade_date: str, trade_time: str) -> str:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
根据交易时间重新计算交易日
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
期货交易规则:
|
|
|
|
|
|
|
|
- 前一交易日 21:00 之后到当前交易日 15:00 之前的交易,算作当天交易
|
|
|
|
|
|
|
|
- 周五 21:00 之后的夜盘交易,算作下周一的交易数据
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param trade_date: 原始交易日 (YYYY-MM-DD)
|
|
|
|
|
|
|
|
:param trade_time: 交易时间 (HH:MM:SS)
|
|
|
|
|
|
|
|
:return: 重新计算后的交易日
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not trade_date or not trade_time:
|
|
|
|
|
|
|
|
return trade_date
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
# 解析日期和时间
|
|
|
|
|
|
|
|
dt = datetime.strptime(trade_date, '%Y-%m-%d')
|
|
|
|
|
|
|
|
time_parts = trade_time.split(':')
|
|
|
|
|
|
|
|
hour = int(time_parts[0])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 判断是否在夜盘时段 (21:00 之后)
|
|
|
|
|
|
|
|
if hour >= 21:
|
|
|
|
|
|
|
|
# 夜盘交易,交易日归属下一天
|
|
|
|
|
|
|
|
next_day = dt + timedelta(days=1)
|
|
|
|
|
|
|
|
# 如果是周五 (weekday=4),下一天是周六,需要跳到下周一
|
|
|
|
|
|
|
|
if dt.weekday() == 4: # 周五
|
|
|
|
|
|
|
|
next_day = dt + timedelta(days=3) # 跳到下周一
|
|
|
|
|
|
|
|
# 如果是周六 (weekday=5),跳到下周一
|
|
|
|
|
|
|
|
elif dt.weekday() == 5:
|
|
|
|
|
|
|
|
next_day = dt + timedelta(days=2)
|
|
|
|
|
|
|
|
# 如果是周日 (weekday=6),跳到下周一
|
|
|
|
|
|
|
|
elif dt.weekday() == 6:
|
|
|
|
|
|
|
|
next_day = dt + timedelta(days=1)
|
|
|
|
|
|
|
|
return next_day.strftime('%Y-%m-%d')
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
# 日盘交易,保持原交易日
|
|
|
|
|
|
|
|
return trade_date
|
|
|
|
|
|
|
|
except (ValueError, IndexError):
|
|
|
|
|
|
|
|
return trade_date
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _build_dedup_key(trade_date: str, variety: str, trade_time: str, price: float) -> str:
|
|
|
|
def _build_dedup_key(trade_date: str, variety: str, trade_time: str, price: float) -> str:
|
|
|
|
"""构建去重键:交易日+品种+交易时间+价格(价格保留2位小数避免浮点精度问题)"""
|
|
|
|
"""构建去重键:交易日+品种+交易时间+价格(价格保留2位小数避免浮点精度问题)"""
|
|
|
|
return f"{trade_date}|{variety}|{trade_time}|{round(price, 2)}"
|
|
|
|
return f"{trade_date}|{variety}|{trade_time}|{round(price, 2)}"
|
|
|
|
@ -280,8 +322,10 @@ def save_to_db(
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
futures_parsed += 1
|
|
|
|
futures_parsed += 1
|
|
|
|
variety = extract_variety(contract)
|
|
|
|
variety = extract_variety(contract)
|
|
|
|
trade_date = _normalize_date(row.get('实际成交日期', ''))
|
|
|
|
raw_date = _normalize_date(row.get('实际成交日期', ''))
|
|
|
|
trade_time = _normalize_time(row.get('成交时间', ''))
|
|
|
|
trade_time = _normalize_time(row.get('成交时间', ''))
|
|
|
|
|
|
|
|
# 根据交易时间重新计算交易日(夜盘归属下一天)
|
|
|
|
|
|
|
|
trade_date = recalculate_trade_date(raw_date, trade_time)
|
|
|
|
bs_flag = str(row.get('买/卖', '')).strip()
|
|
|
|
bs_flag = str(row.get('买/卖', '')).strip()
|
|
|
|
oc_flag = str(row.get('开/平', '')).strip()
|
|
|
|
oc_flag = str(row.get('开/平', '')).strip()
|
|
|
|
price = safe_float(row.get('成交价'))
|
|
|
|
price = safe_float(row.get('成交价'))
|
|
|
|
@ -300,7 +344,7 @@ def save_to_db(
|
|
|
|
|
|
|
|
|
|
|
|
# 记录前几条的去重键用于调试
|
|
|
|
# 记录前几条的去重键用于调试
|
|
|
|
if futures_parsed <= 3:
|
|
|
|
if futures_parsed <= 3:
|
|
|
|
logger.info(f"[去重校验] 期货记录 #{futures_parsed}: date={trade_date!r}, variety={variety!r}, time={trade_time!r}, price={price!r} => key={dedup_key!r}")
|
|
|
|
logger.info(f"[去重校验] 期货记录 #{futures_parsed}: raw_date={raw_date!r}, trade_date={trade_date!r}, variety={variety!r}, time={trade_time!r}, price={price!r} => key={dedup_key!r}")
|
|
|
|
|
|
|
|
|
|
|
|
new_keys_in_batch.add(dedup_key)
|
|
|
|
new_keys_in_batch.add(dedup_key)
|
|
|
|
rec = TradeRecord(
|
|
|
|
rec = TradeRecord(
|
|
|
|
@ -331,8 +375,10 @@ def save_to_db(
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
options_parsed += 1
|
|
|
|
options_parsed += 1
|
|
|
|
variety = extract_variety(contract)
|
|
|
|
variety = extract_variety(contract)
|
|
|
|
trade_date = _normalize_date(row.get('成交日期', ''))
|
|
|
|
raw_date = _normalize_date(row.get('成交日期', ''))
|
|
|
|
trade_time = _normalize_time(row.get('成交时间', ''))
|
|
|
|
trade_time = _normalize_time(row.get('成交时间', ''))
|
|
|
|
|
|
|
|
# 根据交易时间重新计算交易日(夜盘归属下一天)
|
|
|
|
|
|
|
|
trade_date = recalculate_trade_date(raw_date, trade_time)
|
|
|
|
bs_flag = str(row.get('买/卖', '')).strip()
|
|
|
|
bs_flag = str(row.get('买/卖', '')).strip()
|
|
|
|
price = safe_float(row.get('权利金单价'))
|
|
|
|
price = safe_float(row.get('权利金单价'))
|
|
|
|
|
|
|
|
|
|
|
|
|