|
|
|
|
@ -1205,6 +1205,35 @@ class LocalTrade:
|
|
|
|
|
|
|
|
|
|
return float(f"{profit_ratio:.8f}")
|
|
|
|
|
|
|
|
|
|
def calc_close_rate_for_roi(self, target_roi: float) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Calculate the required close price to reach a target ROI.
|
|
|
|
|
Matches the logic used in `calc_profit_ratio()`.
|
|
|
|
|
|
|
|
|
|
:param target_roi: The desired return on investment (as a decimal, e.g., 0.05 for 5%)
|
|
|
|
|
:return: Close price (rate) required to achieve the target ROI
|
|
|
|
|
"""
|
|
|
|
|
leverage = float(self.leverage or 1.0)
|
|
|
|
|
deleveraged_roi = float(target_roi) / leverage
|
|
|
|
|
|
|
|
|
|
open_value = self._calc_open_trade_value(self.amount, self.open_rate)
|
|
|
|
|
|
|
|
|
|
# The ROI formula uses close_value(rate), which depends on trading mode:
|
|
|
|
|
# - SPOT: linear in rate, adjusted by close fee
|
|
|
|
|
# - MARGIN: same, but long subtracts interest, short increases amount
|
|
|
|
|
# - FUTURES: adds/subtracts funding to/from close value
|
|
|
|
|
# All cases are affine in rate:
|
|
|
|
|
# close_value(rate) = a * rate + b
|
|
|
|
|
# We extract a and b by probing close_value at rate = 0 and 1.
|
|
|
|
|
value_at_0 = self.calc_close_trade_value(0.0)
|
|
|
|
|
value_at_1 = self.calc_close_trade_value(1.0)
|
|
|
|
|
alpha = value_at_1 - value_at_0
|
|
|
|
|
beta = value_at_0
|
|
|
|
|
|
|
|
|
|
s = -1.0 if self.is_short else 1.0
|
|
|
|
|
adj = 1.0 + (deleveraged_roi / s)
|
|
|
|
|
return (adj * open_value - beta) / alpha
|
|
|
|
|
|
|
|
|
|
def recalc_trade_from_orders(self, *, is_closing: bool = False):
|
|
|
|
|
ZERO = FtPrecise(0.0)
|
|
|
|
|
current_amount = FtPrecise(0.0)
|
|
|
|
|
|