Skip to content

TA4J 0.17 版本中,要实现"20MA斜率 > 15°"的条件(使用ATR指标量化),可以通过以下步骤实现。这里的关键是将角度条件转换为价格变动幅度的阈值,利用ATR指标动态调整判定标准。


一、实现思路

  1. 斜率量化:将15°角度转换为价格变动幅度(ATR倍数)。
  2. 动态阈值:用ATR值作为波动率基准,计算最小斜率要求。
  3. 规则构建:通过比较当前MA值与历史值的变动幅度来判定斜率条件。

二、完整代码实现

java
import org.ta4j.core.*;
import org.ta4j.core.indicators.*;
import org.ta4j.core.indicators.helpers.*;
import org.ta4j.core.num.Num;
import org.ta4j.core.rules.*;

public class SlopeStrategy {

    public static Strategy buildStrategy(BarSeries series) {
        // 1. 计算基础指标
        ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
        SMAIndicator sma20 = new SMAIndicator(closePrice, 20);
        ATRIndicator atr = new ATRIndicator(series, 14); // 14周期ATR

        // 2. 将15°斜率转换为ATR倍数(经验值:tan(15°)≈0.27)
        Num slopeThreshold = series.numOf(0.27); 

        // 3. 构建斜率规则(当前MA值比前一个MA值高出至少 threshold * ATR)
        Rule slopeRule = new BooleanRule(index -> {
            if (index < 1) return false; // 需要至少2个数据点
            
            Num currentMA = sma20.getValue(index);
            Num previousMA = sma20.getValue(index - 1);
            Num currentATR = atr.getValue(index);
            
            // 计算实际斜率:ΔMA / ATR
            Num actualSlope = currentMA.minus(previousMA).dividedBy(currentATR);
            
            return actualSlope.isGreaterThan(slopeThreshold);
        });

        // 4. 组合其他交易规则(示例:价格在20MA上方)
        Rule entryRule = new AndRule(
            new OverIndicatorRule(closePrice, sma20),
            slopeRule
        );

        // 5. 平仓规则(示例:价格跌破20MA)
        Rule exitRule = new CrossedDownIndicatorRule(closePrice, sma20);

        return new BaseStrategy(entryRule, exitRule);
    }

    public static void main(String[] args) {
        // 加载数据
        BarSeries series = CsvBarsLoader.loadCsvSeries("data/BTC_daily.csv");
        
        // 创建策略
        Strategy strategy = buildStrategy(series);
        
        // 运行回测
        TradingRecord tradingRecord = new BarSeriesManager(series).run(strategy);
        
        // 分析结果
        System.out.println("交易次数: " + tradingRecord.getTradeCount());
        System.out.println("总收益率: " + new ReturnIndicator(series, tradingRecord).getValue(series.getEndIndex()));
    }
}
import org.ta4j.core.*;
import org.ta4j.core.indicators.*;
import org.ta4j.core.indicators.helpers.*;
import org.ta4j.core.num.Num;
import org.ta4j.core.rules.*;

public class SlopeStrategy {

    public static Strategy buildStrategy(BarSeries series) {
        // 1. 计算基础指标
        ClosePriceIndicator closePrice = new ClosePriceIndicator(series);
        SMAIndicator sma20 = new SMAIndicator(closePrice, 20);
        ATRIndicator atr = new ATRIndicator(series, 14); // 14周期ATR

        // 2. 将15°斜率转换为ATR倍数(经验值:tan(15°)≈0.27)
        Num slopeThreshold = series.numOf(0.27); 

        // 3. 构建斜率规则(当前MA值比前一个MA值高出至少 threshold * ATR)
        Rule slopeRule = new BooleanRule(index -> {
            if (index < 1) return false; // 需要至少2个数据点
            
            Num currentMA = sma20.getValue(index);
            Num previousMA = sma20.getValue(index - 1);
            Num currentATR = atr.getValue(index);
            
            // 计算实际斜率:ΔMA / ATR
            Num actualSlope = currentMA.minus(previousMA).dividedBy(currentATR);
            
            return actualSlope.isGreaterThan(slopeThreshold);
        });

        // 4. 组合其他交易规则(示例:价格在20MA上方)
        Rule entryRule = new AndRule(
            new OverIndicatorRule(closePrice, sma20),
            slopeRule
        );

        // 5. 平仓规则(示例:价格跌破20MA)
        Rule exitRule = new CrossedDownIndicatorRule(closePrice, sma20);

        return new BaseStrategy(entryRule, exitRule);
    }

    public static void main(String[] args) {
        // 加载数据
        BarSeries series = CsvBarsLoader.loadCsvSeries("data/BTC_daily.csv");
        
        // 创建策略
        Strategy strategy = buildStrategy(series);
        
        // 运行回测
        TradingRecord tradingRecord = new BarSeriesManager(series).run(strategy);
        
        // 分析结果
        System.out.println("交易次数: " + tradingRecord.getTradeCount());
        System.out.println("总收益率: " + new ReturnIndicator(series, tradingRecord).getValue(series.getEndIndex()));
    }
}

