# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement # flake8: noqa: F401 # isort: skip_file #默认库freq框架已经导入,只需要在脚本调配置就行了。 # --- 基础库导入 --- import numpy as np import pandas as pd from datetime import datetime from pandas import DataFrame from typing import Optional from freqtrade.strategy import ( IStrategy, informative, BooleanParameter, CategoricalParameter, DecimalParameter, IntParameter, RealParameter, timeframe_to_minutes, merge_informative_pair, stoploss_from_absolute, stoploss_from_open, ) import talib.abstract as ta from technical import qtpylib class OptimizedETHStrategy(IStrategy): # ============ 杠杆与资金费用设置 ============ can_short = False # 只做多方向 timeframe = '15m' process_only_new_candles = True startup_candle_count = 100 # ============ 风险管理参数 ============ stoploss = -0.50 # 单笔最大亏损50%(考虑杠杆后实际为0.5/6 1/12%本金) use_custom_stoploss = True position_adjustment_enable = True max_entry_position_adjustment = 4 # ============ 动态止盈参数 ============ minimal_roi = { "0": 0.15, "10": 0.10, "30": 0.05, "60": 0 } # ============ 追踪止损参数 ============ trailing_stop = True trailing_stop_positive = 0.03 # 盈利3%后激活 trailing_stop_positive_offset = 0.08 # 从8%利润开始追踪 trailing_only_offset_is_reached = True # ============ 订单类型 ============ order_types = { 'entry': 'market', 'exit': 'market', 'emergency_exit': 'market', 'force_entry': "market", 'stoploss': 'market', 'stoploss_on_exchange': False, 'stoploss_on_exchange_interval': 60, 'stoploss_on_exchange_limit_ratio': 0.99 } # 训练过的yperopt参数 (不要修改) buy_rsi = IntParameter(low=1, high=50, default=31.685, space="buy", optimize=True, load=True) sell_rsi = IntParameter(low=50, high=100, default=72.581, space="sell", optimize=True, load=True) short_rsi = IntParameter(low=51, high=100, default=70, space="sell", optimize=True, load=True) exit_short_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True, load=True) plot_config = { "main_plot": { "tema": {}, "sar": {"color": "white"}, }, "subplots": { "MACD": { "macd": {"color": "blue"}, "macdsignal": {"color": "orange"}, }, "RSI": { "rsi": {"color": "red"}, }, }, } def informative_pairs(self): return [] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Momentum Indicators dataframe["adx"] = ta.ADX(dataframe) dataframe["rsi"] = ta.RSI(dataframe) # Stochastic Fast stoch_fast = ta.STOCHF(dataframe) dataframe["fastd"] = stoch_fast["fastd"] dataframe["fastk"] = stoch_fast["fastk"] # MACD macd = ta.MACD(dataframe) dataframe["macd"] = macd["macd"] dataframe["macdsignal"] = macd["macdsignal"] dataframe["macdhist"] = macd["macdhist"] # Bollinger Bands bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) dataframe["bb_lowerband"] = bollinger["lower"] dataframe["bb_middleband"] = bollinger["mid"] dataframe["bb_upperband"] = bollinger["upper"] dataframe["bb_percent"] = (dataframe["close"] - dataframe["bb_lowerband"]) / ( dataframe["bb_upperband"] - dataframe["bb_lowerband"] ) dataframe["bb_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] # TEMA dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.buy_rsi.value)) & (dataframe["tema"] <= dataframe["bb_middleband"]) & (dataframe["tema"] > dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "enter_long", ] = 1 dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.short_rsi.value)) & (dataframe["tema"] > dataframe["bb_middleband"]) & (dataframe["tema"] < dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "enter_short", ] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.sell_rsi.value)) & (dataframe["tema"] > dataframe["bb_middleband"]) & (dataframe["tema"] < dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "exit_long", ] = 1 dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.exit_short_rsi.value)) & (dataframe["tema"] <= dataframe["bb_middleband"]) & (dataframe["tema"] > dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "exit_short", ] = 1 return dataframe