期权交易"权利金"改为"开仓价";新增期权双买交易功能,支持跨式策略开平仓及组合盈亏分析
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user