线性映射加仓阈值
This commit is contained in:
parent
0b00430b9a
commit
eb1c40cbf5
@ -8,33 +8,33 @@
|
||||
"max_open_trades": 5
|
||||
},
|
||||
"buy": {
|
||||
"ADD_POSITION_THRESHOLD": -0.042,
|
||||
"BUY_THRESHOLD_MAX": -0.008,
|
||||
"BUY_THRESHOLD_MIN": -0.045,
|
||||
"COOLDOWN_PERIOD_MINUTES": 6,
|
||||
"MAX_ENTRY_POSITION_ADJUSTMENT": 2
|
||||
"ADD_POSITION_THRESHOLD": -0.01,
|
||||
"BUY_THRESHOLD_MAX": -0.011,
|
||||
"BUY_THRESHOLD_MIN": -0.079,
|
||||
"COOLDOWN_PERIOD_MINUTES": 8,
|
||||
"MAX_ENTRY_POSITION_ADJUSTMENT": 1
|
||||
},
|
||||
"sell": {
|
||||
"EXIT_POSITION_RATIO": 0.596,
|
||||
"SELL_THRESHOLD_MAX": 0.099,
|
||||
"SELL_THRESHOLD_MIN": 0.01,
|
||||
"TRAILING_STOP_DISTANCE": 0.02,
|
||||
"TRAILING_STOP_START": 0.048
|
||||
"EXIT_POSITION_RATIO": 0.341,
|
||||
"SELL_THRESHOLD_MAX": 0.082,
|
||||
"SELL_THRESHOLD_MIN": 0.012,
|
||||
"TRAILING_STOP_DISTANCE": 0.016,
|
||||
"TRAILING_STOP_START": 0.026
|
||||
},
|
||||
"protection": {},
|
||||
"roi": {
|
||||
"0": 0.081,
|
||||
"17": 0.058,
|
||||
"23": 0.01,
|
||||
"30": 0
|
||||
"0": 0.057,
|
||||
"15": 0.025,
|
||||
"22": 0.013,
|
||||
"39": 0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.054,
|
||||
"trailing_stop_positive_offset": 0.101,
|
||||
"trailing_only_offset_is_reached": true
|
||||
"trailing_stop_positive": 0.139,
|
||||
"trailing_stop_positive_offset": 0.23700000000000002,
|
||||
"trailing_only_offset_is_reached": false
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2025-06-21 14:12:39.140743+00:00"
|
||||
"export_time": "2025-06-22 18:22:25.969981+00:00"
|
||||
}
|
||||
@ -374,77 +374,114 @@ class FreqaiPrimer(IStrategy):
|
||||
current_entry_profit: float, current_exit_profit: float,
|
||||
**kwargs) -> float | None | tuple[float | None, str | None]:
|
||||
"""
|
||||
动态调整仓位:支持加仓和分批减仓
|
||||
动态调整仓位:支持加仓、减仓、追踪止损和最大持仓时间限制
|
||||
参数:
|
||||
- trade: 当前交易对象
|
||||
- current_time: 当前时间
|
||||
- current_rate: 当前价格
|
||||
- current_profit: 当前总盈利
|
||||
- min_stake: 最小下注金额
|
||||
- max_stake: 最大下注金额
|
||||
- current_entry_rate: 当前入场价格
|
||||
- current_exit_rate: 当前退出价格
|
||||
- current_entry_profit: 当前入场盈利
|
||||
- current_exit_profit: 当前退出盈利
|
||||
返回:
|
||||
- 调整金额(正数为加仓,负数为减仓)或 None
|
||||
"""
|
||||
pair = trade.pair
|
||||
dataframe = self.dp.get_pair_dataframe(pair, self.timeframe)
|
||||
trend_score = self.get_market_trend(dataframe=dataframe, metadata={'pair': pair})
|
||||
hold_time = (current_time - trade.open_date_utc).total_seconds() / 60
|
||||
market_trend_score = self.get_market_trend()
|
||||
profit_ratio = (current_rate - trade.open_rate) / trade.open_rate
|
||||
|
||||
# --- 加仓逻辑 ---
|
||||
max_entry_adjustments = self.MAX_ENTRY_POSITION_ADJUSTMENT.value
|
||||
if trade.nr_of_successful_entries <= max_entry_adjustments + 1: # +1 包括初始入场
|
||||
add_position_threshold = self.ADD_POSITION_THRESHOLD.value
|
||||
if profit_ratio <= add_position_threshold and hold_time > 5:
|
||||
if market_trend_score <= 60: # 熊市或中性更倾向加仓
|
||||
add_amount = 0.5 * trade.stake_amount # 加仓 50% 的初始仓位
|
||||
if min_stake is not None and add_amount < min_stake:
|
||||
logger.warning(f"[{pair}] 加仓金额 {add_amount:.2f} 低于最小下单金额 {min_stake},取消加仓")
|
||||
return (None, "Add amount below min_stake")
|
||||
if add_amount > max_stake:
|
||||
logger.warning(f"[{pair}] 加仓金额 {add_amount:.2f} 超出最大可用金额 {max_stake},取消加仓")
|
||||
return (None, "Add amount exceeds max_stake")
|
||||
logger.info(f"[{pair}] 价格下跌 {profit_ratio*100:.2f}%,触发加仓 {add_amount:.2f}")
|
||||
return (add_amount, f"Price dropped {profit_ratio*100:.2f}%")
|
||||
else:
|
||||
logger.debug(f"[{pair}] 价格下跌但市场趋势得分 {market_trend_score},不加仓")
|
||||
return None
|
||||
initial_stake_amount = trade.stake_amount / 3
|
||||
logger.debug(f"{pair} 首次入场金额: {initial_stake_amount:.2f}, 当前持仓金额: {trade.stake_amount:.2f}, "
|
||||
f"加仓次数: {trade.nr_of_successful_entries - 1}")
|
||||
|
||||
# --- 减仓逻辑 ---
|
||||
# 动态最大持仓时间
|
||||
# max_hold_time = self.MAX_HOLD_TIME_MINUTES.value
|
||||
# # 线性映射持仓时间因子
|
||||
# hold_factor = self.HOLD_TIME_REDUCTION.value + (self.HOLD_TIME_EXTENSION.value - self.HOLD_TIME_REDUCTION.value) * (trend_score / 100)
|
||||
# max_hold_time *= hold_factor
|
||||
# if profit_ratio > 0.02:
|
||||
# max_hold_time *= 1.2
|
||||
# elif profit_ratio < -0.02:
|
||||
# max_hold_time *= 0.8
|
||||
# max_hold_time = int(max_hold_time)
|
||||
|
||||
# 加仓逻辑
|
||||
max_entry_adjustments = self.MAX_ENTRY_POSITION_ADJUSTMENT.value
|
||||
if trade.nr_of_successful_entries <= max_entry_adjustments + 1:
|
||||
add_position_threshold = self.ADD_POSITION_THRESHOLD.value
|
||||
# 线性映射加仓阈值,趋势值越高,加仓越严格
|
||||
add_threshold = 80 - 30 * (trend_score / 100) # 趋势值 100 -> 50, 0 -> 80
|
||||
if profit_ratio <= add_position_threshold and hold_time > 5 and trend_score <= add_threshold:
|
||||
logger.debug(f"{pair} 初始下注金额: {initial_stake_amount:.2f}, trend_score: {trend_score:.2f}, add_threshold: {add_threshold} ")
|
||||
|
||||
# 计算加仓金额
|
||||
add_count = trade.nr_of_successful_entries - 1
|
||||
multipliers = [2, 4, 8]
|
||||
if add_count < len(multipliers):
|
||||
multiplier = multipliers[add_count]
|
||||
add_amount = initial_stake_amount * multiplier
|
||||
logger.debug(f"{pair} 第 {add_count + 1} 次加仓,倍数={multiplier}, "
|
||||
f"金额 = {initial_stake_amount:.2f} * {multiplier} = {add_amount:.2f}")
|
||||
logger.debug(f"{pair} 加仓计算: 第 {add_count + 1} 次加仓,倍数={multiplier}, "
|
||||
f"金额 = {initial_stake_amount:.2f} * {multiplier} = {add_amount:.2f}")
|
||||
|
||||
if min_stake is not None and add_amount < min_stake:
|
||||
logger.warning(f"{pair} 加仓金额 {add_amount:.2f} 低于最小下注金额 {min_stake:.2f},取消加仓")
|
||||
return (None, f"Add amount {add_amount:.2f} below min_stake {min_stake:.2f}")
|
||||
if add_amount > max_stake:
|
||||
logger.warning(f"{pair} 加仓金额 {add_amount:.2f} 超出最大可用金额 {max_stake:.2f},调整为 {max_stake:.2f}")
|
||||
add_amount = max_stake
|
||||
logger.info(f"{pair} 价格下跌 {profit_ratio*100:.2f}%,触发第 {add_count + 1} 次加仓 {add_amount:.2f}")
|
||||
return (add_amount, f"Price dropped {profit_ratio*100:.2f}%, add {add_amount:.2f}")
|
||||
|
||||
# 减仓逻辑
|
||||
exit_position_ratio = self.EXIT_POSITION_RATIO.value
|
||||
if profit_ratio >= 0.03: # 利润达到 3%
|
||||
if market_trend_score > 70: # 强牛市
|
||||
reduce_amount = -exit_position_ratio * 0.6 * trade.stake_amount # 减仓较少
|
||||
logger.info(f"[{pair}] 强牛市(得分 {market_trend_score}),利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
|
||||
return (reduce_amount, f"Strong bull market, profit {profit_ratio*100:.2f}%")
|
||||
else:
|
||||
reduce_amount = -exit_position_ratio * trade.stake_amount # 其他市场减仓较多
|
||||
logger.info(f"[{pair}] 利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
|
||||
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
|
||||
elif profit_ratio >= 0.05: # 利润达到 5%
|
||||
reduce_amount = -exit_position_ratio * 1.4 * trade.stake_amount # 卖出更多
|
||||
logger.info(f"[{pair}] 利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
|
||||
if profit_ratio >= 0.03:
|
||||
# 趋势值越高,减仓比例越低
|
||||
reduce_factor = 0.6 + 0.4 * (1 - trend_score / 100) # 牛市(100) -> 0.6, 熊市(0) -> 1.0
|
||||
reduce_amount = -exit_position_ratio * reduce_factor * trade.stake_amount
|
||||
logger.info(f"{pair} 趋势值 {trend_score:.2f},利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
|
||||
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
|
||||
elif profit_ratio >= 0.05:
|
||||
reduce_factor = 1.4 - 0.4 * (trend_score / 100) # 牛市(100) -> 1.0, 熊市(0) -> 1.4
|
||||
reduce_amount = -exit_position_ratio * reduce_factor * trade.stake_amount
|
||||
logger.info(f"{pair} 趋势值 {trend_score:.2f},利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
|
||||
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
|
||||
|
||||
# --- 追踪止损逻辑 ---
|
||||
# 追踪止损逻辑
|
||||
trailing_stop_start = self.TRAILING_STOP_START.value
|
||||
trailing_stop_distance = self.TRAILING_STOP_DISTANCE.value
|
||||
if market_trend_score > 70: # 强牛市
|
||||
trailing_stop_distance *= 1.5
|
||||
trailing_stop_start *= 1.2
|
||||
elif market_trend_score < 30: # 强熊市
|
||||
trailing_stop_distance *= 0.7
|
||||
trailing_stop_start *= 0.8
|
||||
# 使用 Sigmoid 映射调整追踪止损参数
|
||||
sigmoid = 1 / (1 + np.exp(-0.1 * (trend_score - 50)))
|
||||
trailing_factor = 0.8 + (1.2 - 0.8) * sigmoid # 牛市(100) -> 1.2, 熊市(0) -> 0.8
|
||||
distance_factor = 0.7 + (1.5 - 0.7) * sigmoid # 牛市(100) -> 1.5, 熊市(0) -> 0.7
|
||||
trailing_stop_start *= trailing_factor
|
||||
trailing_stop_distance *= distance_factor
|
||||
|
||||
if profit_ratio >= trailing_stop_start and not self.trailing_stop_enabled:
|
||||
self.trailing_stop_enabled = True
|
||||
trade.adjust_min_max_rates(current_rate, current_rate)
|
||||
logger.info(f"[{pair}] 价格上涨超过 {trailing_stop_start*100:.1f}%,启动 Trailing Stop")
|
||||
logger.info(f"{pair} 价格上涨超过 {trailing_stop_start*100:.1f}%,启动追踪止损")
|
||||
return None
|
||||
|
||||
if self.trailing_stop_enabled:
|
||||
max_rate = trade.max_rate
|
||||
max_rate = trade.max_rate or current_rate
|
||||
trailing_stop_price = max_rate * (1 - trailing_stop_distance)
|
||||
if current_rate < trailing_stop_price:
|
||||
logger.info(f"[{pair}] 价格回落至 Trailing Stop 点 {trailing_stop_price:.6f},触发全部卖出")
|
||||
logger.info(f"{pair} 价格回落至 {trailing_stop_price:.6f},触发全部卖出")
|
||||
return (-trade.stake_amount, f"Trailing stop at {trailing_stop_price:.6f}")
|
||||
trade.adjust_min_max_rates(current_rate, trade.min_rate)
|
||||
return None
|
||||
|
||||
# --- 最大持仓时间限制 ---
|
||||
if hold_time > 30:
|
||||
logger.info(f"[{pair}] 持仓时间超过30分钟,强制清仓")
|
||||
return (-trade.stake_amount, "Max hold time exceeded")
|
||||
# 最大持仓时间限制
|
||||
# if hold_time > max_hold_time:
|
||||
# logger.info(f"{pair} 趋势值 {trend_score:.2f},持仓时间超过 {max_hold_time} 分钟,强制清仓")
|
||||
# return (-trade.stake_amount, f"Max hold time ({max_hold_time} min) exceeded")
|
||||
|
||||
return None
|
||||
|
||||
@ -499,7 +536,8 @@ class FreqaiPrimer(IStrategy):
|
||||
logger.debug(f"[{pair}] 自定义卖出价:{adjusted_rate:.6f}(原价:{proposed_rate:.6f})")
|
||||
return adjusted_rate
|
||||
|
||||
def get_market_trend(self, dataframe: DataFrame = None) -> int:
|
||||
def get_market_trend(self, dataframe: DataFrame = None, metadata: dict = None) -> int:
|
||||
|
||||
"""
|
||||
计算市场趋势得分,0 表示强熊,100 表示强牛,50 表示中性。
|
||||
使用对数函数映射,非线性增强两端趋势。
|
||||
@ -512,6 +550,19 @@ class FreqaiPrimer(IStrategy):
|
||||
int: 0-100 的趋势得分。
|
||||
"""
|
||||
try:
|
||||
# 获取 BTC/USDT 数据
|
||||
if dataframe is None:
|
||||
btc_df = self.dp.get_pair_dataframe("BTC/USDT", self.timeframe)
|
||||
else:
|
||||
btc_df = dataframe
|
||||
|
||||
if len(btc_df) < 200:
|
||||
logger.warning("BTC 数据不足,返回默认趋势得分:50")
|
||||
return 50
|
||||
|
||||
# 示例:使用 metadata 记录币种信息
|
||||
pair = metadata.get('pair', 'Unknown') if metadata else 'Unknown'
|
||||
logger.debug(f"[{pair}] 正在计算市场趋势得分")
|
||||
# 获取 BTC/USDT 数据
|
||||
btc_df = dataframe if dataframe is not None else self.dp.get_pair_dataframe("BTC/USDT", self.timeframe)
|
||||
if len(btc_df) < 200:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user