修复数据采集和清理的bug,新增持仓排名功能,日线数据分页
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import math
|
||||
from datetime import date, timedelta
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from fastapi import APIRouter, Depends, Request, Query
|
||||
from fastapi.responses import HTMLResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
from app.models import DailyBar, Contract
|
||||
from app.models import DailyBar, Contract, PositionRanking
|
||||
|
||||
router = APIRouter(prefix="/contracts", tags=["contracts"])
|
||||
|
||||
WEEKDAY_ZH = {0: "周一", 1: "周二", 2: "周三", 3: "周四", 4: "周五", 5: "周六", 6: "周日"}
|
||||
PAGE_SIZE = 7
|
||||
|
||||
|
||||
def get_active_contracts(db: Session) -> list[str]:
|
||||
@@ -47,7 +49,13 @@ def contract_index(request: Request, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/{contract}", response_class=HTMLResponse)
|
||||
def contract_detail(request: Request, contract: str, db: Session = Depends(get_db)):
|
||||
def contract_detail(
|
||||
request: Request,
|
||||
contract: str,
|
||||
pos_date: str | None = None,
|
||||
page: int = Query(1, ge=1),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
active_contracts = get_active_contracts(db)
|
||||
bars = (
|
||||
db.query(DailyBar)
|
||||
@@ -56,9 +64,17 @@ def contract_detail(request: Request, contract: str, db: Session = Depends(get_d
|
||||
.all()
|
||||
)
|
||||
|
||||
total = len(bars)
|
||||
total_pages = max(1, math.ceil(total / PAGE_SIZE))
|
||||
page = min(page, total_pages)
|
||||
start = (page - 1) * PAGE_SIZE
|
||||
page_bars = bars[start:start + PAGE_SIZE]
|
||||
|
||||
rows = []
|
||||
for bar in bars:
|
||||
for i, bar in enumerate(page_bars):
|
||||
global_idx = start + i
|
||||
rows.append({
|
||||
"global_idx": global_idx,
|
||||
"date": bar.date.strftime("%Y/%-m/%-d"),
|
||||
"weekday": WEEKDAY_ZH.get(bar.date.weekday(), ""),
|
||||
"open": int(bar.open) if bar.open else "-",
|
||||
@@ -72,6 +88,45 @@ def contract_detail(request: Request, contract: str, db: Session = Depends(get_d
|
||||
|
||||
latest = bars[0] if bars else None
|
||||
|
||||
# Dates that have position data (for date picker)
|
||||
pos_dates = [
|
||||
r[0] for r in
|
||||
db.query(PositionRanking.date)
|
||||
.filter(PositionRanking.contract_code == contract.upper())
|
||||
.distinct()
|
||||
.order_by(PositionRanking.date.desc())
|
||||
.all()
|
||||
]
|
||||
|
||||
# Determine which date to show position rankings for
|
||||
if pos_date:
|
||||
try:
|
||||
selected_date = date.fromisoformat(pos_date)
|
||||
except ValueError:
|
||||
selected_date = pos_dates[0] if pos_dates else None
|
||||
else:
|
||||
selected_date = pos_dates[0] if pos_dates else None
|
||||
|
||||
# Position rankings for the selected date
|
||||
pos_data = {"volume": [], "long": [], "short": []}
|
||||
if selected_date:
|
||||
rankings = (
|
||||
db.query(PositionRanking)
|
||||
.filter(
|
||||
PositionRanking.contract_code == contract.upper(),
|
||||
PositionRanking.date == selected_date,
|
||||
)
|
||||
.order_by(PositionRanking.data_type, PositionRanking.rank)
|
||||
.all()
|
||||
)
|
||||
for r in rankings:
|
||||
pos_data[r.data_type].append({
|
||||
"rank": r.rank,
|
||||
"institution": r.institution,
|
||||
"value": r.value,
|
||||
"change": r.change,
|
||||
})
|
||||
|
||||
# Predict next trading day amplitude: mean of latest 5 diffs
|
||||
# Compute next trading date
|
||||
next_date = latest.date + timedelta(days=1) if latest else None
|
||||
@@ -91,9 +146,17 @@ def contract_detail(request: Request, contract: str, db: Session = Depends(get_d
|
||||
contracts=active_contracts,
|
||||
rows=rows,
|
||||
latest=latest,
|
||||
pos_dates=pos_dates,
|
||||
selected_pos_date=selected_date,
|
||||
pos_data=pos_data,
|
||||
next_amp=next_amp,
|
||||
next_date=next_date.strftime("%Y/%-m/%-d") if next_date else None,
|
||||
next_weekday=WEEKDAY_ZH.get(next_date.weekday(), "") if next_date else "",
|
||||
row_count=len(rows),
|
||||
total_rows=total,
|
||||
page=page,
|
||||
total_pages=total_pages,
|
||||
pos_date=pos_date or "",
|
||||
WEEKDAY_ZH=WEEKDAY_ZH,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user