This commit is contained in:
zhangkun9038@dingtalk.com 2025-05-07 13:41:13 +08:00
parent 6730a560fd
commit b5d1743843
3 changed files with 260 additions and 2 deletions

View File

@ -0,0 +1,68 @@
{
"strategy": "MyStrategy",
"timeframe": "5m",
"dry_run": true,
"stake_currency": "USDT",
"stake_amount": 10.0,
"minimal_roi": {
"40": 0.0,
"30": 0.01,
"20": 0.02,
"0": 0.04
},
"stoploss": -0.10,
"trailing_stop": false,
"trailing_stop_positive": 0.0,
"trailing_stop_positive_offset": 0.0,
"trailing_only_offset_is_reached": 0.0,
"unfilledtimeout": {
"buy": 300,
"sell": 300
},
"exchange": {
"name": "binance",
"key": "",
"secret": "",
"ccxt_config": {
"enableRateLimit": true
},
"pair_whitelist": [
"BTC/USDT",
"ETH/USDT",
"SOL/USDT"
],
"pair_blacklist": []
},
"experimental": {
"use_sell_signal": true,
"ignore_roi_if_buy_signal": false
},
"telegram": {
"enabled": false,
"token": "",
"chat_id": ""
},
"api_server": {
"enabled": false,
"listen_ip_address": "127.0.0.1",
"listen_port": 8080,
"verbosity": "error",
"enable_openapi": false
},
"hyperopt": {
"enabled": false,
"epochs": 100,
"spaces": [
"buy",
"sell",
"roi",
"stoploss",
"trailing"
],
"hyperopt_path": "",
"hyperopt_loss": "SharpeHyperOptLossDaily",
"print_all": false,
"mongodb_url": "",
"mongodb_database": ""
}
}

View File

@ -67,9 +67,9 @@ services:
backtesting
--logfile /freqtrade/user_data/logs/freqtrade.log
--freqaimodel XGBoostRegressor
--config /freqtrade/config_examples/config_freqai.okx.json
--config /freqtrade/config_examples/config_base_hyperopt.json
--strategy-path /freqtrade/templates
--strategy OKXRegressionStrategy
--strategy SharpeHyperOptStrategy
--timerange 20250401-20250415
--fee 0.0008
--cache none

View File

@ -0,0 +1,190 @@
from freqtrade.strategy import IStrategy, IntParameter, RealParameter, DecimalParameter, BooleanParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from datetime import datetime
class BsseHyperOptStrategy(IStrategy):
# 策略的基本配置
timeframe = '5m'
minimal_roi = {"40": 0.0, "30": 0.01, "20": 0.02, "0": 0.04}
stoploss = -0.10
startup_candle_count = 20
# 可选的订单类型映射
order_types = {
"entry": "limit",
"exit": "limit",
"stoploss": "limit",
"stoploss_on_exchange": False,
}
# 可选的订单有效时间
order_time_in_force = {
"entry": "gtc",
"exit": "gtc",
}
# 可优化的参数
buy_rsi = IntParameter(30, 50, default=35, space='buy')
buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy')
sell_rsi = IntParameter(low=50, high=100, default=70, space='sell')
sell_minusdi = DecimalParameter(
low=0, high=1, default=0.5001, decimals=3, space='sell', load=False
)
protection_enabled = BooleanParameter(default=True)
protection_cooldown_lookback = IntParameter([0, 50], default=30)
@property
def protections(self):
prot = []
if self.protection_enabled.value:
prot.append(
{
"method": "CooldownPeriod",
"stop_duration_candles": self.protection_cooldown_lookback.value,
}
)
return prot
def bot_start(self):
pass
def informative_pairs(self):
return []
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# 动量指标
# ADX
dataframe["adx"] = ta.ADX(dataframe)
# MACD
macd = ta.MACD(dataframe)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
dataframe["macdhist"] = macd["macdhist"]
# 负向指标
dataframe["minus_di"] = ta.MINUS_DI(dataframe)
# 正向指标
dataframe["plus_di"] = ta.PLUS_DI(dataframe)
# RSI
dataframe["rsi"] = ta.RSI(dataframe)
# 快速随机指标
stoch_fast = ta.STOCHF(dataframe)
dataframe["fastd"] = stoch_fast["fastd"]
dataframe["fastk"] = stoch_fast["fastk"]
# 布林带
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["ema10"] = ta.EMA(dataframe, timeperiod=10)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe["rsi"] < self.buy_rsi.value)
& (dataframe["fastd"] < 35)
& (dataframe["adx"] > 30)
& (dataframe["plus_di"] > self.buy_plusdi.value)
)
| ((dataframe["adx"] > 65) & (dataframe["plus_di"] > self.buy_plusdi.value)),
"enter_long",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
(qtpylib.crossed_above(dataframe["rsi"], self.sell_rsi.value))
| (qtpylib.crossed_above(dataframe["fastd"], 70))
)
& (dataframe["adx"] > 10)
& (dataframe["minus_di"] > 0)
)
| ((dataframe["adx"] > 70) & (dataframe["minus_di"] > self.sell_minusdi.value)),
"exit_long",
] = 1
return dataframe
def leverage(
self,
pair: str,
current_time: datetime,
current_rate: float,
proposed_leverage: float,
max_leverage: float,
entry_tag: str | None,
side: str,
**kwargs,
) -> float:
return 3.0
def adjust_trade_position(
self,
trade,
current_time: datetime,
current_rate: float,
current_profit: float,
min_stake: float | None,
max_stake: float,
current_entry_rate: float,
current_exit_rate: float,
current_entry_profit: float,
current_exit_profit: float,
**kwargs,
) -> float | None:
if current_profit < -0.0075:
orders = trade.select_filled_orders(trade.entry_side)
return round(orders[0].stake_amount, 0)
return None
class HyperOpt:
def buy_indicator_space(self):
return [
self.strategy.buy_rsi.get_space('buy_rsi'),
self.strategy.buy_plusdi.get_space('buy_plusdi')
]
def sell_indicator_space(self):
return [
self.strategy.sell_rsi.get_space('sell_rsi'),
self.strategy.sell_minusdi.get_space('sell_minusdi')
]
def roi_space(self):
from skopt.space import Integer
return [
Integer(10, 120, name='roi_t1'),
Integer(10, 60, name='roi_t2'),
Integer(10, 40, name='roi_t3'),
]
def stoploss_space(self):
from skopt.space import Real
return [Real(-0.5, -0.01, name='stoploss')]
def trailing_space(self):
from skopt.space import Real, Categorical
return [
Categorical([True, False], name='trailing_stop'),
Real(0.01, 0.1, name='trailing_stop_positive'),
Real(0.0, 0.1, name='trailing_stop_positive_offset'),
Real(0.0, 0.1, name='trailing_only_offset_is_reached')
]
def max_open_trades_space(self):
from skopt.space import Integer
return [Integer(1, 10, name='max_open_trades')]``