feat: 手续费仅CTP每日后台同步入库,前端只读展示

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-24 13:33:14 +08:00
parent de6815d481
commit e01c011df5
7 changed files with 240 additions and 214 deletions
+17 -56
View File
@@ -29,15 +29,10 @@ from contract_specs import calc_position_metrics
from fee_specs import (
calc_fee_breakdown,
calc_round_trip_fee,
get_fee_multiplier,
get_fee_source_mode,
list_all_fee_rates,
list_fee_rates_for_ui,
count_fee_rates_by_source,
load_fee_rates_from_json,
upsert_fee_rate,
purge_non_ctp_fee_rates,
)
from fee_sync import sync_fees_from_akshare
from nav_settings import NAV_TOGGLES, get_nav_items, nav_enabled, save_nav_items
from contract_profile import get_contract_profile
from stats_engine import STATS_VIEWS, load_stats_cache, refresh_stats_cache
@@ -376,11 +371,11 @@ def init_db():
set_setting("risk_percent", "1")
if not get_setting("fee_source_mode"):
set_setting("fee_source_mode", "ctp")
conn = get_db()
fee_cnt = conn.execute("SELECT COUNT(*) FROM fee_rates").fetchone()[0]
conn.close()
if fee_cnt == 0:
load_fee_rates_from_json()
set_setting("fee_source_mode", "ctp")
try:
purge_non_ctp_fee_rates()
except Exception:
pass
def sync_admin_from_env():
@@ -1565,66 +1560,32 @@ def api_contract_profile():
@require_nav("fees")
def fees():
from trading_context import get_trading_mode
from ctp_fee_sync import sync_fees_from_ctp
from ctp_fee_worker import try_daily_ctp_fee_sync, get_fee_last_sync, fees_synced_today
from vnpy_bridge import ctp_status
mode = get_trading_mode(get_setting)
if request.method == "POST":
action = request.form.get("action")
if action == "fee_source":
fs = request.form.get("fee_source_mode", "ctp").strip()
set_setting("fee_source_mode", fs if fs in ("ctp", "local") else "ctp")
flash("手续费数据源已保存")
elif action == "sync_ctp":
count, msg = sync_fees_from_ctp(mode)
if action == "sync_ctp":
force = request.form.get("force") == "1"
count, msg = try_daily_ctp_fee_sync(
mode,
get_setting=get_setting,
set_setting=set_setting,
force=force,
)
flash(msg)
elif action == "multiplier":
try:
mult = float(request.form.get("fee_multiplier", "2"))
if mult < 0:
flash("倍率不能为负数")
else:
set_setting("fee_multiplier", str(mult))
flash(f"手续费倍率已保存:标准 × {mult}")
except ValueError:
flash("请输入有效倍率")
elif action == "sync":
mult = float(get_setting("fee_multiplier", "2") or 2)
count, msg = sync_fees_from_akshare(mult)
flash(msg if count else msg)
elif action == "reload_json":
n = load_fee_rates_from_json()
flash(f"已从本地 JSON 加载 {n} 个品种费率")
elif action == "save_row":
product = request.form.get("product", "").strip().lower()
if not product:
flash("品种代码不能为空")
else:
upsert_fee_rate(product, {
"exchange": request.form.get("exchange", "").strip(),
"mult": int(request.form.get("mult") or 10),
"open_fixed": float(request.form.get("open_fixed") or 0),
"open_ratio": float(request.form.get("open_ratio") or 0),
"close_yesterday_fixed": float(request.form.get("close_yesterday_fixed") or 0),
"close_yesterday_ratio": float(request.form.get("close_yesterday_ratio") or 0),
"close_today_fixed": float(request.form.get("close_today_fixed") or 0),
"close_today_ratio": float(request.form.get("close_today_ratio") or 0),
"source": "manual",
})
flash(f"已保存 {product} 费率")
return redirect(url_for("fees"))
rates = list_fee_rates_for_ui()
fee_counts = count_fee_rates_by_source()
multiplier = get_setting("fee_multiplier", "2")
fee_source_mode = get_fee_source_mode()
ctp_st = ctp_status(mode)
return render_template(
"fees.html",
rates=rates,
fee_counts=fee_counts,
multiplier=multiplier,
fee_source_mode=fee_source_mode,
fee_last_sync=get_fee_last_sync(get_setting),
fee_synced_today=fees_synced_today(get_setting),
ctp_connected=bool(ctp_st.get("connected")),
)