moved dynamic ROI to its own function in the strategy interface
This commit is contained in:
parent
39ffcecffa
commit
db5e038b0f
@ -628,55 +628,59 @@ class IStrategy(ABC):
|
||||
|
||||
return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE)
|
||||
|
||||
def min_roi_reached_dynamic(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
|
||||
"""
|
||||
Based on trade duration returns an ROI value based on various functions.
|
||||
:param trade_dur: trade duration in minutes
|
||||
:return: minimal ROI value or None if no proper ROI type was found.
|
||||
"""
|
||||
dynamic_roi = self.dynamic_roi
|
||||
minimal_roi = self.minimal_roi
|
||||
start, end = dynamic_roi['dynamic_roi_start'], dynamic_roi['dynamic_roi_end']
|
||||
|
||||
# linear decay: f(t) = start - (rate * t)
|
||||
if dynamic_roi['dynamic_roi_type'] == 'linear':
|
||||
rate = (start - end) / dynamic_roi['dynamic_roi_time']
|
||||
min_roi = max(end, start - (rate * trade_dur))
|
||||
# exponential decay: f(t) = start * e^(-rate*t)
|
||||
elif dynamic_roi['dynamic_roi_type'] == 'exponential':
|
||||
min_roi = max(end, start * np.exp(-dynamic_roi['dynamic_roi_rate']*trade_dur))
|
||||
elif dynamic_roi['dynamic_roi_type'] == 'connect':
|
||||
# connect the points in the defined table with lines
|
||||
past_roi = list(filter(lambda x: x <= trade_dur, minimal_roi.keys()))
|
||||
next_roi = list(filter(lambda x: x > trade_dur, minimal_roi.keys()))
|
||||
if not past_roi:
|
||||
return None, None
|
||||
current_entry = max(past_roi)
|
||||
# if we are past the final point in the table, use that key/vaule pair
|
||||
if not next_roi:
|
||||
return current_entry, minimal_roi[current_entry]
|
||||
# use the slope-intercept formula between the two points in the roi table we are between
|
||||
else:
|
||||
next_entry = min(next_roi)
|
||||
# y = mx + b
|
||||
x1, y1 = current_entry, minimal_roi[current_entry]
|
||||
x2, y2 = next_entry, minimal_roi[next_entry]
|
||||
m = (y1-y2)/(x1-x2)
|
||||
b = (x1*y2 - x2*y1)/(x1-x2)
|
||||
min_roi = (m * trade_dur) + b
|
||||
else:
|
||||
return None, None
|
||||
|
||||
return trade_dur, min_roi
|
||||
|
||||
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]:
|
||||
"""
|
||||
Based on trade duration defines the ROI entry that may have been reached.
|
||||
:param trade_dur: trade duration in minutes
|
||||
:return: minimal ROI entry value or None if none proper ROI entry was found.
|
||||
"""
|
||||
dynamic_roi = self.dynamic_roi
|
||||
minimal_roi = self.minimal_roi
|
||||
start, end = dynamic_roi['dynamic_roi_start'], dynamic_roi['dynamic_roi_end']
|
||||
|
||||
# if the dynamic_roi dict is defined and enabled, use it, otherwise fallback to default functionality
|
||||
if dynamic_roi and dynamic_roi['dynamic_roi_enabled']:
|
||||
# linear decay: f(t) = start - (rate * t)
|
||||
if dynamic_roi['dynamic_roi_type'] == 'linear':
|
||||
rate = (start - end) / dynamic_roi['dynamic_roi_time']
|
||||
min_roi = max(end, start - (rate * trade_dur))
|
||||
# exponential decay: f(t) = start * e^(-rate*t)
|
||||
elif dynamic_roi['dynamic_roi_type'] == 'exponential':
|
||||
min_roi = max(end, start * np.exp(-dynamic_roi['dynamic_roi_rate']*trade_dur))
|
||||
elif dynamic_roi['dynamic_roi_type'] == 'connect':
|
||||
# connect the points in the defined table with lines
|
||||
past_roi = list(filter(lambda x: x <= trade_dur, minimal_roi.keys()))
|
||||
next_roi = list(filter(lambda x: x > trade_dur, minimal_roi.keys()))
|
||||
if not past_roi:
|
||||
return None, None
|
||||
current_entry = max(past_roi)
|
||||
if not next_roi:
|
||||
return current_entry, minimal_roi[current_entry]
|
||||
# use the slope-intercept formula between the two points in the roi table we are between
|
||||
else:
|
||||
next_entry = min(next_roi)
|
||||
# y = mx + b
|
||||
x1, y1 = current_entry, minimal_roi[current_entry]
|
||||
x2, y2 = next_entry, minimal_roi[next_entry]
|
||||
m = (y1-y2)/(x1-x2)
|
||||
b = (x1*y2 - x2*y1)/(x1-x2)
|
||||
min_roi = (m * trade_dur) + b
|
||||
else:
|
||||
min_roi = 0
|
||||
|
||||
return trade_dur, min_roi
|
||||
# Default ROI table functionality
|
||||
else:
|
||||
# Get highest entry in ROI dict where key <= trade-duration
|
||||
roi_list = list(filter(lambda x: x <= trade_dur, self.minimal_roi.keys()))
|
||||
if not roi_list:
|
||||
return None, None
|
||||
roi_entry = max(roi_list)
|
||||
return roi_entry, self.minimal_roi[roi_entry]
|
||||
# Get highest entry in ROI dict where key <= trade-duration
|
||||
roi_list = list(filter(lambda x: x <= trade_dur, self.minimal_roi.keys()))
|
||||
if not roi_list:
|
||||
return None, None
|
||||
roi_entry = max(roi_list)
|
||||
return roi_entry, self.minimal_roi[roi_entry]
|
||||
|
||||
def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool:
|
||||
"""
|
||||
@ -687,7 +691,10 @@ class IStrategy(ABC):
|
||||
"""
|
||||
# Check if time matches and current rate is above threshold
|
||||
trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60)
|
||||
_, roi = self.min_roi_reached_entry(trade_dur)
|
||||
if self.dynamic_roi and self.dynamic_roi['dynamic_roi_enabled']:
|
||||
_, roi = self.min_roi_reached_dynamic(trade_dur)
|
||||
else:
|
||||
_, roi = self.min_roi_reached_entry(trade_dur)
|
||||
if roi is None:
|
||||
return False
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user