第29课:机器学习与策略优化

发布: (2025年12月3日 GMT+8 11:03)
4 min read
原文: Dev.to

Source: Dev.to

⏱ Duration: 2.5 hours

🎯 Learning Objectives

  • 学会使用机器学习辅助策略开发和参数优化

Course Overview

机器学习(ML)可以帮助我们:

  • 🔍 发现数据中的隐藏模式
  • 🎯 优化策略参数
  • 📊 预测价格趋势
  • 🤖 构建自适应策略

Important Reminders

  • ⚠️ 机器学习并非“圣杯”,不能保证盈利。
  • ⚠️ 需要大量数据和计算资源。
  • ⚠️ 容易出现过拟合,必须谨慎验证。
  • ⚠️ 本课程侧重实用方法,而非理论深度。

Part 1: Freqtrade’s Hyperopt

1.1 Hyperopt Introduction

Hyperopt 是 Freqtrade 内置的参数优化工具,使用机器学习算法自动寻找最优参数。

Basic Concepts

What is Hyperopt?
- Automated parameter search
- Uses Bayesian optimization algorithms
- Searches for optimal parameters within specified ranges
- Scores based on backtest results

What can be optimized?
- Buy condition parameters (RSI thresholds, EMA periods)
- Sell condition parameters
- ROI configuration
- Stop loss configuration
- Trailing stop loss configuration

Optimization Spaces

Freqtrade supports 5 optimization spaces:

1. buy      – Buy condition parameters
2. sell     – Sell condition parameters
3. roi      – ROI configuration
4. stoploss – Stop loss configuration
5. trailing – Trailing stop loss configuration

Can optimize individually or in combination.

1.2 Preparing Hyperopt‑Compatible Strategies

Create a strategy file, e.g. user_data/strategies/HyperoptableStrategy.py:

from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter, CategoricalParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce

class HyperoptableStrategy(IStrategy):
    """
    Hyperopt‑compatible strategy
    Define optimizable parameter ranges
    """
    INTERFACE_VERSION = 3

    # ===== Optimizable Parameters =====
    # Buy parameters
    buy_rsi_threshold = IntParameter(20, 40, default=30, space='buy')
    buy_rsi_enabled   = CategoricalParameter([True, False], default=True, space='buy')
    buy_ema_short     = IntParameter(5, 20, default=9, space='buy')
    buy_ema_long      = IntParameter(15, 50, default=21, space='buy')

    # Sell parameters
    sell_rsi_threshold = IntParameter(60, 80, default=70, space='sell')
    sell_rsi_enabled   = CategoricalParameter([True, False], default=True, space='sell')

    # ROI parameters (static example)
    minimal_roi = {
        "0": 0.10,
        "30": 0.05,
        "60": 0.03,
        "120": 0.01
    }

    # Stop loss parameter
    stoploss = -0.10

    # Trailing stop loss parameters
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.02
    trailing_only_offset_is_reached = True

    timeframe = '5m'
    startup_candle_count: int = 50

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # EMA (using optimizable periods)
        for val in self.buy_ema_short.range:
            dataframe[f'ema_short_{val}'] = ta.EMA(dataframe, timeperiod=val)
        for val in self.buy_ema_long.range:
            dataframe[f'ema_long_{val}'] = ta.EMA(dataframe, timeperiod=val)

        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

        # Volume mean
        dataframe['volume_mean'] = dataframe['volume'].rolling(window=20).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        # EMA golden cross
        conditions.append(
            qtpylib.crossed_above(
                dataframe[f'ema_short_{self.buy_ema_short.value}'],
                dataframe[f'ema_long_{self.buy_ema_long.value}']
            )
        )

        # RSI (if enabled)
        if self.buy_rsi_enabled.value:
            conditions.append(dataframe['rsi'] > self.buy_rsi_threshold.value)
            conditions.append(dataframe['rsi']  dataframe['volume_mean'])
        conditions.append(dataframe['volume'] > 0)

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        # EMA death cross
        conditions.append(
            qtpylib.crossed_below(
                dataframe[f'ema_short_{self.buy_ema_short.value}'],
                dataframe[f'ema_long_{self.buy_ema_long.value}']
            )
        )

        # RSI (if enabled)
        if self.sell_rsi_enabled.value:
            conditions.append(dataframe['rsi'] > self.sell_rsi_threshold.value)

        # Volume filter
        conditions.append(dataframe['volume'] > 0)

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
        return dataframe

Key Points

# Integer parameter
buy_rsi_threshold = IntParameter(20, 40, default=30, space='buy')
# Search within 20‑40 range, default 30

# Decimal parameter
stoploss = DecimalParameter(-0.15, -0.05, default=-0.10, space='stoploss')
# Search within -0.15 to -0.05 range

# Categorical parameter (True/False)
buy_rsi_enabled = CategoricalParameter([True, False], default=True, space='buy')

1.3 Running Hyperopt

Basic Commands

# Optimize buy parameters only
freqtrade hyperopt \
    -c config.json \
    --strategy HyperoptableStrategy \
    --hyperopt-loss SharpeHyperOptLoss \
    --spaces buy \
    --epochs 100
  • --hyperopt-loss – defines the optimization objective.
  • --spaces – which parameter spaces to optimize.
  • --epochs – number of optimization iterations.

Optimizing Multiple Spaces

# Optimize both buy and sell simultaneously
freqtrade hyperopt \
    -c config.json \
    --strategy HyperoptableStrategy \
    --hyperopt-loss SharpeHyperOptLoss \
    --spaces buy sell \
    --epochs 200

# Optimize all spaces
freqtrade hyperopt \
    -c config.json \
    --strategy HyperoptableStrategy \
    --hyperopt-loss SharpeHyperOptLoss \
    --spaces all \
    --epochs 500

Sample Output

Best result:
    188/500: 145 trades. Avg profit 0.85%. Total profit 0.01234 BTC (123.45%).
    Avg duration 234.5 m. Objective: -2.34567

Buy hyperspace params:
{
    "buy_ema_short": 12,
    "buy_ema_long": 26,
    "buy_rsi_threshold": 35,
    "buy_rsi_enabled": true
}

Sell hyperspace params:
{
    "sell_rsi_threshold": 65,
    "sell_rsi_enabled": true
}

ROI table:
{
    "0": 0.088,
    "25": 0.045,
    "51": 0.019,
    "139": 0
}

Stoploss: -0.089

1.4 Loss Functions

Loss functions define what “optimal” means for the optimizer.

Common Loss Functions

# Example: Sharpe ratio based loss
from freqtrade.optimize.hyperopt import HyperOptLoss

class SharpeHyperOptLoss(HyperOptLoss):
    @staticmethod
    def hyperopt_loss_function(results):
        # Higher Sharpe → lower loss (since optimizer minimizes)
        return -results['sharpe']

Other built‑in options include CalmarHyperOptLoss, SortinoHyperOptLoss, and custom user‑defined functions. Choose the one that aligns with your risk‑adjusted performance goals.

Back to Blog

相关文章

阅读更多 »

Strands 代理 + Agent Core AWS

入门指南:Amazon Bedrock AgentCore 目录 - 前置要求(requisitos‑previos) - 工具包安装(instalación‑del‑toolkit) - 创建…