From ac03d9e67b647a206eec6618fd2ee1db2e6240be Mon Sep 17 00:00:00 2001 From: gavindiaz Date: Sat, 11 Jul 2026 20:13:35 +0000 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=E3=80=8C/=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md | 223 +++++++++++++++++++++++++++ CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md | 223 +++++++++++++++++++++++++++ EXTENSION_GUIDE.md | 162 +++++++++++++++++++ cross_sectional_momentum_rsi.py | 70 +++++++++ dual_ma_with_params.py | 89 +++++++++++ 5 files changed, 767 insertions(+) create mode 100644 CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md create mode 100644 CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md create mode 100644 EXTENSION_GUIDE.md create mode 100644 cross_sectional_momentum_rsi.py create mode 100644 dual_ma_with_params.py diff --git a/CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md b/CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md new file mode 100644 index 0000000..31795f0 --- /dev/null +++ b/CROSS_SECTIONAL_STRATEGY_GUIDE_CN.md @@ -0,0 +1,223 @@ +# 截面策略使用指南 + +## 概述 + +截面策略(Cross-Sectional Strategy)是一种同时交易多个标的的策略类型。它根据某些因子对所有标的进行评分和排序,然后做多排名靠前的标的,做空排名靠后的标的。 + +## 功能特点 + +1. **多标的支持**:可以同时交易多个标的(股票、币种等) +2. **自动排序**:根据指标计算的评分自动排序标的 +3. **组合管理**:自动管理持仓组合,保持做多/做空比例 +4. **定期调仓**:支持每日/每周/每月调仓频率 +5. **批量执行**:并行执行多个标的的交易,提高效率 + +## 配置说明 + +### 策略配置参数 + +在 **交易助手 → 创建策略** 中选择「截面策略」,自选标的池并配置组合参数;也可在 API/数据库的 `trading_config` 中直接写入以下字段: + +```json +{ + "cs_strategy_type": "cross_sectional", // 策略类型:'single' 或 'cross_sectional' + "symbol_list": [ // 标的列表 + "Crypto:BTC/USDT", + "Crypto:ETH/USDT", + "Crypto:BNB/USDT" + ], + "portfolio_size": 10, // 持仓组合大小(做多+做空的总数) + "long_ratio": 0.5, // 做多比例(0-1之间,0.5表示50%做多,50%做空) + "rebalance_frequency": "daily" // 调仓频率:'daily' | 'weekly' | 'monthly' +} +``` + +### 参数说明 + +- **cs_strategy_type**: + - `'single'`: 单标的策略(默认,原有功能) + - `'cross_sectional'`: 截面策略 + +- **symbol_list**: + - 标的列表,格式为 `["Market:SYMBOL", ...]` + - 例如:`["Crypto:BTC/USDT", "Crypto:ETH/USDT"]` + +- **portfolio_size**: + - 持仓组合大小,即同时持有的标的数量 + - 例如:10 表示同时持有10个标的 + +- **long_ratio**: + - 做多比例,0-1之间的浮点数 + - 例如:0.5 表示50%做多,50%做空 + - 例如:1.0 表示100%做多(不做空) + +- **rebalance_frequency**: + - 调仓频率 + - `'daily'`: 每日调仓 + - `'weekly'`: 每周调仓 + - `'monthly'`: 每月调仓 + +## 指标代码编写 + +截面策略的指标代码需要返回所有标的的评分和排序。 + +### 指标代码模板 + +```python +# 截面策略指标模板 +# 输入:data = {symbol1: df1, symbol2: df2, ...} +# 输出:scores = {symbol1: score1, symbol2: score2, ...} +# rankings = [symbol1, symbol2, ...] # 可选,如果不提供会根据scores自动排序 + +scores = {} +for symbol, df in data.items(): + # 计算每个标的的因子值 + # 例如:动量因子 + momentum = (df['close'].iloc[-1] / df['close'].iloc[-20] - 1) * 100 + + # 例如:RSI指标 + def calculate_rsi(prices, period=14): + delta = prices.diff() + gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + return rsi.iloc[-1] + + rsi = calculate_rsi(df['close'], 14) + + # 综合评分(可以根据需要调整权重) + score = momentum * 0.6 + (100 - rsi) * 0.4 + scores[symbol] = score + +# 可选:手动指定排序(如果不提供,系统会根据scores自动排序) +# rankings = sorted(scores.keys(), key=lambda x: scores[x], reverse=True) +``` + +### 指标代码环境变量 + +在指标代码执行时,可以使用以下变量: + +- `symbols`: 标的列表 `['Crypto:BTC/USDT', 'Crypto:ETH/USDT', ...]` +- `data`: 所有标的的K线数据 `{symbol: df, ...}` +- `scores`: 用于存储评分的字典(需要在代码中填充) +- `rankings`: 用于存储排序的列表(可选,如果不提供会根据scores自动排序) +- `np`: numpy +- `pd`: pandas +- `trading_config`: 交易配置 +- `config`: 交易配置(别名) + +### 输出要求 + +指标代码需要填充 `scores` 字典: + +```python +scores[symbol] = score_value # score_value 可以是任意数值 +``` + +可选:填充 `rankings` 列表(如果不提供,系统会根据scores自动排序): + +```python +rankings = [symbol1, symbol2, ...] # 按评分从高到低排序 +``` + +## 信号生成逻辑 + +系统会根据以下逻辑自动生成交易信号: + +1. **排序标的**:根据指标计算的评分对所有标的进行排序 +2. **选择持仓**: + - 排名靠前的 `portfolio_size * long_ratio` 个标的 → 做多 + - 排名靠后的 `portfolio_size * (1 - long_ratio)` 个标的 → 做空 +3. **生成信号**: + - 新增标的:如果标的不在当前持仓中,生成开仓信号 + - 移除标的:如果标的不在目标持仓中,生成平仓信号 + - 方向变更:如果标的需要从多转空或从空转多,先生成平仓信号,再生成开仓信号 + +## 使用示例 + +### 1. 创建截面策略 + +通过API创建策略时,在请求体中包含: + +```json +{ + "strategy_name": "动量截面策略", + "trading_config": { + "cs_strategy_type": "cross_sectional", + "symbol_list": [ + "Crypto:BTC/USDT", + "Crypto:ETH/USDT", + "Crypto:BNB/USDT", + "Crypto:ADA/USDT", + "Crypto:SOL/USDT" + ], + "portfolio_size": 5, + "long_ratio": 0.6, + "rebalance_frequency": "daily", + "timeframe": "1H", + "initial_capital": 10000, + "leverage": 1, + "market_type": "swap" + }, + "indicator_config": { + "indicator_id": 123, + "indicator_code": "..." + } +} +``` + +### 2. 指标代码示例 + +```python +# 动量+RSI综合评分 +scores = {} +for symbol, df in data.items(): + # 20周期动量 + momentum = (df['close'].iloc[-1] / df['close'].iloc[-20] - 1) * 100 + + # RSI + delta = df['close'].diff() + gain = (delta.where(delta > 0, 0)).rolling(window=14).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean() + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + rsi_value = rsi.iloc[-1] + + # 综合评分 + score = momentum * 0.7 + (100 - rsi_value) * 0.3 + scores[symbol] = score +``` + +## 注意事项 + +1. **数据获取**:系统会为每个标的获取K线数据,如果某个标的数据获取失败,会跳过该标的 +2. **调仓频率**:系统会根据 `rebalance_frequency` 设置检查是否需要调仓,未到调仓时间时不会执行交易 +3. **批量执行**:所有交易信号会并行执行,最多同时执行10个交易 +4. **持仓管理**:系统会自动管理持仓,确保持仓组合符合配置要求 +5. **兼容性**:截面策略功能不影响现有的单标的策略,两者可以共存 + +## 数据库迁移 + +如果需要使用数据库字段存储截面策略配置(可选),可以运行迁移脚本: + +```sql +-- 运行 migrations/add_cross_sectional_strategy.sql +``` + +如果不运行迁移脚本,截面策略配置会存储在 `trading_config` JSON字段中,功能完全正常。 + +## 故障排查 + +1. **策略不执行**: + - 检查 `cs_strategy_type` 是否为 `'cross_sectional'` + - 检查 `symbol_list` 是否不为空 + - 检查调仓频率是否已到时间 + +2. **指标执行失败**: + - 检查指标代码是否正确填充 `scores` 字典 + - 检查所有标的的数据是否都能正常获取 + +3. **信号不生成**: + - 检查 `portfolio_size` 是否小于等于 `symbol_list` 的长度 + - 检查评分是否有效 diff --git a/CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md b/CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md new file mode 100644 index 0000000..e9c8874 --- /dev/null +++ b/CROSS_SECTIONAL_STRATEGY_GUIDE_EN.md @@ -0,0 +1,223 @@ +# Cross-Sectional Strategy Guide + +## Overview + +Cross-Sectional Strategy is a strategy type that trades multiple symbols simultaneously. It scores and ranks all symbols based on certain factors, then goes long on top-ranked symbols and short on bottom-ranked symbols. + +## Features + +1. **Multi-Symbol Support**: Can trade multiple symbols (stocks, cryptocurrencies, etc.) simultaneously +2. **Automatic Ranking**: Automatically ranks symbols based on indicator-calculated scores +3. **Portfolio Management**: Automatically manages portfolio positions, maintaining long/short ratios +4. **Periodic Rebalancing**: Supports daily/weekly/monthly rebalancing frequencies +5. **Batch Execution**: Executes trades for multiple symbols in parallel for improved efficiency + +## Configuration + +### Strategy Configuration Parameters + +When creating or editing a strategy, add the following parameters to `trading_config`: + +```json +{ + "cs_strategy_type": "cross_sectional", // Strategy type: 'single' or 'cross_sectional' + "symbol_list": [ // Symbol list + "Crypto:BTC/USDT", + "Crypto:ETH/USDT", + "Crypto:BNB/USDT" + ], + "portfolio_size": 10, // Portfolio size (total of long + short positions) + "long_ratio": 0.5, // Long ratio (0-1, 0.5 means 50% long, 50% short) + "rebalance_frequency": "daily" // Rebalancing frequency: 'daily' | 'weekly' | 'monthly' +} +``` + +### Parameter Description + +- **cs_strategy_type**: + - `'single'`: Single-symbol strategy (default, original functionality) + - `'cross_sectional'`: Cross-sectional strategy + +- **symbol_list**: + - List of symbols, format: `["Market:SYMBOL", ...]` + - Example: `["Crypto:BTC/USDT", "Crypto:ETH/USDT"]` + +- **portfolio_size**: + - Portfolio size, i.e., the number of symbols to hold simultaneously + - Example: 10 means holding 10 symbols at the same time + +- **long_ratio**: + - Long ratio, a float between 0 and 1 + - Example: 0.5 means 50% long, 50% short + - Example: 1.0 means 100% long (no short positions) + +- **rebalance_frequency**: + - Rebalancing frequency + - `'daily'`: Daily rebalancing + - `'weekly'`: Weekly rebalancing + - `'monthly'`: Monthly rebalancing + +## Indicator Code Writing + +Cross-sectional strategy indicator code needs to return scores and rankings for all symbols. + +### Indicator Code Template + +```python +# Cross-sectional strategy indicator template +# Input: data = {symbol1: df1, symbol2: df2, ...} +# Output: scores = {symbol1: score1, symbol2: score2, ...} +# rankings = [symbol1, symbol2, ...] # Optional, auto-sorted by scores if not provided + +scores = {} +for symbol, df in data.items(): + # Calculate factor values for each symbol + # Example: Momentum factor + momentum = (df['close'].iloc[-1] / df['close'].iloc[-20] - 1) * 100 + + # Example: RSI indicator + def calculate_rsi(prices, period=14): + delta = prices.diff() + gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + return rsi.iloc[-1] + + rsi = calculate_rsi(df['close'], 14) + + # Composite score (adjust weights as needed) + score = momentum * 0.6 + (100 - rsi) * 0.4 + scores[symbol] = score + +# Optional: Manually specify ranking (if not provided, system will auto-sort by scores) +# rankings = sorted(scores.keys(), key=lambda x: scores[x], reverse=True) +``` + +### Indicator Code Environment Variables + +The following variables are available when indicator code executes: + +- `symbols`: Symbol list `['Crypto:BTC/USDT', 'Crypto:ETH/USDT', ...]` +- `data`: K-line data for all symbols `{symbol: df, ...}` +- `scores`: Dictionary for storing scores (needs to be populated in code) +- `rankings`: List for storing rankings (optional, auto-sorted by scores if not provided) +- `np`: numpy +- `pd`: pandas +- `trading_config`: Trading configuration +- `config`: Trading configuration (alias) + +### Output Requirements + +Indicator code needs to populate the `scores` dictionary: + +```python +scores[symbol] = score_value # score_value can be any numeric value +``` + +Optional: Populate the `rankings` list (if not provided, system will auto-sort by scores): + +```python +rankings = [symbol1, symbol2, ...] # Sorted by score from high to low +``` + +## Signal Generation Logic + +The system automatically generates trading signals based on the following logic: + +1. **Rank Symbols**: Rank all symbols based on indicator-calculated scores +2. **Select Positions**: + - Top `portfolio_size * long_ratio` symbols → Long + - Bottom `portfolio_size * (1 - long_ratio)` symbols → Short +3. **Generate Signals**: + - New symbols: If a symbol is not in current positions, generate open signal + - Remove symbols: If a symbol is not in target positions, generate close signal + - Direction change: If a symbol needs to change from long to short or vice versa, first generate close signal, then open signal + +## Usage Examples + +### 1. Create Cross-Sectional Strategy + +When creating a strategy via API, include in the request body: + +```json +{ + "strategy_name": "Momentum Cross-Sectional Strategy", + "trading_config": { + "cs_strategy_type": "cross_sectional", + "symbol_list": [ + "Crypto:BTC/USDT", + "Crypto:ETH/USDT", + "Crypto:BNB/USDT", + "Crypto:ADA/USDT", + "Crypto:SOL/USDT" + ], + "portfolio_size": 5, + "long_ratio": 0.6, + "rebalance_frequency": "daily", + "timeframe": "1H", + "initial_capital": 10000, + "leverage": 1, + "market_type": "swap" + }, + "indicator_config": { + "indicator_id": 123, + "indicator_code": "..." + } +} +``` + +### 2. Indicator Code Example + +```python +# Momentum + RSI Composite Score +scores = {} +for symbol, df in data.items(): + # 20-period momentum + momentum = (df['close'].iloc[-1] / df['close'].iloc[-20] - 1) * 100 + + # RSI + delta = df['close'].diff() + gain = (delta.where(delta > 0, 0)).rolling(window=14).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean() + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + rsi_value = rsi.iloc[-1] + + # Composite score + score = momentum * 0.7 + (100 - rsi_value) * 0.3 + scores[symbol] = score +``` + +## Notes + +1. **Data Retrieval**: The system retrieves K-line data for each symbol. If data retrieval fails for a symbol, that symbol will be skipped. +2. **Rebalancing Frequency**: The system checks if rebalancing is needed based on `rebalance_frequency` settings. No trades will be executed if it's not time to rebalance. +3. **Batch Execution**: All trading signals are executed in parallel, with a maximum of 10 concurrent trades. +4. **Position Management**: The system automatically manages positions to ensure the portfolio meets configuration requirements. +5. **Compatibility**: Cross-sectional strategy functionality does not affect existing single-symbol strategies. Both can coexist. + +## Database Migration + +If you need to store cross-sectional strategy configuration in database fields (optional), you can run the migration script: + +```sql +-- Run migrations/add_cross_sectional_strategy.sql +``` + +If you don't run the migration script, cross-sectional strategy configuration will be stored in the `trading_config` JSON field, and functionality will work normally. + +## Troubleshooting + +1. **Strategy Not Executing**: + - Check if `cs_strategy_type` is `'cross_sectional'` + - Check if `symbol_list` is not empty + - Check if rebalancing frequency time has been reached + +2. **Indicator Execution Failed**: + - Check if indicator code correctly populates the `scores` dictionary + - Check if data for all symbols can be retrieved normally + +3. **Signals Not Generated**: + - Check if `portfolio_size` is less than or equal to the length of `symbol_list` + - Check if scores are valid diff --git a/EXTENSION_GUIDE.md b/EXTENSION_GUIDE.md new file mode 100644 index 0000000..13ef4a2 --- /dev/null +++ b/EXTENSION_GUIDE.md @@ -0,0 +1,162 @@ +# QuantDinger Extension Guide + +This guide explains how to add features without making the backend harder to +maintain. Prefer small, boring, easy-to-review changes. + +## Before You Start + +1. Find the closest existing module. +2. Read `docs/ARCHITECTURE.md` and `docs/MODULE_BOUNDARIES.md`. +3. Decide whether the change is API, service, adapter, data, worker, or docs. +4. Keep route paths and response fields backward-compatible unless a breaking + change is explicitly approved. + +## Add a Human Web API Endpoint + +Use this flow for routes consumed by the web or mobile UI: + +1. Add the route in the closest route module, or create a small sibling module + if the current file is already large. +2. Keep the route thin: validate input, call a service, return JSON. +3. Put workflow logic in `app/services//...` when the feature has more + than one workflow. Use a flat service file only for small one-off helpers. +4. Add or update OpenAPI tag metadata in `app/openapi/register.py` and + `app/openapi/tags.py` when introducing a new route family. +5. Regenerate the human API spec: + +```bash +cd backend_api_python +python scripts/export_openapi.py +``` + +6. Run the OpenAPI smoke test when dependencies are available: + +```bash +cd backend_api_python +python -m pytest tests/test_openapi.py -q +``` + +## Add an Agent Gateway Endpoint + +Use this flow for external AI agents, MCP clients, and automation: + +1. Add code under `app/routes/agent_v1`. +2. Enforce token scopes using the existing agent security helpers. +3. Keep write/trade actions explicit and auditable. +4. Update `docs/agent/agent-openapi.json`. +5. Do not mix agent-only routes into the human OpenAPI spec. + +## Add a Market Data Source + +1. Implement the adapter in `app/data_sources`. +2. Return normalized rows: + +```python +{ + "time": 1710000000, + "open": 1.0, + "high": 1.2, + "low": 0.9, + "close": 1.1, + "volume": 1000.0, +} +``` + +3. Register selection logic in `DataSourceFactory`. +4. Keep provider-specific column names inside the adapter. +5. Include market, symbol, timeframe, exchange, and market type in cache keys + where relevant. +6. Add a small smoke check or script if the provider has fragile symbol rules. + +## Add a Symbol Master Data Source + +1. Prefer database-backed master data over hardcoded symbol lists. +2. Put sync/import logic in scripts or service modules, not route files. +3. Keep seed SQL deterministic so fresh Docker installs work offline. +4. Make search tolerant of symbol, name, alias, and localized company names. +5. Do not hardcode large symbol lists in Python route modules. + +## Add an Exchange or Broker Adapter + +1. Put low-level API calls under `app/services/live_trading`. +2. Normalize account, position, order, fill, and error shapes. +3. Keep exchange precision and sizing logic near the adapter. +4. Keep strategy lifecycle outside the adapter. +5. Add explicit notes for market type support: + - spot + - swap/perpetual + - US stock + - paper/live +6. If an adapter supports live orders, document idempotency and retry behavior. + +## Add a Strategy Runtime Feature + +1. Avoid adding more unrelated logic to `trading_executor.py`. +2. Extract new behavior into a focused service module first. +3. Keep order intent creation separate from order execution. +4. Keep market data reads separate from account mutation. +5. Add safeguards for duplicate starts, duplicate orders, and worker restarts. + +## Add a Backtest Feature + +1. Avoid growing `backtest.py` unless the change is tiny. +2. Prefer extracting: + - data loading + - signal evaluation + - execution model + - metrics + - report formatting +3. Preserve historical result compatibility. +4. Clearly document fill assumptions. + +## Add an AI Feature + +1. Keep prompts and skill definitions separate from provider calls. +2. Keep provider adapters behind a service boundary. +3. Localize user-facing text through translation/i18n structures. +4. Do not let AI flows place live orders without explicit existing trade APIs, + permissions, billing checks, and audit logs. +5. For streaming routes, handle cancellation and partial failures. + +## Add Settings + +1. Define the setting in the backend settings registry. +2. Choose whether it is public, admin-only, or internal. +3. Keep secrets out of public config endpoints. +4. If the setting changes OpenAPI behavior, regenerate `docs/api/openapi.yaml`. +5. Keep environment variable names stable and documented. + +## Add Background Work + +1. Put startup wiring in `app/startup.py`. +2. Put worker behavior in a dedicated service module. +3. Add a clear owner/lock model for multi-process deployments. +4. Make work idempotent before adding retries. +5. Log start, stop, retry, and failure states in English. + +## Verification Checklist + +Run the smallest useful checks for the change: + +```bash +python -m py_compile path/to/changed_file.py +python scripts/check_mojibake.py +``` + +For API changes: + +```bash +cd backend_api_python +python scripts/export_openapi.py +python -m pytest tests/test_openapi.py -q +``` + +For Docker/deploy changes: + +```bash +docker compose config +``` + +For frontend-only work, use the frontend dev server. Do not run production +builds during every small iteration unless the change touches bundling, +environment injection, or release assets. diff --git a/cross_sectional_momentum_rsi.py b/cross_sectional_momentum_rsi.py new file mode 100644 index 0000000..bb6e4be --- /dev/null +++ b/cross_sectional_momentum_rsi.py @@ -0,0 +1,70 @@ +# ============================================================ +# 截面策略指标示例(研究参考版) +# Cross-Sectional Strategy Indicator Example (Research Reference) +# Momentum + RSI Composite Score +# ============================================================ +# +# 使用方法: +# 1. 作为截面研究思路示例阅读 +# 2. 用于理解“对多个标的打分再排序”的基本写法 +# +# 当前限制: +# - 策略快照回测(cross_sectional)暂不支持;实盘指标截面策略可在「交易助手」创建 +# - 创建时选择「截面策略」并插入模板,或在本指标中实现 scores 字典 +# +# 评分逻辑: +# - 动量因子(20周期):价格变化率,越高越好 +# - RSI 指标(14周期):反转 RSI 值,越低越好(100 - RSI) +# - 综合评分:70% 动量 + 30% RSI 反转值 +# +# ============================================================ + +# 截面策略指标 +# 输入: data = {symbol1: df1, symbol2: df2, ...} +# 输出: scores = {symbol1: score1, symbol2: score2, ...} + +scores = {} + +# 遍历全部标的 +for symbol, df in data.items(): + # 确保数据长度足够 + if len(df) < 20: + scores[symbol] = 0 + continue + + # === 1. 计算动量因子 (20周期) === + # 动量 = (当前价格 / 20周期前价格 - 1) * 100 + momentum = (df['close'].iloc[-1] / df['close'].iloc[-20] - 1) * 100 + + # === 2. 计算RSI指标 (14周期) === + def calculate_rsi(prices, period=14): + """计算 RSI 指标""" + delta = prices.diff() + gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + return rsi.iloc[-1] + + rsi_value = calculate_rsi(df['close'], 14) + + # === 3. 综合评分 === + # 动量越高 = 评分越高 + # RSI越低(超卖)= 评分越高(100 - RSI) + # 权重: 70% 动量 + 30% RSI反转值 + momentum_score = momentum + rsi_score = 100 - rsi_value # 反转 RSI(RSI 越低,评分越高) + + composite_score = momentum_score * 0.7 + rsi_score * 0.3 + + scores[symbol] = composite_score + +# === 可选:手动指定排序 === +# 如果不提供,系统会根据 scores 自动排序 +# rankings = sorted(scores.keys(), key=lambda x: scores[x], reverse=True) + +# === 研究语义说明 === +# 1. 根据评分对所有标的进行排序(从高到低) +# 2. 选择排名靠前的 N 个标的做多(基于 portfolio_size * long_ratio) +# 3. 选择排名靠后的 N 个标的做空(基于 portfolio_size * (1 - long_ratio)) +# 4. 在未来平台链路完善后,可由系统统一生成买入 / 卖出 / 平仓动作 diff --git a/dual_ma_with_params.py b/dual_ma_with_params.py new file mode 100644 index 0000000..e24211a --- /dev/null +++ b/dual_ma_with_params.py @@ -0,0 +1,89 @@ +# ============================================================ +# 双均线策略(文档同步版 · 四路信号) +# Dual Moving Average Strategy (Doc-Aligned, Four-Way) +# ============================================================ +# +# 适用场景: +# 1. 在 Indicator IDE 中快速验证均线交叉逻辑 +# 2. 演示 `# @param` + `# @strategy` + 四路执行列 +# 3. 与平台默认模板 / SIGNAL_EXECUTION_STANDARD v1 对齐 +# +# 注意: +# - 杠杆请在产品面板中设置,不要写进源码 +# - 触及型 tp/sl 请用 close_*,勿与 trailingEnabled 叠加 +# +# ============================================================ + +my_indicator_name = "双均线交叉策略" +my_indicator_description = "EMA 金叉/死叉四路信号,边缘触发;退出由引擎 stopLoss/takeProfit 管理。" + +# --- QuantDinger execution contract (v1) --- +# signal_form: four_way +# exit_owner: engine +# flip_mode: R2 + +# === 参数声明(供前端、AI 调参与代码质量检查识别) === +# @param sma_short int 14 短期均线周期 +# @param sma_long int 28 长期均线周期 + +# === 平台默认策略配置 === +# @strategy stopLossPct 0.02 +# @strategy takeProfitPct 0.05 +# @strategy entryPct 0.25 +# @strategy trailingEnabled false +# @strategy tradeDirection both + +# 说明:close_* 只表达均线反转平仓;固定止损/止盈由 engine 风控负责。 +# 如果改成触及型 TP/SL,请同步改为 exit_owner: indicator。 + + +def edge(s): + s = s.fillna(False).astype(bool) + return s & ~s.shift(1).fillna(False) + + +sma_short_period = int(params.get("sma_short", 14)) +sma_long_period = int(params.get("sma_long", 28)) + +df = df.copy() + +sma_short = df["close"].rolling(sma_short_period).mean() +sma_long = df["close"].rolling(sma_long_period).mean() + +golden = (sma_short > sma_long) & (sma_short.shift(1) <= sma_long.shift(1)) +death = (sma_short < sma_long) & (sma_short.shift(1) >= sma_long.shift(1)) + +df["open_long"] = edge(golden) +df["open_short"] = edge(death) +df["close_long"] = edge(death) +df["close_short"] = edge(golden) + +n = len(df) +open_long_marks = [ + df["low"].iloc[i] * 0.995 if bool(df["open_long"].iloc[i]) else None for i in range(n) +] +open_short_marks = [ + df["high"].iloc[i] * 1.005 if bool(df["open_short"].iloc[i]) else None for i in range(n) +] + +output = { + "name": my_indicator_name, + "plots": [ + { + "name": f"SMA{sma_short_period}", + "data": sma_short.fillna(0).tolist(), + "color": "#FF9800", + "overlay": True, + }, + { + "name": f"SMA{sma_long_period}", + "data": sma_long.fillna(0).tolist(), + "color": "#3F51B5", + "overlay": True, + }, + ], + "signals": [ + {"type": "buy", "text": "L", "data": open_long_marks, "color": "#00E676"}, + {"type": "sell", "text": "S", "data": open_short_marks, "color": "#FF5252"}, + ], +}