feat: Multi-user system with PostgreSQL - WIP temporary save
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Backtest API routes
|
||||
"""
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask import Blueprint, request, jsonify, g
|
||||
from datetime import datetime
|
||||
import traceback
|
||||
import json
|
||||
@@ -11,6 +11,7 @@ import os
|
||||
from app.services.backtest import BacktestService
|
||||
from app.utils.logger import get_logger
|
||||
from app.utils.db import get_db_connection
|
||||
from app.utils.auth import login_required
|
||||
import requests
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -82,12 +83,12 @@ def _normalize_lang(lang: str | None) -> str:
|
||||
return l2 if l2 in supported else "zh-CN"
|
||||
|
||||
|
||||
@backtest_bp.route('/backtest/precision-info', methods=['POST'])
|
||||
@backtest_bp.route('/backtest/precision-info', methods=['GET'])
|
||||
def get_precision_info():
|
||||
"""
|
||||
获取回测精度信息(用于前端提示)
|
||||
|
||||
Params:
|
||||
Params (Query String):
|
||||
market: 市场类型
|
||||
startDate: 开始日期 (YYYY-MM-DD)
|
||||
endDate: 结束日期 (YYYY-MM-DD)
|
||||
@@ -96,13 +97,10 @@ def get_precision_info():
|
||||
精度信息,包含推荐的执行时间框架和预估K线数量
|
||||
"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
return jsonify({'code': 0, 'msg': 'Request body is required'}), 400
|
||||
|
||||
market = data.get('market', 'crypto')
|
||||
start_date_str = data.get('startDate', '')
|
||||
end_date_str = data.get('endDate', '')
|
||||
# Use request.args for GET params
|
||||
market = request.args.get('market', 'crypto')
|
||||
start_date_str = request.args.get('startDate', '')
|
||||
end_date_str = request.args.get('endDate', '')
|
||||
|
||||
if not start_date_str or not end_date_str:
|
||||
return jsonify({'code': 0, 'msg': 'startDate and endDate are required'}), 400
|
||||
@@ -123,9 +121,10 @@ def get_precision_info():
|
||||
|
||||
|
||||
@backtest_bp.route('/backtest', methods=['POST'])
|
||||
@login_required
|
||||
def run_backtest():
|
||||
"""
|
||||
Run indicator backtest
|
||||
Run indicator backtest for the current user.
|
||||
|
||||
Params:
|
||||
indicatorId: Indicator ID (optional)
|
||||
@@ -148,8 +147,8 @@ def run_backtest():
|
||||
'data': None
|
||||
}), 400
|
||||
|
||||
# Extract params
|
||||
user_id = int(data.get('userid') or data.get('userId') or 1)
|
||||
# Extract params - use current user's ID
|
||||
user_id = g.user_id
|
||||
indicator_code = data.get('indicatorCode', '')
|
||||
indicator_id = data.get('indicatorId')
|
||||
symbol = data.get('symbol', '')
|
||||
@@ -267,7 +266,6 @@ def run_backtest():
|
||||
# Persist backtest run for AI optimization / history
|
||||
run_id = None
|
||||
try:
|
||||
now_ts = int(time.time())
|
||||
with get_db_connection() as db:
|
||||
cur = db.cursor()
|
||||
cur.execute(
|
||||
@@ -276,7 +274,7 @@ def run_backtest():
|
||||
(user_id, indicator_id, market, symbol, timeframe, start_date, end_date,
|
||||
initial_capital, commission, slippage, leverage, trade_direction,
|
||||
strategy_config, status, error_message, result_json, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
""",
|
||||
(
|
||||
user_id,
|
||||
@@ -294,8 +292,7 @@ def run_backtest():
|
||||
json.dumps(strategy_config or {}, ensure_ascii=False),
|
||||
'success',
|
||||
'',
|
||||
json.dumps(result or {}, ensure_ascii=False),
|
||||
now_ts
|
||||
json.dumps(result or {}, ensure_ascii=False)
|
||||
)
|
||||
)
|
||||
run_id = cur.lastrowid
|
||||
@@ -327,9 +324,8 @@ def run_backtest():
|
||||
# Best-effort persist failed run (if we have enough context)
|
||||
try:
|
||||
data = data if isinstance(data, dict) else {}
|
||||
user_id = int(data.get('userid') or data.get('userId') or 1)
|
||||
user_id = g.user_id
|
||||
indicator_id = data.get('indicatorId')
|
||||
now_ts = int(time.time())
|
||||
with get_db_connection() as db:
|
||||
cur = db.cursor()
|
||||
cur.execute(
|
||||
@@ -338,7 +334,7 @@ def run_backtest():
|
||||
(user_id, indicator_id, market, symbol, timeframe, start_date, end_date,
|
||||
initial_capital, commission, slippage, leverage, trade_direction,
|
||||
strategy_config, status, error_message, result_json, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
|
||||
""",
|
||||
(
|
||||
user_id,
|
||||
@@ -356,8 +352,7 @@ def run_backtest():
|
||||
json.dumps(data.get('strategyConfig') or {}, ensure_ascii=False),
|
||||
'failed',
|
||||
str(e),
|
||||
'',
|
||||
now_ts
|
||||
''
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
@@ -371,13 +366,13 @@ def run_backtest():
|
||||
}), 500
|
||||
|
||||
|
||||
@backtest_bp.route('/backtest/history', methods=['POST'])
|
||||
@backtest_bp.route('/backtest/history', methods=['GET'])
|
||||
@login_required
|
||||
def get_backtest_history():
|
||||
"""
|
||||
Get backtest run history (saved in SQLite).
|
||||
Get backtest run history for the current user.
|
||||
|
||||
Params:
|
||||
userid: User ID (default 1)
|
||||
Params (Query String):
|
||||
limit: Page size (default 50, max 200)
|
||||
offset: Offset (default 0)
|
||||
indicatorId: Optional indicator id filter
|
||||
@@ -386,17 +381,17 @@ def get_backtest_history():
|
||||
timeframe: Optional timeframe filter
|
||||
"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
user_id = int(data.get('userid') or data.get('userId') or 1)
|
||||
limit = int(data.get('limit') or 50)
|
||||
offset = int(data.get('offset') or 0)
|
||||
# Use current user's ID
|
||||
user_id = g.user_id
|
||||
limit = int(request.args.get('limit') or 50)
|
||||
offset = int(request.args.get('offset') or 0)
|
||||
limit = max(1, min(limit, 200))
|
||||
offset = max(0, offset)
|
||||
|
||||
indicator_id = data.get('indicatorId')
|
||||
symbol = (data.get('symbol') or '').strip()
|
||||
market = (data.get('market') or '').strip()
|
||||
timeframe = (data.get('timeframe') or '').strip()
|
||||
indicator_id = request.args.get('indicatorId')
|
||||
symbol = (request.args.get('symbol') or '').strip()
|
||||
market = (request.args.get('market') or '').strip()
|
||||
timeframe = (request.args.get('timeframe') or '').strip()
|
||||
|
||||
where = ["user_id = ?"]
|
||||
params = [user_id]
|
||||
@@ -449,19 +444,18 @@ def get_backtest_history():
|
||||
return jsonify({'code': 0, 'msg': str(e), 'data': None}), 500
|
||||
|
||||
|
||||
@backtest_bp.route('/backtest/get', methods=['POST'])
|
||||
@backtest_bp.route('/backtest/get', methods=['GET'])
|
||||
@login_required
|
||||
def get_backtest_run():
|
||||
"""
|
||||
Get a backtest run detail by run id (includes result_json).
|
||||
Get a backtest run detail by run id for the current user.
|
||||
|
||||
Params:
|
||||
userid: User ID (default 1)
|
||||
Params (Query String):
|
||||
runId: Backtest run id (required)
|
||||
"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
user_id = int(data.get('userid') or data.get('userId') or 1)
|
||||
run_id = int(data.get('runId') or 0)
|
||||
user_id = g.user_id
|
||||
run_id = int(request.args.get('runId') or 0)
|
||||
if not run_id:
|
||||
return jsonify({'code': 0, 'msg': 'runId is required', 'data': None}), 400
|
||||
|
||||
@@ -716,17 +710,18 @@ def _heuristic_ai_advice(runs: list[dict], lang: str) -> str:
|
||||
|
||||
|
||||
@backtest_bp.route('/backtest/aiAnalyze', methods=['POST'])
|
||||
@login_required
|
||||
def ai_analyze_backtest_runs():
|
||||
"""
|
||||
AI analyze selected backtest runs and provide strategy_config tuning suggestions.
|
||||
AI analyze selected backtest runs and provide strategy_config tuning suggestions
|
||||
for the current user.
|
||||
|
||||
Params:
|
||||
userid: User ID (default 1)
|
||||
runIds: list[int] (required)
|
||||
"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
user_id = int(data.get('userid') or data.get('userId') or 1)
|
||||
user_id = g.user_id
|
||||
lang = _normalize_lang(data.get('lang'))
|
||||
run_ids = data.get('runIds') or []
|
||||
if not isinstance(run_ids, list) or not run_ids:
|
||||
|
||||
Reference in New Issue
Block a user