三、关键代码解析

1. 斜率量化逻辑

java
// 将角度转换为ATR倍数(tan(15°)≈0.27)
Num slopeThreshold = series.numOf(0.27);

// 计算实际斜率
Num actualSlope = currentMA.minus(previousMA).dividedBy(currentATR);
// 将角度转换为ATR倍数(tan(15°)≈0.27)
Num slopeThreshold = series.numOf(0.27);

// 计算实际斜率
Num actualSlope = currentMA.minus(previousMA).dividedBy(currentATR);
  • 为什么用ATR:ATR反映市场波动率,使斜率判定自适应不同品种/行情
  • 0.27的含义tan(15°)≈0.27,表示价格需要上涨27%的ATR值

2. 动态斜率规则

java
Rule slopeRule = new BooleanRule(index -> {
    Num currentMA = sma20.getValue(index);
    Num previousMA = sma20.getValue(index - 1);
    Num currentATR = atr.getValue(index);
    return currentMA.minus(previousMA).dividedBy(currentATR).isGreaterThan(slopeThreshold);
});
Rule slopeRule = new BooleanRule(index -> {
    Num currentMA = sma20.getValue(index);
    Num previousMA = sma20.getValue(index - 1);
    Num currentATR = atr.getValue(index);
    return currentMA.minus(previousMA).dividedBy(currentATR).isGreaterThan(slopeThreshold);
});
  • 每根K线检查MA变化幅度是否超过ATR的27%
  • 避免固定点数阈值,适应不同波动市场

3. 策略组合

java
Rule entryRule = new AndRule(
    new OverIndicatorRule(closePrice, sma20), // 价格在MA上方
    slopeRule // MA斜率达标
);
Rule entryRule = new AndRule(
    new OverIndicatorRule(closePrice, sma20), // 价格在MA上方
    slopeRule // MA斜率达标
);
  • 只有同时满足价格位置和斜率条件才会触发交易

四、参数优化建议

  1. 斜率阈值调整

    • 激进策略:使用tan(10°)≈0.18
    • 保守策略:使用tan(20°)≈0.36
  2. ATR周期优化

    java
    ATRIndicator atr = new ATRIndicator(series, 20); // 改为20周期ATR
    ATRIndicator atr = new ATRIndicator(series, 20); // 改为20周期ATR
  3. 结合其他过滤器

    java
    // 增加成交量条件
    VolumeIndicator volume = new VolumeIndicator(series);
    Rule volumeRule = new OverIndicatorRule(volume, new SMAIndicator(volume, 10));
    
    entryRule = new AndRule(entryRule, volumeRule);
    // 增加成交量条件
    VolumeIndicator volume = new VolumeIndicator(series);
    Rule volumeRule = new OverIndicatorRule(volume, new SMAIndicator(volume, 10));
    
    entryRule = new AndRule(entryRule, volumeRule);

五、可视化验证(调试技巧)

java
// 打印关键指标值用于调试
for (int i = series.getBeginIndex(); i <= series.getEndIndex(); i++) {
    Num ma = sma20.getValue(i);
    Num atrValue = atr.getValue(i);
    Num slope = i > 0 ? 
        ma.minus(sma20.getValue(i-1)).dividedBy(atrValue) : 
        series.numOf(0);
    
    System.out.printf("Bar %d: MA=%.2f ATR=%.2f Slope=%.2f%n", 
        i, ma.doubleValue(), atrValue.doubleValue(), slope.doubleValue());
}
// 打印关键指标值用于调试
for (int i = series.getBeginIndex(); i <= series.getEndIndex(); i++) {
    Num ma = sma20.getValue(i);
    Num atrValue = atr.getValue(i);
    Num slope = i > 0 ? 
        ma.minus(sma20.getValue(i-1)).dividedBy(atrValue) : 
        series.numOf(0);
    
    System.out.printf("Bar %d: MA=%.2f ATR=%.2f Slope=%.2f%n", 
        i, ma.doubleValue(), atrValue.doubleValue(), slope.doubleValue());
}

输出示例:

Bar 25: MA=5023.45 ATR=120.50 Slope=0.31  ← 满足条件
Bar 26: MA=5030.20 ATR=118.75 Slope=0.22  ← 不满足
Bar 25: MA=5023.45 ATR=120.50 Slope=0.31  ← 满足条件
Bar 26: MA=5030.20 ATR=118.75 Slope=0.22  ← 不满足

六、注意事项

  1. 边界处理

    • 检查index-1是否越界(示例代码已处理)
    • 初始阶段ATR可能不稳定,建议忽略前20根K线
  2. 时间周期适配

    • 15°斜率标准适用于日线级别
    • 短线交易(如15分钟)建议调整为tan(30°)≈0.58
  3. 实盘测试

    • 先用历史数据回测验证
    • 逐步调整参数至最佳风险收益比

通过这种方法,您可以实现动态的均线斜率条件,相比固定点数阈值更能适应市场波动变化。