Use Beijing time for next-open countdown and day open labels.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+108
-17
@@ -118,15 +118,18 @@ def suggest_lot_by_balance(balance: float) -> float:
|
||||
return LOT_MID
|
||||
|
||||
|
||||
def _as_bjt(now: Optional[datetime] = None) -> datetime:
|
||||
dt = now or datetime.now(BJT)
|
||||
if dt.tzinfo is None:
|
||||
return dt.replace(tzinfo=BJT)
|
||||
return dt.astimezone(BJT)
|
||||
|
||||
|
||||
def current_session_label(now: Optional[datetime] = None, market_open: bool = True) -> str:
|
||||
"""北京时间盘段:亚盘/欧盘/美盘(可重叠显示);休市单独标注。"""
|
||||
if not market_open:
|
||||
return "休市"
|
||||
dt = now or datetime.now(BJT)
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=BJT)
|
||||
else:
|
||||
dt = dt.astimezone(BJT)
|
||||
dt = _as_bjt(now)
|
||||
h = dt.hour + dt.minute / 60.0
|
||||
asia = 8.0 <= h < 16.0
|
||||
euro = 15.0 <= h < 24.0
|
||||
@@ -143,10 +146,75 @@ def current_session_label(now: Optional[datetime] = None, market_open: bool = Tr
|
||||
return "+".join(parts)
|
||||
|
||||
|
||||
def format_open_elapsed(open_ts: float, market_open: bool) -> str:
|
||||
"""开盘后已过多久;休市时显示休市(仍可看下方 OHLC)。"""
|
||||
# 黄金常见时段(一律按北京时间 UTC+8):周一 07:00 开 → 周六 05:00 收;日内约 05:00–07:00
|
||||
GOLD_OPEN_HOUR = 7
|
||||
GOLD_OPEN_MINUTE = 0
|
||||
GOLD_CLOSE_HOUR = 5
|
||||
GOLD_CLOSE_MINUTE = 0
|
||||
|
||||
|
||||
def fmt_bjt(dt: datetime, fmt: str = "%m-%d %H:%M") -> str:
|
||||
"""格式化为北京时间字符串(不依赖系统时区)。"""
|
||||
return _as_bjt(dt).strftime(fmt)
|
||||
|
||||
|
||||
def next_market_open(now: Optional[datetime] = None) -> datetime:
|
||||
"""估算下一次开盘时刻,返回带 BJT 时区的 datetime。"""
|
||||
dt = _as_bjt(now)
|
||||
open_hm = (GOLD_OPEN_HOUR, GOLD_OPEN_MINUTE, 0)
|
||||
close_hm = (GOLD_CLOSE_HOUR, GOLD_CLOSE_MINUTE, 0)
|
||||
t = (dt.hour, dt.minute, dt.second)
|
||||
wd = dt.weekday() # Mon=0 … Sun=6
|
||||
|
||||
# 周末休市:周六 05:00(北京)→ 下周一 07:00(北京)
|
||||
if wd == 5 and t >= close_hm:
|
||||
days = 2
|
||||
elif wd == 6:
|
||||
days = 1
|
||||
elif wd == 0 and t < open_hm:
|
||||
days = 0
|
||||
# 工作日日内休市窗口 05:00–07:00(北京)
|
||||
elif wd <= 4 and close_hm <= t < open_hm:
|
||||
days = 0
|
||||
else:
|
||||
# 非预期休市(节假日等):推到下一个可交易日的北京时间 07:00
|
||||
days = 1
|
||||
while True:
|
||||
cand_date = (dt + timedelta(days=days)).date()
|
||||
cwd = datetime(cand_date.year, cand_date.month, cand_date.day, tzinfo=BJT).weekday()
|
||||
if cwd <= 4:
|
||||
break
|
||||
days += 1
|
||||
if days > 10:
|
||||
break
|
||||
|
||||
target = (dt + timedelta(days=days)).date()
|
||||
return datetime(
|
||||
target.year, target.month, target.day,
|
||||
GOLD_OPEN_HOUR, GOLD_OPEN_MINUTE, 0, tzinfo=BJT,
|
||||
)
|
||||
|
||||
|
||||
def format_countdown(seconds: int) -> str:
|
||||
seconds = max(0, int(seconds))
|
||||
days, rem = divmod(seconds, 86400)
|
||||
hours, rem = divmod(rem, 3600)
|
||||
mins, secs = divmod(rem, 60)
|
||||
if days > 0:
|
||||
return f"距开盘 {days}天{hours}小时{mins}分"
|
||||
if hours > 0:
|
||||
return f"距开盘 {hours}小时{mins}分"
|
||||
if mins > 0:
|
||||
return f"距开盘 {mins}分{secs}秒"
|
||||
return f"距开盘 {secs}秒"
|
||||
|
||||
|
||||
def format_open_elapsed(open_ts: float, market_open: bool, now: Optional[datetime] = None) -> str:
|
||||
"""开盘后已过多久;休市时显示距下次开盘倒计时。"""
|
||||
if not market_open:
|
||||
return "休市"
|
||||
nxt = next_market_open(now)
|
||||
left = max(0, int((nxt - _as_bjt(now)).total_seconds()))
|
||||
return format_countdown(left)
|
||||
elapsed = max(0, int(time.time() - open_ts))
|
||||
days, rem = divmod(elapsed, 86400)
|
||||
hours, rem = divmod(rem, 3600)
|
||||
@@ -237,16 +305,20 @@ class Mt5Bridge:
|
||||
ask = float(tick.ask)
|
||||
high = max(high, bid, ask)
|
||||
low = min(low, bid, ask)
|
||||
bar_day = datetime.fromtimestamp(open_ts).strftime("%m-%d")
|
||||
open_dt = datetime.fromtimestamp(open_ts, BJT)
|
||||
bar_day = open_dt.strftime("%m-%d")
|
||||
nxt = None if market_open else next_market_open()
|
||||
return {
|
||||
"open": open_px,
|
||||
"high": high,
|
||||
"low": low,
|
||||
"open_time": datetime.fromtimestamp(open_ts),
|
||||
"open_time": open_dt,
|
||||
"open_ts": open_ts,
|
||||
"bar_day": bar_day,
|
||||
"market_open": market_open,
|
||||
"elapsed_text": format_open_elapsed(float(open_ts), market_open),
|
||||
"next_open": nxt,
|
||||
"next_open_text": fmt_bjt(nxt) if nxt else "",
|
||||
}
|
||||
|
||||
def atr(self, symbol: str, period: int = ATR_PERIOD) -> float:
|
||||
@@ -1460,8 +1532,12 @@ class OrderApp(tk.Tk):
|
||||
self.lbl_account.configure(text="余额 --")
|
||||
|
||||
sess = current_session_label(market_open=market_open)
|
||||
if not market_open:
|
||||
sess_txt = f"休市 · {format_open_elapsed(0, False)}"
|
||||
else:
|
||||
sess_txt = f"时段 {sess}"
|
||||
self.lbl_session.configure(
|
||||
text=f"时段 {sess}",
|
||||
text=sess_txt,
|
||||
bg="#3a2820" if not market_open else "#243044",
|
||||
fg=COLOR_WARN if not market_open else COLOR_ACCENT,
|
||||
)
|
||||
@@ -1493,11 +1569,18 @@ class OrderApp(tk.Tk):
|
||||
f"{amp:.{digits}f} ({amp_pct:.2f}%)",
|
||||
COLOR_ACCENT,
|
||||
)
|
||||
ot = day["open_time"].strftime("%m-%d %H:%M")
|
||||
tag = "交易中" if day["market_open"] else "休市 · 显示最近交易日"
|
||||
self.lbl_day_ohlc.configure(text=f"{tag} · 日线开盘 {ot}")
|
||||
ot = fmt_bjt(day["open_time"])
|
||||
if day["market_open"]:
|
||||
tag = "交易中"
|
||||
else:
|
||||
nxt_txt = day.get("next_open_text") or ""
|
||||
tag = f"休市 · {day['elapsed_text']}"
|
||||
if nxt_txt:
|
||||
tag += f"(预计开盘 {nxt_txt} 北京时间)"
|
||||
self.lbl_day_ohlc.configure(text=f"{tag} · 日线开盘 {ot} 北京时间")
|
||||
except Exception:
|
||||
self._set_metric("elapsed", "休市" if not market_open else "--", COLOR_WARN)
|
||||
left = format_open_elapsed(0, False) if not market_open else "--"
|
||||
self._set_metric("elapsed", left, COLOR_WARN)
|
||||
self._set_metric("open", "--")
|
||||
self._set_metric("high", "--")
|
||||
self._set_metric("low", "--")
|
||||
@@ -1531,8 +1614,16 @@ class OrderApp(tk.Tk):
|
||||
f"{amp:.{digits}f} ({amp_pct:.2f}%)",
|
||||
COLOR_ACCENT,
|
||||
)
|
||||
self.lbl_session.configure(text="时段 休市", bg="#3a2820", fg=COLOR_WARN)
|
||||
self.lbl_day_ohlc.configure(text="休市 · 显示最近交易日日线")
|
||||
self.lbl_session.configure(
|
||||
text=f"休市 · {day['elapsed_text']}",
|
||||
bg="#3a2820",
|
||||
fg=COLOR_WARN,
|
||||
)
|
||||
nxt = day.get("next_open_text") or ""
|
||||
tip = f"休市 · {day['elapsed_text']}"
|
||||
if nxt:
|
||||
tip += f"(预计开盘 {nxt} 北京时间)"
|
||||
self.lbl_day_ohlc.configure(text=f"{tip} · 显示最近交易日日线")
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user