Compare commits

...

3 Commits

Author SHA1 Message Date
fish 71ef310648 更新数据库文件
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-26 11:38:34 +08:00
fish e3f288083c 对冲管理新增品种筛选,合约下拉去掉品种前缀
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-26 11:37:40 +08:00
fish d44e93dd4f 交易记录新建开仓改为先选品种再选合约
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-26 11:34:36 +08:00
5 changed files with 75 additions and 12 deletions
+12 -1
View File
@@ -3,7 +3,7 @@ from fastapi import APIRouter, Depends, Form, Request
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.database import get_db from app.database import get_db
from app.models import Round, Position, Contract from app.models import Round, Position, Contract, Product
router = APIRouter(prefix="/positions", tags=["positions"]) router = APIRouter(prefix="/positions", tags=["positions"])
@@ -18,6 +18,16 @@ def get_active_contracts(db: Session) -> list[str]:
return [c[0] for c in contracts] return [c[0] for c in contracts]
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
@router.get("/", response_class=HTMLResponse) @router.get("/", response_class=HTMLResponse)
def positions_page(request: Request, db: Session = Depends(get_db)): def positions_page(request: Request, db: Session = Depends(get_db)):
active_rounds = ( active_rounds = (
@@ -33,6 +43,7 @@ def positions_page(request: Request, db: Session = Depends(get_db)):
request=request, request=request,
active_nav="positions", active_nav="positions",
contracts=get_active_contracts(db), contracts=get_active_contracts(db),
product_contracts=get_product_contracts(db),
active_rounds=active_rounds, active_rounds=active_rounds,
) )
) )
+12
View File
@@ -20,6 +20,17 @@ def get_active_contracts(db: Session) -> list[str]:
return [c[0] for c in contracts] return [c[0] for c in contracts]
def get_product_contracts(db: Session) -> dict:
"""Return {product_code: [contract_codes]} for active contracts."""
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: def today_str() -> str:
return date.today().isoformat() return date.today().isoformat()
@@ -41,6 +52,7 @@ def trades_page(request: Request, db: Session = Depends(get_db)):
request=request, request=request,
active_nav="trades", active_nav="trades",
contracts=get_active_contracts(db), contracts=get_active_contracts(db),
product_contracts=get_product_contracts(db),
directions=DIRECTIONS, directions=DIRECTIONS,
open_trades=open_trades, open_trades=open_trades,
closed_trades=closed_trades, closed_trades=closed_trades,
+27 -6
View File
@@ -16,15 +16,21 @@
<div class="form-card" style="margin-bottom:28px;"> <div class="form-card" style="margin-bottom:28px;">
<form method="post" action="/positions/round"> <form method="post" action="/positions/round">
<div style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;"> <div style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;">
<div class="form-group" style="margin-bottom:0;flex:1;min-width:140px;"> <div class="form-group" style="margin-bottom:0;flex:1;min-width:100px;">
<label>合约</label> <label>品种</label>
<select name="contract_code" required> <select id="productSelect" required onchange="filterContracts()">
<option value="">-- 选择合约 --</option> <option value="">--</option>
{% for c in contracts %} {% for pcode in product_contracts %}
<option value="{{ c }}">{{ c }}</option> <option value="{{ pcode }}">{{ pcode }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom:0;flex:1;min-width:120px;">
<label>合约</label>
<select name="contract_code" id="contractSelect" required disabled>
<option value="">-- 先选品种 --</option>
</select>
</div>
<div class="form-group" style="margin-bottom:0;flex:1;min-width:100px;"> <div class="form-group" style="margin-bottom:0;flex:1;min-width:100px;">
<label>每日手数 N</label> <label>每日手数 N</label>
<input type="number" name="daily_hands" value="1" min="1" max="10" required> <input type="number" name="daily_hands" value="1" min="1" max="10" required>
@@ -161,4 +167,19 @@
</div> </div>
{% endfor %} {% endfor %}
<script>
var productContracts = {{ product_contracts | tojson }};
function filterContracts() {
var prod = document.getElementById('productSelect').value;
var sel = document.getElementById('contractSelect');
sel.innerHTML = '<option value="">-- 选择合约 --</option>';
sel.disabled = !prod;
if (prod && productContracts[prod]) {
productContracts[prod].forEach(function(c) {
var display = c.startsWith(prod) ? c.substring(prod.length) : c;
sel.innerHTML += '<option value="' + c + '">' + display + '</option>';
});
}
}
</script>
{% endblock %} {% endblock %}
+24 -5
View File
@@ -34,13 +34,19 @@
<div class="form-card" style="margin-bottom:28px;max-width:100%;"> <div class="form-card" style="margin-bottom:28px;max-width:100%;">
<form method="post" action="/trades/open"> <form method="post" action="/trades/open">
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;"> <div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;">
<div class="form-group" style="margin-bottom:0;flex:0 0 auto;min-width:100px;">
<label>品种</label>
<select id="productSelect" required onchange="filterContracts()">
<option value="">--</option>
{% for pcode in product_contracts %}
<option value="{{ pcode }}">{{ pcode }}</option>
{% endfor %}
</select>
</div>
<div class="form-group" style="margin-bottom:0;flex:0 0 auto;min-width:120px;"> <div class="form-group" style="margin-bottom:0;flex:0 0 auto;min-width:120px;">
<label>合约</label> <label>合约</label>
<select name="contract_code" required> <select name="contract_code" id="contractSelect" required disabled>
<option value="">--</option> <option value="">-- 先选品种 --</option>
{% for c in contracts %}
<option value="{{ c }}">{{ c }}</option>
{% endfor %}
</select> </select>
</div> </div>
<div class="form-group" style="margin-bottom:0;flex:0 0 auto;min-width:70px;"> <div class="form-group" style="margin-bottom:0;flex:0 0 auto;min-width:70px;">
@@ -197,6 +203,19 @@
{% if view != 'closed' %} {% if view != 'closed' %}
<script> <script>
var productContracts = {{ product_contracts | tojson }};
function filterContracts() {
var prod = document.getElementById('productSelect').value;
var sel = document.getElementById('contractSelect');
sel.innerHTML = '<option value="">-- 选择合约 --</option>';
sel.disabled = !prod;
if (prod && productContracts[prod]) {
productContracts[prod].forEach(function(c) {
var display = c.startsWith(prod) ? c.substring(prod.length) : c;
sel.innerHTML += '<option value="' + c + '">' + display + '</option>';
});
}
}
function showCloseForm(tradeId) { function showCloseForm(tradeId) {
document.getElementById('closeForm').action = '/trades/' + tradeId + '/close'; document.getElementById('closeForm').action = '/trades/' + tradeId + '/close';
document.getElementById('closeFormOverlay').style.display = 'block'; document.getElementById('closeFormOverlay').style.display = 'block';
BIN
View File
Binary file not shown.