上传文件至「/」
This commit is contained in:
@@ -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` 的长度
|
||||
- 检查评分是否有效
|
||||
@@ -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
|
||||
@@ -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/<feature>/...` 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.
|
||||
@@ -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. 在未来平台链路完善后,可由系统统一生成买入 / 卖出 / 平仓动作
|
||||
@@ -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"},
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user