from datetime import date from fastapi import APIRouter, Depends, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy.orm import Session from app.database import get_db from app.models import DualOptionTrade, Contract, Product router = APIRouter(prefix="/dual-options", tags=["dual_options"]) def get_product_contracts(db: Session) -> dict: result: dict[str, list[str]] = {} products = db.query(Product).order_by(Product.code).all() for p in products: codes = [c.code for c in p.contracts if c.is_active] if codes: result[p.code] = codes return result def today_str() -> str: return date.today().isoformat() @router.get("/", response_class=HTMLResponse) def dual_option_page(request: Request, db: Session = Depends(get_db)): view = request.query_params.get("view", "") open_trades = ( db.query(DualOptionTrade).filter(DualOptionTrade.status == "open") .order_by(DualOptionTrade.open_date.desc()).all() ) closed_trades = ( db.query(DualOptionTrade).filter(DualOptionTrade.status == "closed") .order_by(DualOptionTrade.close_date.desc()).limit(50).all() ) template = request.app.state.templates.get_template("dual_options.html") return HTMLResponse( template.render( request=request, active_nav="dual_options", product_contracts=get_product_contracts(db), open_trades=open_trades, closed_trades=closed_trades, today=today_str(), weekdays=["周一","周二","周三","周四","周五","周六","周日"], ) ) @router.post("/open") def open_trade( request: Request, contract_code: str = Form(...), strike_price: float = Form(...), call_open_price: float = Form(...), put_open_price: float = Form(...), call_open_fee: float = Form(0.0), put_open_fee: float = Form(0.0), open_date: str = Form(...), db: Session = Depends(get_db), ): code = contract_code.upper() contract = db.query(Contract).filter(Contract.code == code).first() if contract: product = contract.product else: product = db.query(Product).filter(Product.code == code[:2]).first() product_code = product.code if product else code[:2] point_value = product.point_value if product else 20 t = DualOptionTrade( product_code=product_code, contract_code=code, strike_price=strike_price, call_open_price=call_open_price, put_open_price=put_open_price, call_open_fee=call_open_fee, put_open_fee=put_open_fee, open_date=date.fromisoformat(open_date), point_value=point_value, status="open", ) db.add(t) db.commit() return RedirectResponse("/dual-options/", status_code=303) @router.post("/{trade_id}/close") def close_trade( request: Request, trade_id: int, close_date: str = Form(...), call_close_price: float = Form(...), put_close_price: float = Form(...), call_close_fee: float = Form(0.0), put_close_fee: float = Form(0.0), db: Session = Depends(get_db), ): t = db.query(DualOptionTrade).filter(DualOptionTrade.id == trade_id).first() if t and t.status == "open": t.close_date = date.fromisoformat(close_date) t.call_close_price = call_close_price t.put_close_price = put_close_price t.call_close_fee = call_close_fee t.put_close_fee = put_close_fee t.status = "closed" db.commit() return RedirectResponse("/dual-options/", status_code=303) @router.post("/{trade_id}/edit") def edit_trade( request: Request, trade_id: int, contract_code: str = Form(...), strike_price: float = Form(...), call_open_price: float = Form(...), put_open_price: float = Form(...), call_open_fee: float = Form(0.0), put_open_fee: float = Form(0.0), open_date: str = Form(...), close_date: str = Form(""), call_close_price: str = Form(""), put_close_price: str = Form(""), call_close_fee: str = Form(""), put_close_fee: str = Form(""), db: Session = Depends(get_db), ): t = db.query(DualOptionTrade).filter(DualOptionTrade.id == trade_id).first() if t: code = contract_code.upper() contract = db.query(Contract).filter(Contract.code == code).first() if contract: product = contract.product else: product = db.query(Product).filter(Product.code == code[:2]).first() t.product_code = product.code if product else code[:2] t.point_value = product.point_value if product else 20 t.contract_code = code t.strike_price = strike_price t.call_open_price = call_open_price t.put_open_price = put_open_price t.call_open_fee = call_open_fee t.put_open_fee = put_open_fee t.open_date = date.fromisoformat(open_date) if close_date and call_close_price and put_close_price: t.close_date = date.fromisoformat(close_date) t.call_close_price = float(call_close_price) t.put_close_price = float(put_close_price) t.call_close_fee = float(call_close_fee) if call_close_fee else 0.0 t.put_close_fee = float(put_close_fee) if put_close_fee else 0.0 db.commit() return RedirectResponse("/dual-options/", status_code=303) @router.post("/{trade_id}/delete") def delete_trade(trade_id: int, db: Session = Depends(get_db)): t = db.query(DualOptionTrade).filter(DualOptionTrade.id == trade_id).first() if t: db.delete(t) db.commit() return RedirectResponse("/dual-options/", status_code=303)