移除全部合约同步按钮,改为单合约后台同步带进度条

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 13:53:44 +08:00
parent b74dccd805
commit ca98967af0
3 changed files with 135 additions and 153 deletions
+79 -71
View File
@@ -5,119 +5,127 @@ from app.database import SessionLocal
from app.models import DailyBar, Contract
from app.engine.lock_strategy import compute_amp_5d
_sync_progress = {
"running": False,
"contract": "",
"contract_done": 0,
"contract_total": 0,
"date_done": 0,
"date_total": 0,
"rows": 0,
"finished": False,
}
_progress = {"running": False, "label": "", "done": 0, "total": 0, "finished": False}
_lock = threading.Lock()
def get_sync_progress() -> dict:
def get_progress() -> dict:
with _lock:
return dict(_sync_progress)
return dict(_progress)
def start_sync_positions_background():
"""Start sync_position_rankings in a background thread. Returns immediately."""
def _start_bg(target, label):
with _lock:
if _sync_progress["running"]:
if _progress["running"]:
return False
_sync_progress.update({
"running": True,
"finished": False,
"contract": "",
"contract_done": 0,
"contract_total": 0,
"date_done": 0,
"date_total": 0,
"rows": 0,
})
_progress.update(running=True, finished=False, label=label, done=0, total=0)
def _run():
try:
_do_sync_with_progress()
target()
finally:
with _lock:
_sync_progress["running"] = False
_sync_progress["finished"] = True
_progress["running"] = False
_progress["finished"] = True
_progress["done"] = _progress["total"]
threading.Thread(target=_run, daemon=True).start()
return True
def _do_sync_with_progress():
from app.models import PositionRanking
def sync_contract_bars_bg(contract_code: str) -> bool:
"""Sync bars for one contract in background. Returns True if started."""
code = contract_code.upper()
db = SessionLocal()
try:
active_contracts = (
db.query(Contract).filter(Contract.is_active == True).all()
)
with _lock:
_sync_progress["contract_total"] = len(active_contracts)
def _run():
db = SessionLocal()
try:
latest = (
db.query(DailyBar.date)
.filter(DailyBar.contract == code)
.order_by(DailyBar.date.desc())
.first()
)
start_date = latest[0].isoformat() if latest else None
bars = fetch_contract_bars(code, start_date)
for idx, c in enumerate(active_contracts):
with _lock:
_sync_progress.update({
"contract": c.code,
"contract_done": idx,
"date_done": 0,
"date_total": 0,
})
_progress["total"] = len(bars)
code = c.code.upper()
inserted = 0
min_date = None
for i, bar in enumerate(bars):
existing = (
db.query(DailyBar)
.filter(DailyBar.contract == code, DailyBar.date == bar["date"])
.first()
)
if not existing:
db.add(DailyBar(
contract=code, date=bar["date"],
open=bar["open"], close=bar["close"],
high=bar["high"], low=bar["low"],
))
inserted += 1
if min_date is None or bar["date"] < min_date:
min_date = bar["date"]
with _lock:
_progress["done"] = i + 1
if inserted > 0:
db.flush()
_recompute_amp(db, code, from_date=min_date)
db.commit()
finally:
db.close()
return _start_bg(_run, f"同步行情 {code}")
def sync_positions_bg(contract_code: str) -> bool:
"""Sync position rankings for one contract in background. Returns True if started."""
from app.models import PositionRanking
code = contract_code.upper()
def _run():
db = SessionLocal()
try:
existing_dates = {
r[0] for r in
db.query(PositionRanking.date)
.filter(PositionRanking.contract_code == code)
.distinct()
.all()
.distinct().all()
}
bar_dates = [
r[0] for r in
db.query(DailyBar.date)
.filter(DailyBar.contract == code)
.order_by(DailyBar.date)
.all()
.order_by(DailyBar.date).all()
]
missing = [d for d in bar_dates if d not in existing_dates]
with _lock:
_sync_progress["date_total"] = len(missing)
for date_idx, d in enumerate(missing):
date_str = d.strftime("%Y%m%d")
rankings = fetch_position_rankings(code, date_str)
inserted = 0
with _lock:
_progress["total"] = len(missing)
inserted = 0
for i, d in enumerate(missing):
rankings = fetch_position_rankings(code, d.strftime("%Y%m%d"))
for r in rankings:
db.add(PositionRanking(
contract_code=code,
institution=r["institution"],
data_type=r["data_type"],
date=d,
rank=r["rank"],
value=r["value"],
change=r["change"],
contract_code=code, institution=r["institution"],
data_type=r["data_type"], date=d,
rank=r["rank"], value=r["value"], change=r["change"],
))
inserted += 1
db.flush()
with _lock:
_sync_progress["date_done"] = date_idx + 1
_sync_progress["rows"] += inserted
_progress["done"] = i + 1
db.commit()
with _lock:
_sync_progress["contract_done"] = len(active_contracts)
finally:
db.close()
db.commit()
finally:
db.close()
return _start_bg(_run, f"同步持仓 {code}")
def fetch_contract_bars(contract_code: str, start_date: str | None = None) -> list[dict]: