From c0e338eb239a4cce4364bba23dd6b2cc6fc499a9 Mon Sep 17 00:00:00 2001 From: fish Date: Fri, 24 Jul 2026 23:05:54 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=8D=9A=E5=BC=88=E5=88=86?= =?UTF-8?q?=E6=9E=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ft-app/app/engine/game_theory.py | 26 ---- ft-app/app/main.py | 3 +- ft-app/app/routers/analysis.py | 125 ------------------ ft-app/app/seed.py | 204 +---------------------------- ft-app/app/templates/analysis.html | 75 ----------- ft-app/app/templates/base.html | 3 - 6 files changed, 3 insertions(+), 433 deletions(-) delete mode 100644 ft-app/app/engine/game_theory.py delete mode 100644 ft-app/app/routers/analysis.py delete mode 100644 ft-app/app/templates/analysis.html diff --git a/ft-app/app/engine/game_theory.py b/ft-app/app/engine/game_theory.py deleted file mode 100644 index e6824fa..0000000 --- a/ft-app/app/engine/game_theory.py +++ /dev/null @@ -1,26 +0,0 @@ -"""博弈分析计算引擎""" - - -def net_position(long_pos: int, short_pos: int) -> int: - """净持仓 = 多单 - 空单。正=净多, 负=净空""" - return long_pos - short_pos - - -def net_pnl(net_pos: int, avg_cost: float, current_price: float) -> float: - """净盈亏 = 净持仓 × (现价 - 成本均价) × 20""" - return net_pos * (current_price - avg_cost) * 20 - - -def cost_delta(old_cost: float, new_cost: float) -> float: - """成本变化 = 新均价 - 旧均价""" - return round(new_cost - old_cost, 2) - - -def format_pnl(pnl_yuan: float) -> str: - """格式化盈亏为亿/万""" - yi = abs(pnl_yuan) / 1e8 - if yi >= 0.01: - sign = "+" if pnl_yuan >= 0 else "-" - return f"{sign}{yi:.2f}亿" - wan = abs(pnl_yuan) / 1e4 - return f"{'+' if pnl_yuan >= 0 else '-'}{wan:.1f}万" diff --git a/ft-app/app/main.py b/ft-app/app/main.py index 343fc13..ddd530a 100644 --- a/ft-app/app/main.py +++ b/ft-app/app/main.py @@ -7,7 +7,7 @@ from starlette.middleware.base import BaseHTTPMiddleware from app.database import engine, Base, SessionLocal from app.models import User from app.seed import seed -from app.routers import contracts, analysis, admin, auth +from app.routers import contracts, admin, auth TEMPLATES_DIR = Path(__file__).parent / "templates" @@ -55,7 +55,6 @@ app.add_middleware(AuthMiddleware) app.include_router(auth.router) app.include_router(contracts.router) -app.include_router(analysis.router) app.include_router(admin.router) diff --git a/ft-app/app/routers/analysis.py b/ft-app/app/routers/analysis.py deleted file mode 100644 index 55f5814..0000000 --- a/ft-app/app/routers/analysis.py +++ /dev/null @@ -1,125 +0,0 @@ -from fastapi import APIRouter, Depends, Request -from fastapi.responses import HTMLResponse -from sqlalchemy.orm import Session -from app.database import get_db -from app.models import PositionSnapshot, Contract, DailyBar -from app.engine.game_theory import net_position, net_pnl, format_pnl - -router = APIRouter(prefix="/analysis", tags=["analysis"]) - -INSTITUTIONS = ["中信期货", "高盛期货", "国泰君安期货", "华泰期货", "东证期货", "银河期货"] - - -@router.get("/", response_class=HTMLResponse) -def analysis_page(request: Request, db: Session = Depends(get_db)): - # Get active contracts for selector - active_contracts = ( - db.query(Contract.code) - .filter(Contract.is_active == True) - .order_by(Contract.code) - .all() - ) - contract_list = [c[0] for c in active_contracts] - - # Default to first contract, or use query param - selected = request.query_params.get("contract", contract_list[0] if contract_list else None) - - if not selected: - template = request.app.state.templates.get_template("analysis.html") - return HTMLResponse( - template.render(request=request, active_nav="analysis", rows=[], latest_date=None) - ) - - # Get latest date for selected contract - latest_snap = ( - db.query(PositionSnapshot.date) - .filter(PositionSnapshot.contract_code == selected) - .order_by(PositionSnapshot.date.desc()) - .first() - ) - - if not latest_snap: - template = request.app.state.templates.get_template("analysis.html") - return HTMLResponse( - template.render( - request=request, active_nav="analysis", - rows=[], latest_date=None, contracts=contract_list, selected=selected, - ) - ) - - latest_date = latest_snap[0] - - # Get latest close for current_price reference - latest_bar = ( - db.query(DailyBar) - .filter(DailyBar.contract == selected) - .order_by(DailyBar.date.desc()) - .first() - ) - current_price = int(latest_bar.close) if latest_bar else 0 - - rows = [] - total_net_short = 0 - pnl_sum = 0.0 - - for inst in INSTITUTIONS: - long = ( - db.query(PositionSnapshot) - .filter( - PositionSnapshot.contract_code == selected, - PositionSnapshot.institution == inst, - PositionSnapshot.direction == "long", - PositionSnapshot.date == latest_date, - ) - .first() - ) - short = ( - db.query(PositionSnapshot) - .filter( - PositionSnapshot.contract_code == selected, - PositionSnapshot.institution == inst, - PositionSnapshot.direction == "short", - PositionSnapshot.date == latest_date, - ) - .first() - ) - - long_pos = long.position if long else 0 - short_pos = short.position if short else 0 - long_cost = long.avg_cost if long else 0 - short_cost = short.avg_cost if short else 0 - - np = net_position(long_pos, short_pos) - pnl = 0.0 - if np < 0: - pnl = net_pnl(np, short_cost, current_price) - elif np > 0: - pnl = net_pnl(np, long_cost, current_price) - - if np < 0: - total_net_short += abs(np) - pnl_sum += pnl - - rows.append({ - "institution": inst, - "long_pos": f"{long_pos / 10000:.1f}万" if long_pos else "—", - "short_pos": f"{short_pos / 10000:.1f}万" if short_pos else "—", - "net_pos": f"净{'多' if np > 0 else '空'} {abs(np) / 10000:.1f}万", - "pnl": format_pnl(pnl), - "pnl_raw": pnl, - }) - - template = request.app.state.templates.get_template("analysis.html") - return HTMLResponse( - template.render( - request=request, - active_nav="analysis", - rows=rows, - latest_date=latest_date.strftime("%Y-%m-%d"), - current_price=current_price, - total_net_short=f"{total_net_short / 10000:.1f}万", - total_pnl=format_pnl(pnl_sum), - contracts=contract_list, - selected=selected, - ) - ) diff --git a/ft-app/app/seed.py b/ft-app/app/seed.py index cdb03c9..9c7a657 100644 --- a/ft-app/app/seed.py +++ b/ft-app/app/seed.py @@ -1,7 +1,7 @@ """Seed database from existing data files. Run once manually or on first start.""" from datetime import date from app.database import engine, Base, SessionLocal -from app.models import DailyBar, PositionSnapshot, Product, Contract, User +from app.models import DailyBar, Product, Contract, User from app.engine.lock_strategy import compute_amp_5d # --- Seed OHLCV data --- @@ -27,176 +27,6 @@ SEED_BARS: list[dict] = [ {"date": "2026-07-24", "open": 900, "close": 908, "high": 912, "low": 891}, ] -# --- Position snapshots (from info.txt) --- -POSITION_DATA_SHORT: list[dict] = [ - ("中信期货", "short", "2026-07-22", 193030, -22032, 995.26), - ("中信期货", "short", "2026-07-21", 215062, -1029, 995.26), - ("中信期货", "short", "2026-07-20", 216091, -18178, 995.26), - ("中信期货", "short", "2026-07-17", 234269, -31, 995.26), - ("中信期货", "short", "2026-07-16", 234300, 35258, 995.26), - ("中信期货", "short", "2026-07-15", 199042, 5294, 1005.40), - ("中信期货", "short", "2026-07-14", 193748, 4117, 1006.94), - ("中信期货", "short", "2026-07-13", 189631, 18219, 1008.16), - ("中信期货", "short", "2026-07-10", 171412, -17319, 1013.49), - ("中信期货", "short", "2026-07-09", 188731, 9860, 1013.49), - ("中信期货", "short", "2026-07-08", 178871, -19747, 1016.71), - ("中信期货", "short", "2026-07-07", 198618, 25262, 1016.71), - ("中信期货", "short", "2026-07-06", 173356, 2998, 1025.41), - ("中信期货", "short", "2026-07-03", 170358, -11691, 1026.30), - ("中信期货", "short", "2026-07-02", 182049, 1284, 1026.30), - ("中信期货", "long", "2026-07-22", 63971, -10850, 988.16), - ("中信期货", "long", "2026-07-21", 74821, 2587, 988.16), - ("中信期货", "long", "2026-07-20", 72234, -84, 991.28), - ("中信期货", "long", "2026-07-17", 72318, 6928, 991.28), - ("中信期货", "long", "2026-07-16", 65390, 6950, 999.15), - ("中信期货", "long", "2026-07-15", 58440, -1227, 1006.42), - ("中信期货", "long", "2026-07-14", 59667, 887, 1006.42), - ("中信期货", "long", "2026-07-13", 58780, -4908, 1007.26), - ("中信期货", "long", "2026-07-10", 63688, 5795, 1007.26), - ("中信期货", "long", "2026-07-09", 57893, -3193, 1011.59), - ("中信期货", "long", "2026-07-08", 61086, 2092, 1011.59), - ("中信期货", "long", "2026-07-07", 58994, 8116, 1013.45), - ("中信期货", "long", "2026-07-06", 50878, -14738, 1022.46), - ("中信期货", "long", "2026-07-03", 65616, 9777, 1022.46), - ("中信期货", "long", "2026-07-02", 55839, -2024, 1031.30), - ("高盛期货", "short", "2026-07-22", 188460, -14927, 997.89), - ("高盛期货", "short", "2026-07-21", 203387, -15903, 997.89), - ("高盛期货", "short", "2026-07-20", 219290, 1220, 997.89), - ("高盛期货", "short", "2026-07-17", 218070, 14452, 998.44), - ("高盛期货", "short", "2026-07-16", 203618, 12879, 1004.22), - ("高盛期货", "short", "2026-07-15", 190739, -5701, 1008.69), - ("高盛期货", "short", "2026-07-14", 196440, 1711, 1008.69), - ("高盛期货", "short", "2026-07-13", 194729, 418, 1009.20), - ("高盛期货", "short", "2026-07-10", 194311, -5203, 1009.31), - ("高盛期货", "short", "2026-07-09", 199514, 7653, 1009.31), - ("高盛期货", "short", "2026-07-08", 191861, 1394, 1011.47), - ("高盛期货", "short", "2026-07-07", 190467, 12046, 1011.86), - ("高盛期货", "short", "2026-07-06", 178421, 578, 1015.56), - ("高盛期货", "short", "2026-07-03", 177843, 1049, 1015.69), - ("高盛期货", "short", "2026-07-02", 176794, 19121, 1015.95), - ("国泰君安期货", "short", "2026-07-22", 168449, -9289, 1018.54), - ("国泰君安期货", "short", "2026-07-21", 177738, -10380, 1018.54), - ("国泰君安期货", "short", "2026-07-20", 188118, -731, 1018.54), - ("国泰君安期货", "short", "2026-07-17", 188849, -12984, 1018.54), - ("国泰君安期货", "short", "2026-07-16", 201833, -5144, 1018.54), - ("国泰君安期货", "short", "2026-07-15", 206977, 2787, 1018.54), - ("国泰君安期货", "short", "2026-07-14", 204190, -2399, 1019.49), - ("国泰君安期货", "short", "2026-07-13", 206589, 24344, 1019.49), - ("国泰君安期货", "short", "2026-07-10", 182245, -4391, 1027.70), - ("国泰君安期货", "short", "2026-07-09", 186636, -6510, 1027.70), - ("国泰君安期货", "short", "2026-07-08", 193146, -6957, 1027.70), - ("国泰君安期货", "short", "2026-07-07", 200103, 9696, 1027.70), - ("国泰君安期货", "short", "2026-07-06", 190407, 1344, 1031.30), - ("国泰君安期货", "short", "2026-07-03", 189063, -1588, 1031.70), - ("国泰君安期货", "short", "2026-07-02", 190651, 4656, 1031.70), - ("国泰君安期货", "long", "2026-07-22", 144325, -6262, 991.07), - ("国泰君安期货", "long", "2026-07-21", 150587, 17790, 991.07), - ("国泰君安期货", "long", "2026-07-20", 132797, 3578, 1003.13), - ("国泰君安期货", "long", "2026-07-17", 129219, 12066, 1005.99), - ("国泰君安期货", "long", "2026-07-16", 117153, 8387, 1015.15), - ("国泰君安期货", "long", "2026-07-15", 108766, 5534, 1021.10), - ("国泰君安期货", "long", "2026-07-14", 103232, 4815, 1024.97), - ("国泰君安期货", "long", "2026-07-13", 98417, 4839, 1028.58), - ("国泰君安期货", "long", "2026-07-10", 93578, -1293, 1032.23), - ("国泰君安期货", "long", "2026-07-09", 94871, -807, 1032.23), - ("国泰君安期货", "long", "2026-07-08", 95678, -5169, 1032.23), - ("国泰君安期货", "long", "2026-07-07", 100847, 3412, 1032.23), - ("国泰君安期货", "long", "2026-07-06", 97435, -4615, 1034.87), - ("国泰君安期货", "long", "2026-07-03", 102050, 2169, 1034.87), - ("国泰君安期货", "long", "2026-07-02", 99881, 9801, 1036.23), - ("华泰期货", "short", "2026-07-22", 80564, -8762, 976.69), - ("华泰期货", "short", "2026-07-21", 89326, 9844, 976.69), - ("华泰期货", "short", "2026-07-20", 79482, 1751, 986.06), - ("华泰期货", "short", "2026-07-17", 77731, -8367, 988.00), - ("华泰期货", "short", "2026-07-16", 86098, 11358, 988.00), - ("华泰期货", "short", "2026-07-15", 74740, 3028, 995.60), - ("华泰期货", "short", "2026-07-14", 71712, -2199, 997.57), - ("华泰期货", "short", "2026-07-13", 73911, 10715, 997.57), - ("华泰期货", "short", "2026-07-10", 63196, -3512, 1004.28), - ("华泰期货", "short", "2026-07-09", 66708, 3827, 1004.28), - ("华泰期货", "short", "2026-07-08", 62881, -10077, 1007.27), - ("华泰期货", "short", "2026-07-07", 72958, 12276, 1007.27), - ("华泰期货", "short", "2026-07-06", 60682, -6933, 1017.45), - ("华泰期货", "short", "2026-07-03", 65615, -5963, 1017.45), - ("华泰期货", "short", "2026-07-02", 71558, -2128, 1017.45), - ("华泰期货", "long", "2026-07-22", 68791, -5130, 1002.62), - ("华泰期货", "long", "2026-07-21", 73921, -274, 1002.62), - ("华泰期货", "long", "2026-07-20", 74195, 840, 1002.62), - ("华泰期货", "long", "2026-07-17", 73355, 7012, 1003.79), - ("华泰期货", "long", "2026-07-16", 66343, 4562, 1012.97), - ("华泰期货", "long", "2026-07-15", 61781, -1562, 1018.50), - ("华泰期货", "long", "2026-07-14", 63343, 2364, 1018.50), - ("华泰期货", "long", "2026-07-13", 60979, -1843, 1021.12), - ("华泰期货", "long", "2026-07-10", 62822, 1161, 1021.12), - ("华泰期货", "long", "2026-07-09", 61661, 162, 1022.19), - ("华泰期货", "long", "2026-07-08", 61499, 82, 1022.37), - ("华泰期货", "long", "2026-07-07", 61417, 6050, 1022.46), - ("华泰期货", "long", "2026-07-06", 55367, -2699, 1029.61), - ("华泰期货", "long", "2026-07-03", 58066, -4006, 1029.61), - ("华泰期货", "long", "2026-07-02", 62072, -2935, 1029.61), - ("东证期货", "short", "2026-07-22", 112614, -18937, 965.67), - ("东证期货", "short", "2026-07-21", 131551, -45486, 965.67), - ("东证期货", "short", "2026-07-20", 177037, -1629, 965.67), - ("东证期货", "short", "2026-07-17", 178666, -4252, 965.67), - ("东证期货", "short", "2026-07-16", 182918, 47376, 965.67), - ("东证期货", "short", "2026-07-15", 135542, -13505, 975.35), - ("东证期货", "short", "2026-07-14", 149047, -1108, 975.35), - ("东证期货", "short", "2026-07-13", 150155, 40931, 975.35), - ("东证期货", "short", "2026-07-10", 109224, -23556, 981.85), - ("东证期货", "short", "2026-07-09", 132780, 25017, 981.85), - ("东证期货", "short", "2026-07-08", 107763, -56346, 988.08), - ("东证期货", "short", "2026-07-07", 164109, 37956, 988.08), - ("东证期货", "short", "2026-07-06", 126153, 20536, 997.43), - ("东证期货", "short", "2026-07-03", 105617, -10003, 1001.79), - ("东证期货", "short", "2026-07-02", 115620, -16409, 1001.79), - ("东证期货", "long", "2026-07-22", 85630, 6685, 965.35), - ("东证期货", "long", "2026-07-21", 78945, 8359, 970.20), - ("东证期货", "long", "2026-07-20", 70586, 2334, 978.40), - ("东证期货", "long", "2026-07-17", 68252, -5918, 981.08), - ("东证期货", "long", "2026-07-16", 74170, 10413, 981.08), - ("东证期货", "long", "2026-07-15", 63757, 1640, 988.12), - ("东证期货", "long", "2026-07-14", 62117, -2136, 989.15), - ("东证期货", "long", "2026-07-13", 64253, -14158, 989.15), - ("东证期货", "long", "2026-07-10", 78411, 7829, 989.15), - ("东证期货", "long", "2026-07-09", 70582, -9231, 991.94), - ("东证期货", "long", "2026-07-08", 79813, 11598, 991.94), - ("东证期货", "long", "2026-07-07", 68215, 10382, 997.54), - ("东证期货", "long", "2026-07-06", 57833, -30335, 1004.82), - ("东证期货", "long", "2026-07-03", 88168, 20705, 1004.82), - ("东证期货", "long", "2026-07-02", 67463, 3862, 1014.89), - ("银河期货", "short", "2026-07-22", 62130, -3771, 1022.69), - ("银河期货", "short", "2026-07-21", 65901, -3865, 1022.69), - ("银河期货", "short", "2026-07-20", 69766, 1572, 1022.69), - ("银河期货", "short", "2026-07-17", 68194, 431, 1025.51), - ("银河期货", "short", "2026-07-16", 67763, -936, 1026.20), - ("银河期货", "short", "2026-07-15", 68699, 372, 1026.20), - ("银河期货", "short", "2026-07-14", 68327, 5179, 1026.62), - ("银河期货", "short", "2026-07-13", 63148, -3119, 1032.83), - ("银河期货", "short", "2026-07-10", 66267, -431, 1032.83), - ("银河期货", "short", "2026-07-09", 66698, 1995, 1032.83), - ("银河期货", "short", "2026-07-08", 64703, -5025, 1035.23), - ("银河期货", "short", "2026-07-07", 69728, 6103, 1035.23), - ("银河期货", "short", "2026-07-06", 63625, -1703, 1042.73), - ("银河期货", "short", "2026-07-03", 65328, -3861, 1042.73), - ("银河期货", "short", "2026-07-02", 69189, 1875, 1042.73), - ("银河期货", "long", "2026-07-22", 57020, -7565, 1016.17), - ("银河期货", "long", "2026-07-21", 64585, -4812, 1016.17), - ("银河期货", "long", "2026-07-20", 69397, -2877, 1016.17), - ("银河期货", "long", "2026-07-17", 72274, -4410, 1016.17), - ("银河期货", "long", "2026-07-16", 76684, 4888, 1016.17), - ("银河期货", "long", "2026-07-15", 71796, -3235, 1021.49), - ("银河期货", "long", "2026-07-14", 75031, -456, 1021.49), - ("银河期货", "long", "2026-07-13", 75487, 4361, 1021.49), - ("银河期货", "long", "2026-07-10", 71126, -6491, 1025.39), - ("银河期货", "long", "2026-07-09", 77617, 376, 1025.39), - ("银河期货", "long", "2026-07-08", 77241, -3621, 1025.73), - ("银河期货", "long", "2026-07-07", 80862, 10307, 1025.73), - ("银河期货", "long", "2026-07-06", 70555, 2439, 1035.77), - ("银河期货", "long", "2026-07-03", 68116, -4101, 1037.95), - ("银河期货", "long", "2026-07-02", 72217, 490, 1037.95), -] - - def seed(): Base.metadata.create_all(bind=engine) db = SessionLocal() @@ -260,38 +90,8 @@ def seed(): if i >= 5: bar.amp_5d = compute_amp_5d([b.diff for b in seed_bars[i - 5 : i]]) - # --- Seed position snapshots --- - existing_pos = { - (r.contract_code, r.institution, r.direction, r.date) - for r in db.query( - PositionSnapshot.contract_code, - PositionSnapshot.institution, - PositionSnapshot.direction, - PositionSnapshot.date, - ).all() - } - - snaps = [] - for inst, direction, date_str, pos, delta, cost in POSITION_DATA_SHORT: - d = date.fromisoformat(date_str) - if ("FG2609", inst, direction, d) not in existing_pos: - snaps.append( - PositionSnapshot( - contract_code="FG2609", - institution=inst, - direction=direction, - date=d, - position=pos, - delta=delta, - avg_cost=cost, - ) - ) - - if snaps: - db.add_all(snaps) - db.commit() - print(f"Seeded {len(bars_to_insert)} bars + {len(snaps)} position snapshots") + print(f"Seeded {len(bars_to_insert)} bars") finally: db.close() diff --git a/ft-app/app/templates/analysis.html b/ft-app/app/templates/analysis.html deleted file mode 100644 index 8932df2..0000000 --- a/ft-app/app/templates/analysis.html +++ /dev/null @@ -1,75 +0,0 @@ -{% extends "base.html" %} -{% block title %}博弈分析{% endblock %} -{% block heading %}博弈分析{% endblock %} -{% block breadcrumb %}机构持仓{% endblock %} - -{% block content %} -{% if contracts %} -
- 合约 - -
-{% endif %} - -{% if latest_date %} -
-
-
数据日期
-
{{ latest_date }}
-
-
-
{{ selected }} 现价
-
{{ current_price }}
-
-
-
六家净空
-
{{ total_net_short }}
-
-
-
浮动盈亏
-
{{ total_pnl }}
-
-
- -
机构持仓明细
-
- - - - - {% for r in rows %} - - - - - - - - {% endfor %} - - - - - - - -
机构多单空单净持仓净盈亏
{{ r.institution }}{{ r.long_pos }}{{ r.short_pos }}{{ r.net_pos }} - {% if r.pnl_raw > 0 %} - {{ r.pnl }} - {% elif r.pnl_raw < 0 %} - {{ r.pnl }} - {% else %} - - {% endif %} -
合计{{ total_net_short }}{{ total_pnl }}
-
-{% else %} -
-

暂无「{{ selected }}」的持仓数据

-
-{% endif %} -{% endblock %} diff --git a/ft-app/app/templates/base.html b/ft-app/app/templates/base.html index 192afff..f0960eb 100644 --- a/ft-app/app/templates/base.html +++ b/ft-app/app/templates/base.html @@ -195,9 +195,6 @@ 📈 行情数据 - - ⚔️ 博弈分析 - ⚙️ 系统管理