feat: Add cross-sectional strategy support

- Add cross-sectional strategy type (single vs cross-sectional)
- Support multi-symbol portfolio management with automatic ranking
- Add portfolio size, long ratio, and rebalance frequency configuration
- Implement parallel order execution for cross-sectional strategies
- Add frontend UI for strategy type selection and configuration
- Add i18n support (Chinese and English) for cross-sectional features
- Fix decimal precision issues in exchange order quantities
- Add last_rebalance_at field to database schema
- Add comprehensive documentation and examples

Database migration required: Add last_rebalance_at column to qd_strategies_trading table
This commit is contained in:
TIANHE
2026-02-10 15:18:45 +08:00
parent a89cc9bee9
commit a51184497d
19 changed files with 1517 additions and 36 deletions
@@ -559,6 +559,21 @@ class StrategyService:
initial_capital = (trading_config or {}).get('initial_capital') or payload.get('initial_capital') or 1000
leverage = (trading_config or {}).get('leverage') or 1
market_type = (trading_config or {}).get('market_type') or 'swap'
# Cross-sectional strategy fields (store in trading_config to avoid DB schema changes)
cs_strategy_type = payload.get('cs_strategy_type') or trading_config.get('cs_strategy_type') or 'single'
symbol_list = payload.get('symbol_list') or trading_config.get('symbol_list') or []
portfolio_size = payload.get('portfolio_size') or trading_config.get('portfolio_size') or 10
long_ratio = float(payload.get('long_ratio') or trading_config.get('long_ratio') or 0.5)
rebalance_frequency = payload.get('rebalance_frequency') or trading_config.get('rebalance_frequency') or 'daily'
# Store cross-sectional config in trading_config
if cs_strategy_type == 'cross_sectional':
trading_config['cs_strategy_type'] = cs_strategy_type
trading_config['symbol_list'] = symbol_list
trading_config['portfolio_size'] = portfolio_size
trading_config['long_ratio'] = long_ratio
trading_config['rebalance_frequency'] = rebalance_frequency
with get_db_connection() as db:
cur = db.cursor()
@@ -764,6 +779,18 @@ class StrategyService:
trading_config = payload.get('trading_config') if payload.get('trading_config') is not None else (existing.get('trading_config') or {})
exchange_config = payload.get('exchange_config') if payload.get('exchange_config') is not None else (existing.get('exchange_config') or {})
ai_model_config = payload.get('ai_model_config') if payload.get('ai_model_config') is not None else (existing.get('ai_model_config') or {})
# Handle cross-sectional strategy config updates
if payload.get('cs_strategy_type') is not None:
trading_config['cs_strategy_type'] = payload.get('cs_strategy_type')
if payload.get('symbol_list') is not None:
trading_config['symbol_list'] = payload.get('symbol_list')
if payload.get('portfolio_size') is not None:
trading_config['portfolio_size'] = payload.get('portfolio_size')
if payload.get('long_ratio') is not None:
trading_config['long_ratio'] = payload.get('long_ratio')
if payload.get('rebalance_frequency') is not None:
trading_config['rebalance_frequency'] = payload.get('rebalance_frequency')
symbol = (trading_config or {}).get('symbol')
timeframe = (trading_config or {}).get('timeframe')