update pay ui
This commit is contained in:
158
app.py
158
app.py
@@ -6285,6 +6285,164 @@ def get_stock_kline(stock_code):
|
||||
return jsonify({'error': f'Unsupported chart type: {chart_type}'}), 400
|
||||
|
||||
|
||||
@app.route('/api/stock/batch-kline', methods=['POST'])
|
||||
def get_batch_kline_data():
|
||||
"""批量获取多只股票的K线/分时数据
|
||||
请求体:{ codes: string[], type: 'timeline'|'daily', event_time?: string }
|
||||
返回:{ success: true, data: { [code]: { data: [], trade_date: '', ... } } }
|
||||
"""
|
||||
try:
|
||||
data = request.json
|
||||
codes = data.get('codes', [])
|
||||
chart_type = data.get('type', 'timeline')
|
||||
event_time = data.get('event_time')
|
||||
|
||||
if not codes:
|
||||
return jsonify({'success': False, 'error': '请提供股票代码列表'}), 400
|
||||
|
||||
if len(codes) > 50:
|
||||
return jsonify({'success': False, 'error': '单次最多查询50只股票'}), 400
|
||||
|
||||
try:
|
||||
event_datetime = datetime.fromisoformat(event_time) if event_time else datetime.now()
|
||||
except ValueError:
|
||||
return jsonify({'success': False, 'error': 'Invalid event_time format'}), 400
|
||||
|
||||
client = get_clickhouse_client()
|
||||
|
||||
# 批量获取股票名称
|
||||
stock_names = {}
|
||||
with engine.connect() as conn:
|
||||
base_codes = list(set([code.split('.')[0] for code in codes]))
|
||||
if base_codes:
|
||||
placeholders = ','.join([f':code{i}' for i in range(len(base_codes))])
|
||||
params = {f'code{i}': code for i, code in enumerate(base_codes)}
|
||||
result = conn.execute(text(
|
||||
f"SELECT SECCODE, SECNAME FROM ea_stocklist WHERE SECCODE IN ({placeholders})"
|
||||
), params).fetchall()
|
||||
for row in result:
|
||||
stock_names[row[0]] = row[1]
|
||||
|
||||
# 确定目标交易日
|
||||
target_date = get_trading_day_near_date(event_datetime.date())
|
||||
is_after_market = event_datetime.time() > dt_time(15, 0)
|
||||
|
||||
if target_date and is_after_market:
|
||||
next_trade_date = get_trading_day_near_date(target_date + timedelta(days=1))
|
||||
if next_trade_date:
|
||||
target_date = next_trade_date
|
||||
|
||||
if not target_date:
|
||||
# 返回空数据
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': {code: {'data': [], 'trade_date': event_datetime.date().strftime('%Y-%m-%d'), 'type': chart_type} for code in codes}
|
||||
})
|
||||
|
||||
start_time = datetime.combine(target_date, dt_time(9, 30))
|
||||
end_time = datetime.combine(target_date, dt_time(15, 0))
|
||||
|
||||
results = {}
|
||||
|
||||
if chart_type == 'timeline':
|
||||
# 批量查询分时数据
|
||||
batch_data = client.execute("""
|
||||
SELECT code, timestamp, close, volume
|
||||
FROM stock_minute
|
||||
WHERE code IN %(codes)s
|
||||
AND timestamp BETWEEN %(start)s AND %(end)s
|
||||
ORDER BY code, timestamp
|
||||
""", {
|
||||
'codes': codes,
|
||||
'start': start_time,
|
||||
'end': end_time
|
||||
})
|
||||
|
||||
# 按股票代码分组
|
||||
stock_data = {}
|
||||
for row in batch_data:
|
||||
code = row[0]
|
||||
if code not in stock_data:
|
||||
stock_data[code] = []
|
||||
stock_data[code].append({
|
||||
'time': row[1].strftime('%H:%M'),
|
||||
'price': float(row[2]),
|
||||
'volume': float(row[3])
|
||||
})
|
||||
|
||||
# 组装结果
|
||||
for code in codes:
|
||||
base_code = code.split('.')[0]
|
||||
stock_name = stock_names.get(base_code, f'股票{base_code}')
|
||||
data_list = stock_data.get(code, [])
|
||||
|
||||
results[code] = {
|
||||
'code': code,
|
||||
'name': stock_name,
|
||||
'data': data_list,
|
||||
'trade_date': target_date.strftime('%Y-%m-%d'),
|
||||
'type': 'timeline'
|
||||
}
|
||||
|
||||
elif chart_type == 'daily':
|
||||
# 批量查询日线数据(从MySQL ea_trade表)
|
||||
with engine.connect() as conn:
|
||||
base_codes = list(set([code.split('.')[0] for code in codes]))
|
||||
if base_codes:
|
||||
placeholders = ','.join([f':code{i}' for i in range(len(base_codes))])
|
||||
params = {f'code{i}': code for i, code in enumerate(base_codes)}
|
||||
params['start_date'] = target_date - timedelta(days=60)
|
||||
params['end_date'] = target_date
|
||||
|
||||
daily_result = conn.execute(text(f"""
|
||||
SELECT SECCODE, TRADEDATE, F003N as open, F005N as high, F006N as low, F007N as close, F004N as volume
|
||||
FROM ea_trade
|
||||
WHERE SECCODE IN ({placeholders})
|
||||
AND TRADEDATE BETWEEN :start_date AND :end_date
|
||||
ORDER BY SECCODE, TRADEDATE
|
||||
"""), params).fetchall()
|
||||
|
||||
# 按股票代码分组
|
||||
stock_data = {}
|
||||
for row in daily_result:
|
||||
code_base = row[0]
|
||||
if code_base not in stock_data:
|
||||
stock_data[code_base] = []
|
||||
stock_data[code_base].append({
|
||||
'date': row[1].strftime('%Y-%m-%d') if hasattr(row[1], 'strftime') else str(row[1]),
|
||||
'open': float(row[2]) if row[2] else 0,
|
||||
'high': float(row[3]) if row[3] else 0,
|
||||
'low': float(row[4]) if row[4] else 0,
|
||||
'close': float(row[5]) if row[5] else 0,
|
||||
'volume': float(row[6]) if row[6] else 0
|
||||
})
|
||||
|
||||
# 组装结果
|
||||
for code in codes:
|
||||
base_code = code.split('.')[0]
|
||||
stock_name = stock_names.get(base_code, f'股票{base_code}')
|
||||
data_list = stock_data.get(base_code, [])
|
||||
|
||||
results[code] = {
|
||||
'code': code,
|
||||
'name': stock_name,
|
||||
'data': data_list,
|
||||
'trade_date': target_date.strftime('%Y-%m-%d'),
|
||||
'type': 'daily'
|
||||
}
|
||||
|
||||
print(f"批量K线查询完成: {len(codes)} 只股票, 类型: {chart_type}, 交易日: {target_date}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': results
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"批量K线查询错误: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/stock/<stock_code>/latest-minute', methods=['GET'])
|
||||
def get_latest_minute_data(stock_code):
|
||||
"""获取最新交易日的分钟频数据"""
|
||||
|
||||
Reference in New Issue
Block a user