Added more error checking to strategy interface and tested/validated

This commit is contained in:
werkkrew 2021-03-13 13:26:29 -05:00
parent db5e038b0f
commit 9e92a641f5

View File

@ -10,6 +10,7 @@ from enum import Enum
from typing import Dict, List, NamedTuple, Optional, Tuple from typing import Dict, List, NamedTuple, Optional, Tuple
import arrow import arrow
import numpy as np
from pandas import DataFrame from pandas import DataFrame
from freqtrade.constants import ListPairsWithTimeframes from freqtrade.constants import ListPairsWithTimeframes
@ -636,39 +637,61 @@ class IStrategy(ABC):
""" """
dynamic_roi = self.dynamic_roi dynamic_roi = self.dynamic_roi
minimal_roi = self.minimal_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 not dynamic_roi:
if dynamic_roi['dynamic_roi_type'] == 'linear': return None, None
rate = (start - end) / dynamic_roi['dynamic_roi_time']
min_roi = max(end, start - (rate * trade_dur)) if 'dynamic_roi_type' in dynamic_roi and dynamic_roi['dynamic_roi_type'] \
# exponential decay: f(t) = start * e^(-rate*t) in ['linear', 'exponential', 'connect']:
elif dynamic_roi['dynamic_roi_type'] == 'exponential': roi_type = dynamic_roi['dynamic_roi_type']
min_roi = max(end, start * np.exp(-dynamic_roi['dynamic_roi_rate']*trade_dur)) # linear decay: f(t) = start - (rate * t)
elif dynamic_roi['dynamic_roi_type'] == 'connect': if roi_type == 'linear':
# connect the points in the defined table with lines if 'dynamic_roi_start' in dynamic_roi and 'dynamic_roi_end' in dynamic_roi and \
past_roi = list(filter(lambda x: x <= trade_dur, minimal_roi.keys())) 'dynamic_roi_time' in dynamic_roi:
next_roi = list(filter(lambda x: x > trade_dur, minimal_roi.keys())) start = dynamic_roi['dynamic_roi_start']
if not past_roi: end = dynamic_roi['dynamic_roi_end']
return None, None time = dynamic_roi['dynamic_roi_time']
current_entry = max(past_roi) rate = (start - end) / time
# if we are past the final point in the table, use that key/vaule pair min_roi = max(end, start - (rate * trade_dur))
if not next_roi: return trade_dur, min_roi
return current_entry, minimal_roi[current_entry] else:
# use the slope-intercept formula between the two points in the roi table we are between return None, None
else: # exponential decay: f(t) = start * e^(-rate*t)
elif roi_type == 'exponential':
if 'dynamic_roi_start' in dynamic_roi and 'dynamic_roi_end' in dynamic_roi and \
'dynamic_roi_rate' in dynamic_roi:
start = dynamic_roi['dynamic_roi_start']
end = dynamic_roi['dynamic_roi_end']
rate = dynamic_roi['dynamic_roi_rate']
min_roi = max(end, start * np.exp(-rate*trade_dur))
return trade_dur, min_roi
else:
return None, None
# "connect the dots" between the points on the minima_roi table
elif roi_type == 'connect':
if not minimal_roi:
return None, None
# figure out where we are in the defined roi table
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 we are past the final point in the table, use that key/vaule pair
if not past_roi:
return None, None
current_entry = max(past_roi)
if not next_roi:
return current_entry, minimal_roi[current_entry]
next_entry = min(next_roi) next_entry = min(next_roi)
# use the slope-intercept formula between the two points
# y = mx + b # y = mx + b
x1, y1 = current_entry, minimal_roi[current_entry] x1, y1 = current_entry, minimal_roi[current_entry]
x2, y2 = next_entry, minimal_roi[next_entry] x2, y2 = next_entry, minimal_roi[next_entry]
m = (y1-y2)/(x1-x2) m = (y1-y2)/(x1-x2)
b = (x1*y2 - x2*y1)/(x1-x2) b = (x1*y2 - x2*y1)/(x1-x2)
min_roi = (m * trade_dur) + b min_roi = (m * trade_dur) + b
return trade_dur, min_roi
else: else:
return None, None return None, None
return trade_dur, min_roi
def min_roi_reached_entry(self, trade_dur: int) -> Tuple[Optional[int], Optional[float]]: 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. Based on trade duration defines the ROI entry that may have been reached.
@ -691,7 +714,9 @@ class IStrategy(ABC):
""" """
# Check if time matches and current rate is above threshold # Check if time matches and current rate is above threshold
trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60) trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60)
if self.dynamic_roi and self.dynamic_roi['dynamic_roi_enabled']:
if self.dynamic_roi and 'dynamic_roi_enabled' in self.dynamic_roi \
and self.dynamic_roi['dynamic_roi_enabled']:
_, roi = self.min_roi_reached_dynamic(trade_dur) _, roi = self.min_roi_reached_dynamic(trade_dur)
else: else:
_, roi = self.min_roi_reached_entry(trade_dur) _, roi = self.min_roi_reached_entry(trade_dur)