部署改回/opt;接入同花顺iFinD HTTP行情,新浪作回退
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,7 +14,8 @@ from flask import (
|
||||
)
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
from symbols import search_symbols, get_price, ths_to_sina_code
|
||||
from symbols import search_symbols, ths_to_codes
|
||||
from market import get_price as market_get_price, set_ths_refresh_token
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -83,8 +84,9 @@ def init_db():
|
||||
"ALTER TABLE key_monitors ADD COLUMN lower_triggered INTEGER DEFAULT 0",
|
||||
"ALTER TABLE trade_records ADD COLUMN symbol_name TEXT",
|
||||
"ALTER TABLE order_plans ADD COLUMN sina_code TEXT",
|
||||
"ALTER TABLE key_monitors ADD COLUMN sina_code TEXT",
|
||||
"ALTER TABLE trade_records ADD COLUMN sina_code TEXT",
|
||||
"ALTER TABLE order_plans ADD COLUMN market_code TEXT",
|
||||
"ALTER TABLE key_monitors ADD COLUMN market_code TEXT",
|
||||
"ALTER TABLE trade_records ADD COLUMN market_code TEXT",
|
||||
]
|
||||
for sql in migrations:
|
||||
try:
|
||||
@@ -103,9 +105,19 @@ def init_db():
|
||||
if not get_setting("wechat_webhook") and os.getenv("WECHAT_WEBHOOK"):
|
||||
set_setting("wechat_webhook", os.getenv("WECHAT_WEBHOOK"))
|
||||
|
||||
if not get_setting("ths_refresh_token") and os.getenv("THS_REFRESH_TOKEN"):
|
||||
set_setting("ths_refresh_token", os.getenv("THS_REFRESH_TOKEN"))
|
||||
|
||||
|
||||
init_db()
|
||||
|
||||
|
||||
def sync_ths_token():
|
||||
set_ths_refresh_token(get_setting("ths_refresh_token"))
|
||||
|
||||
|
||||
sync_ths_token()
|
||||
|
||||
# —————————————— 推送 ——————————————
|
||||
|
||||
def send_wechat_msg(content: str):
|
||||
@@ -121,20 +133,25 @@ def send_wechat_msg(content: str):
|
||||
|
||||
# —————————————— 行情 ——————————————
|
||||
|
||||
def resolve_sina_code(ths_code: str, sina_code: str = "") -> Optional[str]:
|
||||
"""同花顺代码 -> 新浪行情代码;兼容旧数据中的新浪格式。"""
|
||||
if sina_code:
|
||||
return sina_code
|
||||
def resolve_market_codes(ths_code: str, market_code: str = "", sina_code: str = "") -> tuple[str, str]:
|
||||
"""返回 (market_code, sina_code) 用于行情拉取。"""
|
||||
if market_code:
|
||||
return market_code, sina_code
|
||||
if sina_code and "." in sina_code:
|
||||
return sina_code, ""
|
||||
codes = ths_to_codes(ths_code)
|
||||
if codes:
|
||||
return codes["market_code"], codes["sina_code"]
|
||||
if ths_code.startswith("nf_") or ths_code.startswith("CFF_RE_"):
|
||||
return ths_code
|
||||
return ths_to_sina_code(ths_code)
|
||||
return ths_code, ths_code
|
||||
return "", sina_code or ""
|
||||
|
||||
|
||||
def fetch_price(ths_code: str, sina_code: str = "") -> Optional[float]:
|
||||
code = resolve_sina_code(ths_code, sina_code)
|
||||
if not code:
|
||||
def fetch_price(ths_code: str, market_code: str = "", sina_code: str = "") -> Optional[float]:
|
||||
mc, sc = resolve_market_codes(ths_code, market_code, sina_code)
|
||||
if not mc and not sc:
|
||||
return None
|
||||
return get_price(code)
|
||||
return market_get_price(mc, sc)
|
||||
|
||||
# —————————————— 监控逻辑 ——————————————
|
||||
|
||||
@@ -147,7 +164,8 @@ def check_order_plans():
|
||||
for r in rows:
|
||||
sym = r["symbol"]
|
||||
sina = r["sina_code"] if "sina_code" in r.keys() else ""
|
||||
p = fetch_price(sym, sina)
|
||||
market = r["market_code"] if "market_code" in r.keys() else ""
|
||||
p = fetch_price(sym, market, sina)
|
||||
if not p:
|
||||
continue
|
||||
|
||||
@@ -229,8 +247,9 @@ def check_key_monitors():
|
||||
name = r["symbol_name"] or sym
|
||||
pid = r["id"]
|
||||
sina = r["sina_code"] if "sina_code" in r.keys() else ""
|
||||
market = r["market_code"] if "market_code" in r.keys() else ""
|
||||
|
||||
p = fetch_price(sym, sina)
|
||||
p = fetch_price(sym, market, sina)
|
||||
if not p:
|
||||
continue
|
||||
|
||||
@@ -337,20 +356,22 @@ def add_plan():
|
||||
direction = d.get("direction")
|
||||
symbol = d.get("symbol", "").strip()
|
||||
symbol_name = d.get("symbol_name", "").strip()
|
||||
market_code = d.get("market_code", "").strip()
|
||||
sina_code = d.get("sina_code", "").strip()
|
||||
if not direction:
|
||||
flash("请选择多空方向")
|
||||
return redirect(url_for("plans"))
|
||||
if not symbol or not sina_code:
|
||||
if not symbol or not market_code:
|
||||
flash("请从下拉列表选择品种(同花顺合约代码)")
|
||||
return redirect(url_for("plans"))
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"""INSERT INTO order_plans
|
||||
(symbol, symbol_name, sina_code, direction, zone_upper, zone_lower, stop_loss, take_profit)
|
||||
(symbol, symbol_name, market_code, sina_code, direction,
|
||||
zone_upper, zone_lower, stop_loss, take_profit)
|
||||
VALUES (?,?,?,?,?,?,?,?)""",
|
||||
(
|
||||
symbol, symbol_name, sina_code, direction,
|
||||
symbol, symbol_name, market_code, sina_code, direction,
|
||||
float(d["zone_upper"]), float(d["zone_lower"]),
|
||||
float(d["stop_loss"]), float(d["take_profit"]),
|
||||
),
|
||||
@@ -388,19 +409,20 @@ def add_key():
|
||||
direction = d.get("direction")
|
||||
symbol = d.get("symbol", "").strip()
|
||||
symbol_name = d.get("symbol_name", "").strip()
|
||||
market_code = d.get("market_code", "").strip()
|
||||
sina_code = d.get("sina_code", "").strip()
|
||||
if not direction:
|
||||
flash("请选择多空方向")
|
||||
return redirect(url_for("keys"))
|
||||
if not symbol or not sina_code:
|
||||
if not symbol or not market_code:
|
||||
flash("请从下拉列表选择品种(同花顺合约代码)")
|
||||
return redirect(url_for("keys"))
|
||||
conn = get_db()
|
||||
conn.execute(
|
||||
"""INSERT INTO key_monitors
|
||||
(symbol, symbol_name, sina_code, monitor_type, direction, upper, lower)
|
||||
VALUES (?,?,?,?,?,?,?)""",
|
||||
(symbol, symbol_name, sina_code, d["type"], direction, float(d["upper"]), float(d["lower"])),
|
||||
(symbol, symbol_name, market_code, sina_code, monitor_type, direction, upper, lower)
|
||||
VALUES (?,?,?,?,?,?,?,?)""",
|
||||
(symbol, symbol_name, market_code, sina_code, d["type"], direction, float(d["upper"]), float(d["lower"])),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
@@ -499,6 +521,11 @@ def settings():
|
||||
webhook = request.form.get("wechat_webhook", "").strip()
|
||||
set_setting("wechat_webhook", webhook)
|
||||
flash("企业微信配置已保存")
|
||||
elif action == "ths":
|
||||
token = request.form.get("ths_refresh_token", "").strip()
|
||||
set_setting("ths_refresh_token", token)
|
||||
sync_ths_token()
|
||||
flash("同花顺行情配置已保存")
|
||||
elif action == "password":
|
||||
old_p = request.form.get("old_password", "")
|
||||
new_p = request.form.get("new_password", "")
|
||||
@@ -516,8 +543,16 @@ def settings():
|
||||
return redirect(url_for("settings"))
|
||||
|
||||
webhook = get_setting("wechat_webhook")
|
||||
ths_token = get_setting("ths_refresh_token")
|
||||
username = get_setting("admin_username")
|
||||
return render_template("settings.html", webhook=webhook, username=username)
|
||||
quote_source = os.getenv("QUOTE_SOURCE", "auto")
|
||||
return render_template(
|
||||
"settings.html",
|
||||
webhook=webhook,
|
||||
ths_token=ths_token,
|
||||
username=username,
|
||||
quote_source=quote_source,
|
||||
)
|
||||
|
||||
# —————————————— 启动 ——————————————
|
||||
|
||||
|
||||
Reference in New Issue
Block a user