144 lines
4.9 KiB
Markdown
144 lines
4.9 KiB
Markdown
#交易 #量化交易 #策略研究 #freqtrade #DeepSeek
|
||
|
||
在 Freqtrade 策略中实现多时间框架指标计算(如 5 分钟主框架下计算 1 小时 ADX)需通过 **K 线数据重采样(Resample)** 实现。以下是具体方法和注意事项:
|
||
|
||
---
|
||
|
||
### 一、实现原理
|
||
|
||
1. **默认时间框架**
|
||
`populate_indicators()` 中 `dataframe` 默认使用配置文件 `config.json` 的 `timeframe`(如 `5m`),所有计算基于此周期[1,3](@ref)。
|
||
2. **多时间框架需求**
|
||
若需计算更高周期指标(如 1 小时 ADX),需将原始数据**重采样**为目标周期(1h),再计算指标,最后**对齐**到原始时间戳[6](@ref)。
|
||
|
||
---
|
||
|
||
### 二、实现步骤(代码示例)
|
||
|
||
以下是在 5 分钟策略中计算 1 小时 ADX 的完整代码:
|
||
|
||
```python
|
||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||
# 1. 复制 DataFrame 避免污染原始数据
|
||
df = dataframe.copy()
|
||
|
||
# 2. 重采样为 1 小时数据 (聚合规则)
|
||
resample_rule = '1H'
|
||
df_resampled = df.resample(
|
||
resample_rule,
|
||
on='date', # 时间列
|
||
closed='right', # 右边界闭合
|
||
label='right' # 时间标签取右边界
|
||
).agg({
|
||
'open': 'first',
|
||
'high': 'max',
|
||
'low': 'min',
|
||
'close': 'last',
|
||
'volume': 'sum'
|
||
}).dropna()
|
||
|
||
# 3. 在重采样数据上计算 1 小时 ADX
|
||
df_resampled['adx_1h'] = ta.ADX(
|
||
df_resampled,
|
||
timeperiod=14 # ADX 周期
|
||
)
|
||
|
||
# 4. 将 1 小时 ADX 合并回原始 5 分钟数据
|
||
# 注意:使用前向填充 (ffill) 避免未来函数
|
||
dataframe['adx_1h'] = df_resampled['adx_1h'].reindex(
|
||
df.index,
|
||
method='ffill' # 用上一个有效的小时值填充
|
||
)
|
||
|
||
# 5. 可选:删除中间列避免内存占用
|
||
dataframe.drop(columns=['adx_1h_temp'], inplace=True, errors='ignore')
|
||
|
||
return dataframe
|
||
```
|
||
|
||
---
|
||
|
||
### 三、关键注意事项
|
||
|
||
1. **避免未来函数**
|
||
|
||
- **必须用 `ffill` 而非 `bfill`**:`bfill` 会使用未来数据,导致回测失真[6](@ref)。
|
||
- **滞后处理**:1 小时 ADX 在 5 分钟数据中需在整点后生效(如 10:00 的 ADX 在 10:05 才能使用)。
|
||
2. **重采样规则**
|
||
|
||
|参数|值|说明|
|
||
|---|---|---|
|
||
|`closed`|`right`|确保当前 K 线数据属于前一个小时的统计区间,避免未来信息泄露|
|
||
|`label`|`right`|时间戳标记为小时结束点(如 10:00 标签包含 09:05-10:00 的数据)|
|
||
|`volume`|`sum`|成交量按小时累加|
|
||
|`high`/`low`|`max`/`min`|价格取区间极值|
|
||
|
||
3. **性能优化**
|
||
|
||
- **仅重采样必要列**:减少 `agg()` 中不必要的列(如不用的 `trades` 列)[6](@ref)。
|
||
- **禁用未用指标**:不在 `populate_indicators` 中计算未参与信号逻辑的指标。
|
||
4. **实盘适配**
|
||
|
||
- 实时运行时,最后一根 K 线可能不完整(如当前小时未结束),需通过 `dropna()` 排除[3](@ref)。
|
||
|
||
---
|
||
|
||
### 四、替代方案:多时间框架数据注入
|
||
|
||
对高频策略,可通过配置文件直接加载多周期数据(需修改 `config.json`):
|
||
|
||
```
|
||
"dataframe_extra": {
|
||
"enabled": true,
|
||
"timeframes": ["1h", "4h"]
|
||
}
|
||
```
|
||
|
||
在策略中通过 `self.dp` 访问:
|
||
|
||
```
|
||
def populate_indicators(self, dataframe, metadata):
|
||
# 获取 1 小时数据
|
||
df_1h = self.dp.get_pair_dataframe(metadata["pair"], "1h")
|
||
dataframe["adx_1h"] = df_1h["adx"].reindex(dataframe.index, method="ffill")
|
||
return dataframe
|
||
```
|
||
|
||
> **优点**:避免重复计算,适合高频策略[4,5](@ref)。
|
||
> **缺点**:需提前下载多周期数据,配置文件更复杂。
|
||
|
||
---
|
||
|
||
### 五、典型错误及规避
|
||
|
||
1. **未来函数陷阱**
|
||
|
||
```
|
||
# 错误!直接合并会导致未来数据
|
||
dataframe['adx_1h'] = df_resampled['adx_1h'] # 未对齐时间戳
|
||
```
|
||
|
||
**修正**:必须用 `reindex(..., method='ffill')`。
|
||
|
||
2. **边界处理错误**
|
||
|
||
```
|
||
# 错误!left 边界会导致当前小时数据污染
|
||
df_resampled = df.resample(..., closed='left', label='left')
|
||
```
|
||
|
||
**修正**:始终用 `closed='right', label='right'`。
|
||
|
||
|
||
---
|
||
|
||
### 六、总结建议
|
||
|
||
- **震荡策略**:优先使用 `resample` 动态计算(节省数据下载时间)。
|
||
- **趋势策略**:在 `config.json` 中预加载多周期数据(减少实时计算负载)。
|
||
- **关键检查点**:
|
||
✅ 验证回测时是否出现 `NaN`(需 `dropna()` 或 `ffill`)
|
||
✅ 对比实盘/回测中 1 小时 ADX 的值是否一致
|
||
✅ 监控策略内存占用(多周期数据易导致 OOM)
|
||
|
||
> 进阶参考:TA-Lib 的多周期协同策略案例可参考[6](@ref)中的 _多周期RSI策略_ 实现。 |