""" Freqtrade strategy template — wave support bounce with 10% stop loss. Aligns with docs/investment/principles.md: - BTC spot only - strict stoploss at -10% - enter near annotated support, reclaim SMA20 Setup: 1. Install freqtrade: https://www.freqtrade.io/en/stable/ 2. Copy this file to /user_data/strategies/ 3. Dry-run: freqtrade trade --strategy WaveSupportStrategy --dry-run Docs: strategies/freqtrade/README.md """ from datetime import datetime from typing import Optional import talib.abstract as ta from pandas import DataFrame from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter class WaveSupportStrategy(IStrategy): INTERFACE_VERSION = 3 # 投资原则: 严格 10% 止损 stoploss = -0.10 trailing_stop = False timeframe = "1d" startup_candle_count = 50 # Annotated support from docs/wave-theory/analysis/btc-2026-03.md support_level = DecimalParameter(60000, 75000, default=67979, decimals=0, space="buy") support_tolerance = DecimalParameter(0.01, 0.05, default=0.02, decimals=2, space="buy") rsi_max = IntParameter(40, 70, default=55, space="buy") minimal_roi = { "0": 0.15, "7": 0.08, "30": 0.04, } def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe["sma_20"] = ta.SMA(dataframe, timeperiod=20) dataframe["sma_50"] = ta.SMA(dataframe, timeperiod=50) dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: support = float(self.support_level.value) tol = float(self.support_tolerance.value) near_support = dataframe["low"] <= support * (1 + tol) reclaim = dataframe["close"] > dataframe["sma_20"] not_overbought = dataframe["rsi"] < self.rsi_max.value dataframe.loc[ near_support & reclaim & not_overbought, "enter_long", ] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Exit when price loses SMA50 in weak RSI environment (trend failure) dataframe.loc[ (dataframe["close"] < dataframe["sma_50"]) & (dataframe["rsi"] < 45), "exit_long", ] = 1 return dataframe def custom_stoploss( self, pair: str, trade, current_time: datetime, current_rate: float, current_profit: float, after_fill: bool, **kwargs, ) -> Optional[float]: # Hard cap: never widen beyond -10% return self.stoploss