use hyperopt to find optimal parameter values for indicators

This commit is contained in:
Janne Sinivirta 2017-10-19 17:12:49 +03:00
parent d4f8b3ebbc
commit 1792e0fb9b

View File

@ -0,0 +1,124 @@
# pragma pylint: disable=missing-docstring
import json
import logging
import os
from functools import reduce
import pytest
import arrow
from pandas import DataFrame
import hyperopt.pyll.stochastic
from hyperopt import fmin, tpe, hp
from freqtrade.analyze import analyze_ticker
from freqtrade.main import should_sell
from freqtrade.persistence import Trade
logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot
def print_results(results):
print('Made {} buys. Average profit {:.2f}%. Total profit was {:.3f}. Average duration {:.1f} mins.'.format(
len(results.index),
results.profit.mean() * 100.0,
results.profit.sum(),
results.duration.mean() * 5
))
@pytest.fixture
def pairs():
return ['btc-neo', 'btc-eth', 'btc-omg', 'btc-edg', 'btc-pay',
'btc-pivx', 'btc-qtum', 'btc-mtl', 'btc-etc', 'btc-ltc']
@pytest.fixture
def conf():
return {
"minimal_roi": {
"50": 0.0,
"40": 0.01,
"30": 0.02,
"0": 0.045
},
"stoploss": -0.40
}
def backtest(conf, pairs, mocker, buy_strategy):
trades = []
mocker.patch.dict('freqtrade.main._CONF', conf)
for pair in pairs:
with open('freqtrade/tests/testdata/'+pair+'.json') as data_file:
data = json.load(data_file)
mocker.patch('freqtrade.analyze.get_ticker_history', return_value=data)
mocker.patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00'))
mocker.patch('freqtrade.analyze.populate_buy_trend', side_effect=buy_strategy)
ticker = analyze_ticker(pair)
# for each buy point
for index, row in ticker[ticker.buy == 1].iterrows():
trade = Trade(
open_rate=row['close'],
open_date=arrow.get(row['date']).datetime,
amount=1,
)
# calculate win/lose forwards from buy point
for index2, row2 in ticker[index:].iterrows():
if should_sell(trade, row2['close'], arrow.get(row2['date']).datetime):
current_profit = (row2['close'] - trade.open_rate) / trade.open_rate
trades.append((pair, current_profit, index2 - index))
break
labels = ['currency', 'profit', 'duration']
results = DataFrame.from_records(trades, columns=labels)
print_results(results)
if len(results.index) < 800:
return 0
return results.profit.sum() / results.duration.mean()
def buy_strategy_generator(params):
print(params)
def populate_buy_trend(dataframe: DataFrame) -> DataFrame:
conditions = []
conditions.append(dataframe['close'] < dataframe['sma'])
conditions.append(dataframe['tema'] <= dataframe['blower'])
if params['mfi']['enabled']:
conditions.append(dataframe['mfi'] < params['mfi']['value'])
if params['fastd']['enabled']:
conditions.append(dataframe['fastd'] < params['fastd']['value'])
if params['adx']['enabled']:
conditions.append(dataframe['adx'] > params['adx']['value'])
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'buy'] = 1
dataframe.loc[dataframe['buy'] == 1, 'buy_price'] = dataframe['close']
return dataframe
return populate_buy_trend
@pytest.mark.skipif(not os.environ.get('BACKTEST', False), reason="BACKTEST not set")
def test_hyperopt(conf, pairs, mocker):
def optimizer(params):
return backtest(conf, pairs, mocker, buy_strategy_generator(params))
space = {
'mfi': hp.choice('mfi', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('mfi-value', 10, 50)}
]),
'fastd': hp.choice('fastd', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('fastd-value', 10, 50)}
]),
'adx': hp.choice('adx', [
{'enabled': False},
{'enabled': True, 'value': hp.uniform('adx-value', 10, 50)}
]),
}
# print(hyperopt.pyll.stochastic.sample(space))
print(fmin(fn=optimizer, space=space, algo=tpe.suggest, max_evals=2))