Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
This commit is contained in:
TIANHE
2025-12-30 19:58:18 +08:00
parent 5df89aa562
commit 58a1133c83
5 changed files with 54 additions and 54 deletions
+5 -5
View File
@@ -159,21 +159,21 @@ def run_backtest():
# 根据周期设置不同的时间限制 # 根据周期设置不同的时间限制
if timeframe == '1m': if timeframe == '1m':
max_days = 30 # 1分钟K线最多1个月 max_days = 30 # 1分钟K线最多1个月
max_range_text = '1个月' max_range_text = '1 month'
elif timeframe == '5m': elif timeframe == '5m':
max_days = 180 # 5分钟K线最多6个月 max_days = 180 # 5分钟K线最多6个月
max_range_text = '6个月' max_range_text = '6 months'
elif timeframe in ['15m', '30m']: elif timeframe in ['15m', '30m']:
max_days = 365 # 15分钟和30分钟K线最多1年 max_days = 365 # 15分钟和30分钟K线最多1年
max_range_text = '1' max_range_text = '1 year'
else: # 1H, 4H, 1D, 1W else: # 1H, 4H, 1D, 1W
max_days = 1095 # 1小时及以上最多3年 max_days = 1095 # 1小时及以上最多3年
max_range_text = '3' max_range_text = '3 years'
if days_diff > max_days: if days_diff > max_days:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'回测时间范围超出限制:{timeframe}周期最多可回测{max_range_text}{max_days}天),当前选择了{days_diff}', 'msg': f'Backtest range exceeds limit: timeframe {timeframe} supports up to {max_range_text} ({max_days} days), but you selected {days_diff} days',
'data': None 'data': None
}), 400 }), 400
+6 -6
View File
@@ -45,7 +45,7 @@ def get_kline():
if not symbol: if not symbol:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少交易标的参数', 'msg': 'Missing symbol parameter',
'data': None 'data': None
}), 400 }), 400
@@ -62,7 +62,7 @@ def get_kline():
if not klines: if not klines:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '未获取到数据', 'msg': 'No data found',
'data': [] 'data': []
}) })
@@ -77,7 +77,7 @@ def get_kline():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取K线数据失败: {str(e)}', 'msg': f'Failed to fetch kline data: {str(e)}',
'data': None 'data': None
}), 500 }), 500
@@ -92,7 +92,7 @@ def get_price():
if not symbol: if not symbol:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少交易标的参数', 'msg': 'Missing symbol parameter',
'data': None 'data': None
}), 400 }), 400
@@ -101,7 +101,7 @@ def get_price():
if not price_data: if not price_data:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '未获取到价格数据', 'msg': 'No price data found',
'data': None 'data': None
}) })
@@ -115,7 +115,7 @@ def get_price():
logger.error(f"Failed to fetch price: {str(e)}") logger.error(f"Failed to fetch price: {str(e)}")
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取价格失败: {str(e)}', 'msg': f'Failed to fetch price: {str(e)}',
'data': None 'data': None
}), 500 }), 500
+8 -8
View File
@@ -375,7 +375,7 @@ def get_watchlist_prices():
if not data: if not data:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '请求参数不能为空', 'msg': 'Request body is required',
'data': [] 'data': []
}), 400 }), 400
@@ -384,7 +384,7 @@ def get_watchlist_prices():
if not watchlist or not isinstance(watchlist, list): if not watchlist or not isinstance(watchlist, list):
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': 'watchlist参数格式错误', 'msg': 'Invalid watchlist format',
'data': [] 'data': []
}), 400 }), 400
@@ -432,7 +432,7 @@ def get_watchlist_prices():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取失败: {str(e)}', 'msg': f'Failed: {str(e)}',
'data': [] 'data': []
}), 500 }), 500
@@ -453,7 +453,7 @@ def get_price():
if not market or not symbol: if not market or not symbol:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少 market symbol 参数', 'msg': 'Missing market or symbol parameter(s)',
'data': None 'data': None
}), 400 }), 400
@@ -469,7 +469,7 @@ def get_price():
logger.error(f"Failed to fetch price: {str(e)}") logger.error(f"Failed to fetch price: {str(e)}")
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取失败: {str(e)}', 'msg': f'Failed: {str(e)}',
'data': None 'data': None
}), 500 }), 500
@@ -499,7 +499,7 @@ def get_stock_name():
if not data: if not data:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '请求参数不能为空', 'msg': 'Request body is required',
'data': None 'data': None
}), 400 }), 400
@@ -509,7 +509,7 @@ def get_stock_name():
if not market or not symbol: if not market or not symbol:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少 market symbol 参数', 'msg': 'Missing market or symbol parameter(s)',
'data': None 'data': None
}), 400 }), 400
@@ -604,6 +604,6 @@ def get_stock_name():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取失败: {str(e)}', 'msg': f'Failed: {str(e)}',
'data': None 'data': None
}), 500 }), 500
+11 -11
View File
@@ -277,7 +277,7 @@ def save_settings():
try: try:
data = request.get_json() data = request.get_json()
if not data: if not data:
return jsonify({'code': 0, 'msg': '无效的请求数据'}) return jsonify({'code': 0, 'msg': 'Invalid request payload'})
# 读取当前配置 # 读取当前配置
current_env = read_env_file() current_env = read_env_file()
@@ -310,18 +310,18 @@ def save_settings():
return jsonify({ return jsonify({
'code': 1, 'code': 1,
'msg': '配置保存成功', 'msg': 'Settings saved successfully',
'data': { 'data': {
'updated_keys': list(updates.keys()), 'updated_keys': list(updates.keys()),
'requires_restart': True # 标记需要重启 'requires_restart': True # 标记需要重启
} }
}) })
else: else:
return jsonify({'code': 0, 'msg': '保存配置失败'}) return jsonify({'code': 0, 'msg': 'Failed to save settings'})
except Exception as e: except Exception as e:
logger.error(f"Failed to save settings: {e}") logger.error(f"Failed to save settings: {e}")
return jsonify({'code': 0, 'msg': f'保存失败: {str(e)}'}) return jsonify({'code': 0, 'msg': f'Save failed: {str(e)}'})
@settings_bp.route('/test-connection', methods=['POST']) @settings_bp.route('/test-connection', methods=['POST'])
@@ -337,27 +337,27 @@ def test_connection():
llm = LLMService() llm = LLMService()
result = llm.test_connection() result = llm.test_connection()
if result: if result:
return jsonify({'code': 1, 'msg': 'OpenRouter连接成功'}) return jsonify({'code': 1, 'msg': 'OpenRouter connection successful'})
else: else:
return jsonify({'code': 0, 'msg': 'OpenRouter连接失败'}) return jsonify({'code': 0, 'msg': 'OpenRouter connection failed'})
elif service == 'finnhub': elif service == 'finnhub':
# 测试 Finnhub 连接 # 测试 Finnhub 连接
import requests import requests
api_key = data.get('api_key') or os.getenv('FINNHUB_API_KEY') api_key = data.get('api_key') or os.getenv('FINNHUB_API_KEY')
if not api_key: if not api_key:
return jsonify({'code': 0, 'msg': 'API Key未配置'}) return jsonify({'code': 0, 'msg': 'API key is not configured'})
resp = requests.get( resp = requests.get(
f'https://finnhub.io/api/v1/quote?symbol=AAPL&token={api_key}', f'https://finnhub.io/api/v1/quote?symbol=AAPL&token={api_key}',
timeout=10 timeout=10
) )
if resp.status_code == 200: if resp.status_code == 200:
return jsonify({'code': 1, 'msg': 'Finnhub连接成功'}) return jsonify({'code': 1, 'msg': 'Finnhub connection successful'})
else: else:
return jsonify({'code': 0, 'msg': f'Finnhub连接失败: {resp.status_code}'}) return jsonify({'code': 0, 'msg': f'Finnhub connection failed: {resp.status_code}'})
return jsonify({'code': 0, 'msg': '未知服务'}) return jsonify({'code': 0, 'msg': 'Unknown service'})
except Exception as e: except Exception as e:
logger.error(f"Connection test failed: {e}") logger.error(f"Connection test failed: {e}")
return jsonify({'code': 0, 'msg': f'测试失败: {str(e)}'}) return jsonify({'code': 0, 'msg': f'Test failed: {str(e)}'})
+24 -24
View File
@@ -48,10 +48,10 @@ def get_strategy_detail():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': None}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': None}), 400
st = get_strategy_service().get_strategy(strategy_id) st = get_strategy_service().get_strategy(strategy_id)
if not st: if not st:
return jsonify({'code': 0, 'msg': '策略不存在', 'data': None}), 404 return jsonify({'code': 0, 'msg': 'Strategy not found', 'data': None}), 404
return jsonify({'code': 1, 'msg': 'success', 'data': st}) return jsonify({'code': 1, 'msg': 'success', 'data': st})
except Exception as e: except Exception as e:
logger.error(f"get_strategy_detail failed: {str(e)}") logger.error(f"get_strategy_detail failed: {str(e)}")
@@ -79,11 +79,11 @@ def update_strategy():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': None}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': None}), 400
payload = request.get_json() or {} payload = request.get_json() or {}
ok = get_strategy_service().update_strategy(strategy_id, payload) ok = get_strategy_service().update_strategy(strategy_id, payload)
if not ok: if not ok:
return jsonify({'code': 0, 'msg': '策略不存在', 'data': None}), 404 return jsonify({'code': 0, 'msg': 'Strategy not found', 'data': None}), 404
return jsonify({'code': 1, 'msg': 'success', 'data': None}) return jsonify({'code': 1, 'msg': 'success', 'data': None})
except Exception as e: except Exception as e:
logger.error(f"update_strategy failed: {str(e)}") logger.error(f"update_strategy failed: {str(e)}")
@@ -96,7 +96,7 @@ def delete_strategy():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': None}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': None}), 400
ok = get_strategy_service().delete_strategy(strategy_id) ok = get_strategy_service().delete_strategy(strategy_id)
return jsonify({'code': 1 if ok else 0, 'msg': 'success' if ok else 'failed', 'data': None}) return jsonify({'code': 1 if ok else 0, 'msg': 'success' if ok else 'failed', 'data': None})
except Exception as e: except Exception as e:
@@ -111,7 +111,7 @@ def get_trades():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': {'trades': [], 'items': []}}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': {'trades': [], 'items': []}}), 400
with get_db_connection() as db: with get_db_connection() as db:
cur = db.cursor() cur = db.cursor()
cur.execute( cur.execute(
@@ -139,7 +139,7 @@ def get_positions():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': {'positions': [], 'items': []}}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': {'positions': [], 'items': []}}), 400
with get_db_connection() as db: with get_db_connection() as db:
cur = db.cursor() cur = db.cursor()
cur.execute( cur.execute(
@@ -240,7 +240,7 @@ def get_equity_curve():
try: try:
strategy_id = request.args.get('id', type=int) strategy_id = request.args.get('id', type=int)
if not strategy_id: if not strategy_id:
return jsonify({'code': 0, 'msg': '缺少策略ID参数', 'data': []}), 400 return jsonify({'code': 0, 'msg': 'Missing strategy id parameter', 'data': []}), 400
st = get_strategy_service().get_strategy(strategy_id) or {} st = get_strategy_service().get_strategy(strategy_id) or {}
initial = float(st.get('initial_capital') or (st.get('trading_config') or {}).get('initial_capital') or 0) initial = float(st.get('initial_capital') or (st.get('trading_config') or {}).get('initial_capital') or 0)
@@ -295,7 +295,7 @@ def stop_strategy():
if not strategy_id: if not strategy_id:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少策略ID参数', 'msg': 'Missing strategy id parameter',
'data': None 'data': None
}), 400 }), 400
@@ -304,7 +304,7 @@ def stop_strategy():
# Local backend: AI strategy executor was removed. Only indicator strategies are supported. # Local backend: AI strategy executor was removed. Only indicator strategies are supported.
if strategy_type == 'PromptBasedStrategy': if strategy_type == 'PromptBasedStrategy':
return jsonify({'code': 0, 'msg': 'AI策略已移除,本地版不支持启动/停止 AI 策略', 'data': None}), 400 return jsonify({'code': 0, 'msg': 'AI strategy has been removed; local edition does not support starting/stopping AI strategies', 'data': None}), 400
# 指标策略 # 指标策略
get_trading_executor().stop_strategy(strategy_id) get_trading_executor().stop_strategy(strategy_id)
@@ -314,7 +314,7 @@ def stop_strategy():
return jsonify({ return jsonify({
'code': 1, 'code': 1,
'msg': '停止成功', 'msg': 'Stopped successfully',
'data': None 'data': None
}) })
@@ -323,7 +323,7 @@ def stop_strategy():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'停止策略失败: {str(e)}', 'msg': f'Failed to stop strategy: {str(e)}',
'data': None 'data': None
}), 500 }), 500
@@ -342,7 +342,7 @@ def start_strategy():
if not strategy_id: if not strategy_id:
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '缺少策略ID参数', 'msg': 'Missing strategy id parameter',
'data': None 'data': None
}), 400 }), 400
@@ -354,7 +354,7 @@ def start_strategy():
# Local backend: AI strategy executor was removed. Only indicator strategies are supported. # Local backend: AI strategy executor was removed. Only indicator strategies are supported.
if strategy_type == 'PromptBasedStrategy': if strategy_type == 'PromptBasedStrategy':
return jsonify({'code': 0, 'msg': 'AI策略已移除,本地版不支持启动 AI 策略', 'data': None}), 400 return jsonify({'code': 0, 'msg': 'AI strategy has been removed; local edition does not support starting AI strategies', 'data': None}), 400
# 指标策略 # 指标策略
success = get_trading_executor().start_strategy(strategy_id) success = get_trading_executor().start_strategy(strategy_id)
@@ -364,13 +364,13 @@ def start_strategy():
get_strategy_service().update_strategy_status(strategy_id, 'stopped') get_strategy_service().update_strategy_status(strategy_id, 'stopped')
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': '启动策略执行器失败', 'msg': 'Failed to start strategy executor',
'data': None 'data': None
}), 500 }), 500
return jsonify({ return jsonify({
'code': 1, 'code': 1,
'msg': '启动成功', 'msg': 'Started successfully',
'data': None 'data': None
}) })
@@ -379,7 +379,7 @@ def start_strategy():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'启动策略失败: {str(e)}', 'msg': f'Failed to start strategy: {str(e)}',
'data': None 'data': None
}), 500 }), 500
@@ -413,11 +413,11 @@ def test_connection():
if not isinstance(exchange_config, dict): if not isinstance(exchange_config, dict):
logger.error(f"Invalid exchange_config type: {type(exchange_config)}, data: {str(exchange_config)[:200]}") logger.error(f"Invalid exchange_config type: {type(exchange_config)}, data: {str(exchange_config)[:200]}")
# Frontend expects HTTP 200 with {code:0} for business failures. # Frontend expects HTTP 200 with {code:0} for business failures.
return jsonify({'code': 0, 'msg': '交易所配置格式错误,请检查数据格式', 'data': None}) return jsonify({'code': 0, 'msg': 'Invalid exchange config format; please check your payload', 'data': None})
# 验证必要字段 # 验证必要字段
if not exchange_config.get('exchange_id'): if not exchange_config.get('exchange_id'):
return jsonify({'code': 0, 'msg': '请选择交易所', 'data': None}) return jsonify({'code': 0, 'msg': 'Please select an exchange', 'data': None})
api_key = exchange_config.get('api_key', '') api_key = exchange_config.get('api_key', '')
secret_key = exchange_config.get('secret_key', '') secret_key = exchange_config.get('secret_key', '')
@@ -434,21 +434,21 @@ def test_connection():
logger.warning("Secret key contains leading/trailing whitespace") logger.warning("Secret key contains leading/trailing whitespace")
if not api_key or not secret_key: if not api_key or not secret_key:
return jsonify({'code': 0, 'msg': '请填写API密钥和Secret密钥', 'data': None}) return jsonify({'code': 0, 'msg': 'Please provide API key and secret key', 'data': None})
result = get_strategy_service().test_exchange_connection(exchange_config) result = get_strategy_service().test_exchange_connection(exchange_config)
if result['success']: if result['success']:
return jsonify({'code': 1, 'msg': result.get('message') or '连接成功', 'data': result.get('data')}) return jsonify({'code': 1, 'msg': result.get('message') or 'Connection successful', 'data': result.get('data')})
# Always return HTTP 200 for business-level failures. # Always return HTTP 200 for business-level failures.
return jsonify({'code': 0, 'msg': result.get('message') or '连接失败', 'data': result.get('data')}) return jsonify({'code': 0, 'msg': result.get('message') or 'Connection failed', 'data': result.get('data')})
except Exception as e: except Exception as e:
logger.error(f"Connection test failed: {str(e)}") logger.error(f"Connection test failed: {str(e)}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'测试连接失败: {str(e)}', 'msg': f'Connection test failed: {str(e)}',
'data': None 'data': None
}), 500 }), 500
@@ -489,7 +489,7 @@ def get_symbols():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return jsonify({ return jsonify({
'code': 0, 'code': 0,
'msg': f'获取交易对失败: {str(e)}', 'msg': f'Failed to fetch symbols: {str(e)}',
'data': { 'data': {
'symbols': [] 'symbols': []
} }