Merge pull request #332 from gcarq/hyperopt_stoploss
Add stoploss to the hyperopt parameters
This commit is contained in:
commit
fa97a82568
@ -31,6 +31,10 @@ TOTAL_TRIES = None
|
|||||||
_CURRENT_TRIES = 0
|
_CURRENT_TRIES = 0
|
||||||
CURRENT_BEST_LOSS = 100
|
CURRENT_BEST_LOSS = 100
|
||||||
|
|
||||||
|
# max average trade duration in minutes
|
||||||
|
# if eval ends with higher value, we consider it a failed eval
|
||||||
|
MAX_ACCEPTED_TRADE_DURATION = 240
|
||||||
|
|
||||||
# this is expexted avg profit * expected trade count
|
# this is expexted avg profit * expected trade count
|
||||||
# for example 3.5%, 1100 trades, EXPECTED_MAX_PROFIT = 3.85
|
# for example 3.5%, 1100 trades, EXPECTED_MAX_PROFIT = 3.85
|
||||||
EXPECTED_MAX_PROFIT = 3.85
|
EXPECTED_MAX_PROFIT = 3.85
|
||||||
@ -91,6 +95,7 @@ SPACE = {
|
|||||||
{'type': 'stochf_cross'},
|
{'type': 'stochf_cross'},
|
||||||
{'type': 'ht_sine'},
|
{'type': 'ht_sine'},
|
||||||
]),
|
]),
|
||||||
|
'stoploss': hp.quniform('stoploss', -30, -2, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -109,11 +114,12 @@ def log_results(results):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
def calculate_loss(total_profit: float, trade_count: int):
|
def calculate_loss(total_profit: float, trade_count: int, trade_duration: float):
|
||||||
""" objective function, returns smaller number for more optimal results """
|
""" objective function, returns smaller number for more optimal results """
|
||||||
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
|
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
|
||||||
profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT)
|
profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT)
|
||||||
return trade_loss + profit_loss
|
duration_loss = min(trade_duration / MAX_ACCEPTED_TRADE_DURATION, 1)
|
||||||
|
return trade_loss + profit_loss + duration_loss
|
||||||
|
|
||||||
|
|
||||||
def optimizer(params):
|
def optimizer(params):
|
||||||
@ -122,20 +128,21 @@ def optimizer(params):
|
|||||||
from freqtrade.optimize import backtesting
|
from freqtrade.optimize import backtesting
|
||||||
backtesting.populate_buy_trend = buy_strategy_generator(params)
|
backtesting.populate_buy_trend = buy_strategy_generator(params)
|
||||||
|
|
||||||
results = backtest(OPTIMIZE_CONFIG['stake_amount'], PROCESSED)
|
results = backtest(OPTIMIZE_CONFIG['stake_amount'], PROCESSED, stoploss=params['stoploss'])
|
||||||
result_explanation = format_results(results)
|
result_explanation = format_results(results)
|
||||||
|
|
||||||
total_profit = results.profit_percent.sum()
|
total_profit = results.profit_percent.sum()
|
||||||
trade_count = len(results.index)
|
trade_count = len(results.index)
|
||||||
|
trade_duration = results.duration.mean() * 5
|
||||||
|
|
||||||
if trade_count == 0:
|
if trade_count == 0 or trade_duration > MAX_ACCEPTED_TRADE_DURATION:
|
||||||
print('.', end='')
|
print('.', end='')
|
||||||
return {
|
return {
|
||||||
'status': STATUS_FAIL,
|
'status': STATUS_FAIL,
|
||||||
'loss': float('inf')
|
'loss': float('inf')
|
||||||
}
|
}
|
||||||
|
|
||||||
loss = calculate_loss(total_profit, trade_count)
|
loss = calculate_loss(total_profit, trade_count, trade_duration)
|
||||||
|
|
||||||
_CURRENT_TRIES += 1
|
_CURRENT_TRIES += 1
|
||||||
|
|
||||||
|
@ -5,17 +5,23 @@ from freqtrade.optimize.hyperopt import calculate_loss, TARGET_TRADES, EXPECTED_
|
|||||||
|
|
||||||
|
|
||||||
def test_loss_calculation_prefer_correct_trade_count():
|
def test_loss_calculation_prefer_correct_trade_count():
|
||||||
correct = calculate_loss(1, TARGET_TRADES)
|
correct = calculate_loss(1, TARGET_TRADES, 20)
|
||||||
over = calculate_loss(1, TARGET_TRADES + 100)
|
over = calculate_loss(1, TARGET_TRADES + 100, 20)
|
||||||
under = calculate_loss(1, TARGET_TRADES - 100)
|
under = calculate_loss(1, TARGET_TRADES - 100, 20)
|
||||||
assert over > correct
|
assert over > correct
|
||||||
assert under > correct
|
assert under > correct
|
||||||
|
|
||||||
|
|
||||||
|
def test_loss_calculation_prefer_shorter_trades():
|
||||||
|
shorter = calculate_loss(1, 100, 20)
|
||||||
|
longer = calculate_loss(1, 100, 30)
|
||||||
|
assert shorter < longer
|
||||||
|
|
||||||
|
|
||||||
def test_loss_calculation_has_limited_profit():
|
def test_loss_calculation_has_limited_profit():
|
||||||
correct = calculate_loss(EXPECTED_MAX_PROFIT, TARGET_TRADES)
|
correct = calculate_loss(EXPECTED_MAX_PROFIT, TARGET_TRADES, 20)
|
||||||
over = calculate_loss(EXPECTED_MAX_PROFIT * 2, TARGET_TRADES)
|
over = calculate_loss(EXPECTED_MAX_PROFIT * 2, TARGET_TRADES, 20)
|
||||||
under = calculate_loss(EXPECTED_MAX_PROFIT / 2, TARGET_TRADES)
|
under = calculate_loss(EXPECTED_MAX_PROFIT / 2, TARGET_TRADES, 20)
|
||||||
assert over == correct
|
assert over == correct
|
||||||
assert under > correct
|
assert under > correct
|
||||||
|
|
||||||
@ -93,7 +99,8 @@ def test_fmin_best_results(mocker, caplog):
|
|||||||
"trigger": 2,
|
"trigger": 2,
|
||||||
"uptrend_long_ema": 1,
|
"uptrend_long_ema": 1,
|
||||||
"uptrend_short_ema": 0,
|
"uptrend_short_ema": 0,
|
||||||
"uptrend_sma": 0
|
"uptrend_sma": 0,
|
||||||
|
"stoploss": -10,
|
||||||
}
|
}
|
||||||
|
|
||||||
mocker.patch('freqtrade.optimize.hyperopt.MongoTrials', return_value=create_trials(mocker))
|
mocker.patch('freqtrade.optimize.hyperopt.MongoTrials', return_value=create_trials(mocker))
|
||||||
@ -109,7 +116,8 @@ def test_fmin_best_results(mocker, caplog):
|
|||||||
'"adx": {\n "enabled": true,\n "value": 15.0\n },',
|
'"adx": {\n "enabled": true,\n "value": 15.0\n },',
|
||||||
'"green_candle": {\n "enabled": true\n },',
|
'"green_candle": {\n "enabled": true\n },',
|
||||||
'"mfi": {\n "enabled": false\n },',
|
'"mfi": {\n "enabled": false\n },',
|
||||||
'"trigger": {\n "type": "ao_cross_zero"\n },'
|
'"trigger": {\n "type": "ao_cross_zero"\n },',
|
||||||
|
'"stoploss": -10.0',
|
||||||
]
|
]
|
||||||
|
|
||||||
for line in exists:
|
for line in exists:
|
||||||
|
Loading…
Reference in New Issue
Block a user