feat(i18n): add missing translations for trading-assistant modal

- Add step2Params and step3Signal translations
- Add execution mode related translations (signal/live)
- Add notification channel translations (browser/email/phone/telegram/discord/webhook)
- Add live trading config translations (savedCredential, credentialName, etc.)
- Add batch operation message translations (batchCreateSuccess, batchStart/Stop/Delete)
- Add placeholders for email, phone, telegram, discord, webhook inputs
- Add validation messages for email and notify channel
- Add strategy group translations (startAll, stopAll, deleteAll, symbolCount)
- Support both zh-CN (Simplified Chinese) and zh-TW (Traditional Chinese)
This commit is contained in:
TIANHE
2026-01-11 22:15:54 +08:00
parent 74138b4cb2
commit e7cb9c6493
8 changed files with 972 additions and 85 deletions
+153 -1
View File
@@ -2,6 +2,7 @@ import os
import time
import json
import threading
import uuid
from typing import List, Dict, Any, Optional
from datetime import datetime
@@ -534,6 +535,10 @@ class StrategyService:
trading_config = payload.get('trading_config') or {}
exchange_config = payload.get('exchange_config') or {}
# 策略组字段
strategy_group_id = payload.get('strategy_group_id') or ''
group_base_name = payload.get('group_base_name') or ''
# Denormalized fields for quick list rendering
symbol = (trading_config or {}).get('symbol')
timeframe = (trading_config or {}).get('timeframe')
@@ -549,8 +554,9 @@ class StrategyService:
(strategy_name, strategy_type, market_category, execution_mode, notification_config,
status, symbol, timeframe, initial_capital, leverage, market_type,
exchange_config, indicator_config, trading_config, ai_model_config, decide_interval,
strategy_group_id, group_base_name,
created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
name,
@@ -569,6 +575,8 @@ class StrategyService:
self._dump_json_or_encrypt(trading_config, encrypt=False),
self._dump_json_or_encrypt(payload.get('ai_model_config') or {}, encrypt=False),
int(payload.get('decide_interval') or 300),
strategy_group_id,
group_base_name,
now,
now
)
@@ -578,6 +586,150 @@ class StrategyService:
cur.close()
return int(new_id)
def batch_create_strategies(self, payload: Dict[str, Any]) -> Dict[str, Any]:
"""
批量创建策略(多币种)
Args:
payload: 包含 symbols(数组)和其他策略配置
Returns:
{
'success': True/False,
'strategy_group_id': '...',
'created_ids': [1, 2, 3],
'failed_symbols': []
}
"""
symbols = payload.get('symbols') or []
if not symbols or not isinstance(symbols, list):
raise ValueError("symbols array is required")
base_name = (payload.get('strategy_name') or '').strip()
if not base_name:
raise ValueError("strategy_name is required")
# 生成策略组ID
strategy_group_id = str(uuid.uuid4())[:8]
created_ids = []
failed_symbols = []
for symbol in symbols:
try:
# 为每个币种创建单独的策略
single_payload = dict(payload)
# 解析 symbol(可能是 "Market:SYMBOL" 格式)
if isinstance(symbol, str) and ':' in symbol:
parts = symbol.split(':', 1)
market_category = parts[0]
symbol_name = parts[1]
else:
market_category = payload.get('market_category') or 'Crypto'
symbol_name = symbol
# 策略名称加币种后缀
single_payload['strategy_name'] = f"{base_name}-{symbol_name}"
single_payload['strategy_group_id'] = strategy_group_id
single_payload['group_base_name'] = base_name
single_payload['market_category'] = market_category
# 更新 trading_config 中的 symbol
trading_config = dict(single_payload.get('trading_config') or {})
trading_config['symbol'] = symbol_name
single_payload['trading_config'] = trading_config
new_id = self.create_strategy(single_payload)
created_ids.append(new_id)
except Exception as e:
logger.error(f"Failed to create strategy for symbol {symbol}: {e}")
failed_symbols.append({'symbol': symbol, 'error': str(e)})
return {
'success': len(created_ids) > 0,
'strategy_group_id': strategy_group_id,
'group_base_name': base_name,
'created_ids': created_ids,
'failed_symbols': failed_symbols,
'total_created': len(created_ids),
'total_failed': len(failed_symbols)
}
def batch_start_strategies(self, strategy_ids: List[int]) -> Dict[str, Any]:
"""批量启动策略"""
success_ids = []
failed_ids = []
for sid in strategy_ids:
try:
self.update_strategy_status(sid, 'running')
success_ids.append(sid)
except Exception as e:
logger.error(f"Failed to start strategy {sid}: {e}")
failed_ids.append({'id': sid, 'error': str(e)})
return {
'success': len(success_ids) > 0,
'success_ids': success_ids,
'failed_ids': failed_ids
}
def batch_stop_strategies(self, strategy_ids: List[int]) -> Dict[str, Any]:
"""批量停止策略"""
success_ids = []
failed_ids = []
for sid in strategy_ids:
try:
self.update_strategy_status(sid, 'stopped')
success_ids.append(sid)
except Exception as e:
logger.error(f"Failed to stop strategy {sid}: {e}")
failed_ids.append({'id': sid, 'error': str(e)})
return {
'success': len(success_ids) > 0,
'success_ids': success_ids,
'failed_ids': failed_ids
}
def batch_delete_strategies(self, strategy_ids: List[int]) -> Dict[str, Any]:
"""批量删除策略"""
success_ids = []
failed_ids = []
for sid in strategy_ids:
try:
self.delete_strategy(sid)
success_ids.append(sid)
except Exception as e:
logger.error(f"Failed to delete strategy {sid}: {e}")
failed_ids.append({'id': sid, 'error': str(e)})
return {
'success': len(success_ids) > 0,
'success_ids': success_ids,
'failed_ids': failed_ids
}
def get_strategies_by_group(self, strategy_group_id: str) -> List[Dict[str, Any]]:
"""获取策略组内的所有策略"""
try:
with get_db_connection() as db:
cur = db.cursor()
cur.execute(
"SELECT id FROM qd_strategies_trading WHERE strategy_group_id = ?",
(strategy_group_id,)
)
rows = cur.fetchall() or []
cur.close()
return [row['id'] for row in rows]
except Exception as e:
logger.error(f"get_strategies_by_group failed: {e}")
return []
def update_strategy(self, strategy_id: int, payload: Dict[str, Any]) -> bool:
now = int(time.time())
existing = self.get_strategy(strategy_id)