Route business quotes and K-lines to CTP; keep Sina only for market chart page.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -165,7 +165,7 @@ def fetch_closed_bar(
|
||||
p,
|
||||
db_path=db_path,
|
||||
trading_mode=trading_mode,
|
||||
prefer_ctp=False,
|
||||
prefer_ctp=True,
|
||||
)
|
||||
bars = data.get("bars") or []
|
||||
return last_closed_bar(bars, bar_period_minutes(p))
|
||||
|
||||
@@ -303,8 +303,7 @@ def fetch_market_klines(
|
||||
except Exception as exc:
|
||||
logger.debug("ctp kline fetch failed %s %s: %s", symbol, p, exc)
|
||||
|
||||
need_sina = force_remote or not prefer_ctp or not ctp_bars or len(ctp_bars) < MIN_CTP_KLINE_BARS
|
||||
|
||||
need_sina = not prefer_ctp or force_remote
|
||||
if ctp_bars and len(ctp_bars) >= MIN_CTP_KLINE_BARS:
|
||||
bars = ctp_bars
|
||||
source = "ctp"
|
||||
@@ -321,7 +320,7 @@ def fetch_market_klines(
|
||||
except Exception as exc:
|
||||
logger.warning("kline cache read failed %s %s: %s", chart_sym, p, exc)
|
||||
|
||||
if not bars or len(ctp_bars) < MIN_CTP_KLINE_BARS or not prefer_ctp:
|
||||
if need_sina and (not bars or len(ctp_bars) < MIN_CTP_KLINE_BARS or not prefer_ctp):
|
||||
remote_bars = fetch_sina_klines(symbol, p)
|
||||
if remote_bars:
|
||||
if prefer_ctp and ctp_bars and ctp_connected:
|
||||
@@ -498,7 +497,7 @@ def generate_review_kline_chart(
|
||||
plotted = False
|
||||
for idx, period in enumerate(valid_periods):
|
||||
ax = axes[idx, 0]
|
||||
bars = fetch_sina_klines(symbol, period)
|
||||
bars = fetch_market_klines(symbol, period, prefer_ctp=True).get("bars") or []
|
||||
bars = _select_bars(bars, cutoff, count)
|
||||
if not bars:
|
||||
ax.set_facecolor("#12121a")
|
||||
|
||||
@@ -43,15 +43,8 @@ def _has_ths_token() -> bool:
|
||||
def get_quote_source_label(*, ctp_connected: bool = False) -> str:
|
||||
"""界面展示用行情源说明。"""
|
||||
if ctp_connected:
|
||||
return "CTP 柜台(已连接)"
|
||||
source = _quote_source()
|
||||
if source == "sina":
|
||||
return "新浪(CTP 未连接时备用)"
|
||||
if source == "ths":
|
||||
return "同花顺 iFinD" if _has_ths_token() else "同花顺(未配置 token)"
|
||||
if _has_ths_token():
|
||||
return "同花顺优先,失败回退新浪"
|
||||
return "新浪(CTP 未连接时备用)"
|
||||
return "CTP 柜台"
|
||||
return "CTP 未连接"
|
||||
|
||||
|
||||
def _sina_headers() -> dict:
|
||||
|
||||
@@ -182,7 +182,7 @@ def register(deps) -> None:
|
||||
yield sse_format(
|
||||
"quote",
|
||||
build_market_quote_payload(
|
||||
symbol, market_code, sina_code, prefer_sina=True,
|
||||
symbol, market_code, sina_code, prefer_sina=False,
|
||||
),
|
||||
)
|
||||
while True:
|
||||
@@ -214,7 +214,7 @@ def register(deps) -> None:
|
||||
if not symbol and not market_code:
|
||||
return jsonify({"error": "请提供合约"}), 400
|
||||
return jsonify(build_market_quote_payload(
|
||||
symbol, market_code, sina_code, prefer_sina=True,
|
||||
symbol, market_code, sina_code, prefer_sina=False,
|
||||
))
|
||||
|
||||
|
||||
|
||||
@@ -9,16 +9,13 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Callable, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from modules.market.kline_chart import fetch_sina_klines, ths_to_sina_chart_symbol
|
||||
from modules.market.kline_chart import fetch_market_klines
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DAILY_LOOKBACK = 7
|
||||
OVERLAP_WINDOW = 3
|
||||
OVERLAP_RANGE_THRESHOLD = 0.70
|
||||
KLINE_FETCH_TIMEOUT = 5
|
||||
|
||||
TREND_LONG = "long"
|
||||
TREND_SHORT = "short"
|
||||
@@ -178,48 +175,13 @@ def analyze_daily_trend(bars: list, *, overlap_threshold: float = OVERLAP_RANGE_
|
||||
}
|
||||
|
||||
|
||||
def _normalize_daily_bars(raw: list) -> list:
|
||||
out = []
|
||||
for row in raw:
|
||||
if isinstance(row, list) and len(row) >= 5:
|
||||
out.append({
|
||||
"d": str(row[0]),
|
||||
"o": float(row[1]),
|
||||
"h": float(row[2]),
|
||||
"l": float(row[3]),
|
||||
"c": float(row[4]),
|
||||
"v": float(row[5]) if len(row) > 5 and row[5] else 0.0,
|
||||
})
|
||||
elif isinstance(row, dict) and row.get("d"):
|
||||
out.append({
|
||||
"d": str(row["d"]),
|
||||
"o": float(row.get("o", 0) or 0),
|
||||
"h": float(row.get("h", 0) or 0),
|
||||
"l": float(row.get("l", 0) or 0),
|
||||
"c": float(row.get("c", 0) or 0),
|
||||
"v": float(row.get("v", 0) or 0),
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def _fetch_sina_daily_quick(chart_sym: str) -> list:
|
||||
url = (
|
||||
"https://stock2.finance.sina.com.cn/futures/api/json.php/"
|
||||
f"IndexService.getInnerFuturesDailyKLine?symbol={chart_sym}"
|
||||
)
|
||||
def _fetch_ctp_daily_bars(sym: str) -> list:
|
||||
try:
|
||||
resp = requests.get(
|
||||
url, timeout=KLINE_FETCH_TIMEOUT,
|
||||
headers={"Referer": "https://finance.sina.com.cn"},
|
||||
)
|
||||
raw = resp.json()
|
||||
if raw and isinstance(raw, list):
|
||||
bars = _normalize_daily_bars(raw)
|
||||
if bars:
|
||||
return bars
|
||||
data = fetch_market_klines(sym, "d", prefer_ctp=True)
|
||||
return data.get("bars") or []
|
||||
except Exception as exc:
|
||||
logger.debug("quick daily kline failed %s: %s", chart_sym, exc)
|
||||
return []
|
||||
logger.debug("ctp daily kline failed %s: %s", sym, exc)
|
||||
return []
|
||||
|
||||
|
||||
def fetch_week_daily_bars(
|
||||
@@ -238,16 +200,7 @@ def fetch_week_daily_bars(
|
||||
return []
|
||||
return bars[-DAILY_LOOKBACK:] if bars else []
|
||||
|
||||
chart_sym = ths_to_sina_chart_symbol(sym)
|
||||
if not chart_sym:
|
||||
return []
|
||||
bars = _fetch_sina_daily_quick(chart_sym)
|
||||
if not bars:
|
||||
try:
|
||||
bars = fetch_sina_klines(sym, "d") or []
|
||||
except Exception as exc:
|
||||
logger.debug("fetch week daily fallback failed %s: %s", sym, exc)
|
||||
return []
|
||||
bars = _fetch_ctp_daily_bars(sym)
|
||||
return bars[-DAILY_LOOKBACK:] if bars else []
|
||||
|
||||
|
||||
|
||||
@@ -544,9 +544,9 @@
|
||||
src = ' · ' + klineSourceLabel(lastData.source);
|
||||
}
|
||||
if (isTradingSession()) {
|
||||
el.textContent = '新浪数据 · 交易中 SSE 推送' + src;
|
||||
el.textContent = 'K线新浪 · 报价CTP · 交易中 SSE 推送' + src;
|
||||
} else {
|
||||
el.textContent = '新浪数据 · 非交易时段低频刷新' + src;
|
||||
el.textContent = 'K线新浪 · 报价CTP · 非交易时段低频刷新' + src;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,7 +652,7 @@
|
||||
if (data.count) parts.push('共 ' + data.count + ' 根 · ' + periodLabel(data.period));
|
||||
if (data.source) parts.push('K线 ' + klineSourceLabel(data.source));
|
||||
if (data.quote_source) {
|
||||
parts.push('报价 新浪');
|
||||
parts.push(data.quote_source === 'ctp' ? '报价 CTP' : '报价 新浪');
|
||||
}
|
||||
meta.textContent = parts.join(' · ');
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<div class="market-chart-empty" id="market-chart-empty">请选择合约并点击「查看」</div>
|
||||
<div class="market-chart-loading" id="market-chart-loading">连接中…</div>
|
||||
</div>
|
||||
<p class="hint">图表引擎:TradingView Lightweight Charts(红跌绿涨)。K 线与报价均使用<strong>新浪</strong>数据。滚轮缩放、拖拽平移;关闭「自动」后拖动查看历史时,推送更新不会重置画面。</p>
|
||||
<p class="hint">图表引擎:TradingView Lightweight Charts(红跌绿涨)。<strong>K 线</strong>使用新浪数据,<strong>报价</strong>使用 CTP 柜台。滚轮缩放、拖拽平移;关闭「自动」后拖动查看历史时,推送更新不会重置画面。</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -397,7 +397,7 @@
|
||||
<div class="card-inner">
|
||||
<p class="hint" style="font-size:.88rem;line-height:1.6;margin:0">
|
||||
当前行情源:<strong class="text-accent">{{ quote_label }}</strong><br>
|
||||
CTP 已连接时使用<strong>柜台行情</strong>;未连接时回退新浪接口。<br>
|
||||
现价、浮盈、关键位等业务数据均使用<strong>CTP 柜台行情</strong>(需已连接);仅行情页 K 线图表使用新浪接口。<br>
|
||||
合约代码按同花顺格式(如 ag2608、IF2606)。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user