Initial standalone crypto_okx with one-click deploy.
Add deploy/manage.sh bootstrap for git.bz121.com/dekun/crypto_okx and point docs at this repo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""复盘自动 K 线:后台线程生成,避免 /add_journal 同步卡住."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import threading
|
||||
from typing import Any, Callable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def schedule_journal_exchange_chart(
|
||||
*,
|
||||
entry_id: str,
|
||||
exchange_symbol: str,
|
||||
title_prefix: str,
|
||||
journal_tfs: list[str],
|
||||
journal_limit: int,
|
||||
marker_payload: dict[str, Any],
|
||||
upload_folder: str,
|
||||
generate_chart_fn: Callable[..., str | None],
|
||||
get_db_fn: Callable[[], Any],
|
||||
) -> None:
|
||||
"""提交后立即返回;线程内画图并写回 journal_entries.image."""
|
||||
entry_id = str(entry_id or "").strip()
|
||||
if not entry_id or not callable(generate_chart_fn) or not callable(get_db_fn):
|
||||
return
|
||||
|
||||
tfs = [str(x).strip() for x in (journal_tfs or []) if str(x).strip()]
|
||||
if not tfs:
|
||||
return
|
||||
|
||||
def _run() -> None:
|
||||
try:
|
||||
chart_fname = f"journal_{entry_id}.png"
|
||||
saved = generate_chart_fn(
|
||||
exchange_symbol,
|
||||
title_prefix,
|
||||
timeframes=tfs,
|
||||
limit=journal_limit,
|
||||
out_dir=upload_folder,
|
||||
filename=chart_fname,
|
||||
filename_prefix="journal",
|
||||
marker_payload=marker_payload,
|
||||
marker_timeframes={x.lower() for x in tfs},
|
||||
layout="vertical",
|
||||
)
|
||||
if not saved:
|
||||
logger.warning("journal chart async empty entry_id=%s", entry_id)
|
||||
return
|
||||
conn = get_db_fn()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE journal_entries SET image=? WHERE id=?",
|
||||
(saved, entry_id),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
except Exception:
|
||||
logger.exception("journal chart async failed entry_id=%s", entry_id)
|
||||
|
||||
threading.Thread(
|
||||
target=_run,
|
||||
name=f"journal-chart-{entry_id[:8]}",
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
|
||||
def request_wants_journal_ajax(request: Any) -> bool:
|
||||
"""XHR / Accept:json / form ajax=1 → 返回 JSON,避免整页刷新."""
|
||||
xrw = str(getattr(request, "headers", {}).get("X-Requested-With") or "").lower()
|
||||
if xrw == "xmlhttprequest":
|
||||
return True
|
||||
form = getattr(request, "form", None)
|
||||
if form is not None:
|
||||
raw = str(form.get("ajax") or "").strip().lower()
|
||||
if raw in ("1", "true", "yes", "on"):
|
||||
return True
|
||||
accept = str(getattr(request, "headers", {}).get("Accept") or "").lower()
|
||||
if "application/json" in accept and accept.strip().startswith("application/json"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def journal_ajax_or_flash_error(request: Any, msg: str, *, redirect_fn: Callable[[], Any]):
|
||||
"""校验失败:AJAX 返回 JSON,否则 flash + 跳转."""
|
||||
from flask import flash, jsonify
|
||||
|
||||
if request_wants_journal_ajax(request):
|
||||
return jsonify({"ok": False, "msg": msg}), 400
|
||||
flash(msg)
|
||||
return redirect_fn()
|
||||
Reference in New Issue
Block a user