Merge branch 'develop' into no-ticker-2
This commit is contained in:
commit
51f52c8609
@ -23,7 +23,7 @@
|
||||
"ask_strategy":{
|
||||
"use_order_book": false,
|
||||
"order_book_min": 1,
|
||||
"order_book_max": 9,
|
||||
"order_book_max": 1,
|
||||
"use_sell_signal": true,
|
||||
"sell_profit_only": false,
|
||||
"ignore_roi_if_buy_signal": false
|
||||
|
@ -23,7 +23,7 @@
|
||||
"ask_strategy":{
|
||||
"use_order_book": false,
|
||||
"order_book_min": 1,
|
||||
"order_book_max": 9,
|
||||
"order_book_max": 1,
|
||||
"use_sell_signal": true,
|
||||
"sell_profit_only": false,
|
||||
"ignore_roi_if_buy_signal": false
|
||||
|
@ -38,7 +38,7 @@
|
||||
"price_side": "ask",
|
||||
"use_order_book": false,
|
||||
"order_book_min": 1,
|
||||
"order_book_max": 9,
|
||||
"order_book_max": 1,
|
||||
"use_sell_signal": true,
|
||||
"sell_profit_only": false,
|
||||
"ignore_roi_if_buy_signal": false
|
||||
|
@ -23,7 +23,7 @@
|
||||
"ask_strategy":{
|
||||
"use_order_book": false,
|
||||
"order_book_min": 1,
|
||||
"order_book_max": 9,
|
||||
"order_book_max": 1,
|
||||
"use_sell_signal": true,
|
||||
"sell_profit_only": false,
|
||||
"ignore_roi_if_buy_signal": false
|
||||
|
@ -536,8 +536,14 @@ The idea here is to place the sell order early, to be ahead in the queue.
|
||||
|
||||
A fixed slot (mirroring `bid_strategy.order_book_top`) can be defined by setting `ask_strategy.order_book_min` and `ask_strategy.order_book_max` to the same number.
|
||||
|
||||
!!! Warning "Orderbook and stoploss_on_exchange"
|
||||
Using `ask_strategy.order_book_max` higher than 1 may increase the risk, since an eventual [stoploss on exchange](#understand-order_types) will be needed to be cancelled as soon as the order is placed.
|
||||
!!! Warning "Order_book_max > 1 - increased risks for stoplosses!"
|
||||
Using `ask_strategy.order_book_max` higher than 1 will increase the risk the stoploss on exchange is cancelled too early, since an eventual [stoploss on exchange](#understand-order_types) will be cancelled as soon as the order is placed.
|
||||
Also, the sell order will remain on the exchange for `unfilledtimeout.sell` (or until it's filled) - which can lead to missed stoplosses (with or without using stoploss on exchange).
|
||||
|
||||
!!! Warning "Order_book_max > 1 in dry-run"
|
||||
Using `ask_strategy.order_book_max` higher than 1 will result in improper dry-run results (significantly better than real orders executed on exchange), since dry-run assumes orders to be filled almost instantly.
|
||||
It is therefore advised to not use this setting for dry-runs.
|
||||
|
||||
|
||||
#### Sell price without Orderbook enabled
|
||||
|
||||
|
@ -160,6 +160,9 @@ So let's write the buy strategy using these values:
|
||||
dataframe['macd'], dataframe['macdsignal']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
|
@ -429,6 +429,7 @@ usage: freqtrade hyperopt-list [-h] [-v] [--logfile FILE] [-V] [-c PATH]
|
||||
[--min-total-profit FLOAT]
|
||||
[--max-total-profit FLOAT] [--no-color]
|
||||
[--print-json] [--no-details]
|
||||
[--export-csv FILE]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
@ -450,6 +451,8 @@ optional arguments:
|
||||
useful if you are redirecting output to a file.
|
||||
--print-json Print best result detailization in JSON format.
|
||||
--no-details Do not print best epoch details.
|
||||
--export-csv FILE Export to CSV-File. This will disable table print.
|
||||
Example: --export-csv hyperopt.csv
|
||||
|
||||
Common arguments:
|
||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||
@ -458,9 +461,10 @@ Common arguments:
|
||||
details.
|
||||
-V, --version show program's version number and exit
|
||||
-c PATH, --config PATH
|
||||
Specify configuration file (default: `config.json`).
|
||||
Multiple --config options may be used. Can be set to
|
||||
`-` to read config from stdin.
|
||||
Specify configuration file (default:
|
||||
`userdir/config.json` or `config.json` whichever
|
||||
exists). Multiple --config options may be used. Can be
|
||||
set to `-` to read config from stdin.
|
||||
-d PATH, --datadir PATH
|
||||
Path to directory with historical backtesting data.
|
||||
--userdir PATH, --user-data-dir PATH
|
||||
|
@ -69,7 +69,8 @@ ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable",
|
||||
"hyperopt_list_min_avg_time", "hyperopt_list_max_avg_time",
|
||||
"hyperopt_list_min_avg_profit", "hyperopt_list_max_avg_profit",
|
||||
"hyperopt_list_min_total_profit", "hyperopt_list_max_total_profit",
|
||||
"print_colorized", "print_json", "hyperopt_list_no_details"]
|
||||
"print_colorized", "print_json", "hyperopt_list_no_details",
|
||||
"export_csv"]
|
||||
|
||||
ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index",
|
||||
"print_json", "hyperopt_show_no_header"]
|
||||
|
@ -221,6 +221,13 @@ AVAILABLE_CLI_OPTIONS = {
|
||||
action='store_true',
|
||||
default=False,
|
||||
),
|
||||
"export_csv": Arg(
|
||||
'--export-csv',
|
||||
help='Export to CSV-File.'
|
||||
' This will disable table print.'
|
||||
' Example: --export-csv hyperopt.csv',
|
||||
metavar='FILE',
|
||||
),
|
||||
"hyperopt_jobs": Arg(
|
||||
'-j', '--job-workers',
|
||||
help='The number of concurrently running jobs for hyperoptimization '
|
||||
|
@ -21,6 +21,7 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
|
||||
|
||||
print_colorized = config.get('print_colorized', False)
|
||||
print_json = config.get('print_json', False)
|
||||
export_csv = config.get('export_csv', None)
|
||||
no_details = config.get('hyperopt_list_no_details', False)
|
||||
no_header = False
|
||||
|
||||
@ -49,6 +50,7 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
|
||||
if print_colorized:
|
||||
colorama_init(autoreset=True)
|
||||
|
||||
if not export_csv:
|
||||
try:
|
||||
Hyperopt.print_result_table(config, trials, total_epochs,
|
||||
not filteroptions['only_best'], print_colorized, 0)
|
||||
@ -60,6 +62,11 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
|
||||
results = sorted_trials[0]
|
||||
Hyperopt.print_epoch_details(results, total_epochs, print_json, no_header)
|
||||
|
||||
if trials and export_csv:
|
||||
Hyperopt.export_csv_file(
|
||||
config, trials, total_epochs, not filteroptions['only_best'], export_csv
|
||||
)
|
||||
|
||||
|
||||
def start_hyperopt_show(args: Dict[str, Any]) -> None:
|
||||
"""
|
||||
|
@ -17,10 +17,15 @@ def setup_optimize_configuration(args: Dict[str, Any], method: RunMode) -> Dict[
|
||||
"""
|
||||
config = setup_utils_configuration(args, method)
|
||||
|
||||
if method == RunMode.BACKTEST:
|
||||
if config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT:
|
||||
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
||||
constants.UNLIMITED_STAKE_AMOUNT)
|
||||
no_unlimited_runmodes = {
|
||||
RunMode.BACKTEST: 'backtesting',
|
||||
RunMode.HYPEROPT: 'hyperoptimization',
|
||||
}
|
||||
if (method in no_unlimited_runmodes.keys() and
|
||||
config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT):
|
||||
raise DependencyException(
|
||||
f'The value of `stake_amount` cannot be set as "{constants.UNLIMITED_STAKE_AMOUNT}" '
|
||||
f'for {no_unlimited_runmodes[method]}')
|
||||
|
||||
return config
|
||||
|
||||
|
@ -282,6 +282,9 @@ class Configuration:
|
||||
self._args_to_config(config, argname='print_json',
|
||||
logstring='Parameter --print-json detected ...')
|
||||
|
||||
self._args_to_config(config, argname='export_csv',
|
||||
logstring='Parameter --export-csv detected: {}')
|
||||
|
||||
self._args_to_config(config, argname='hyperopt_jobs',
|
||||
logstring='Parameter -j/--job-workers detected: {}')
|
||||
|
||||
|
@ -145,27 +145,40 @@ class IDataHandler(ABC):
|
||||
if startup_candles > 0 and timerange_startup:
|
||||
timerange_startup.subtract_start(timeframe_to_seconds(timeframe) * startup_candles)
|
||||
|
||||
df = self._ohlcv_load(pair, timeframe, timerange=timerange_startup)
|
||||
if df.empty:
|
||||
pairdf = self._ohlcv_load(pair, timeframe,
|
||||
timerange=timerange_startup)
|
||||
if self._check_empty_df(pairdf, pair, timeframe, warn_no_data):
|
||||
return pairdf
|
||||
else:
|
||||
enddate = df.iloc[-1]['date']
|
||||
|
||||
if timerange_startup:
|
||||
self._validate_pairdata(pair, pairdf, timerange_startup)
|
||||
pairdf = trim_dataframe(pairdf, timerange_startup)
|
||||
if self._check_empty_df(pairdf, pair, timeframe, warn_no_data):
|
||||
return pairdf
|
||||
|
||||
# incomplete candles should only be dropped if we didn't trim the end beforehand.
|
||||
pairdf = clean_ohlcv_dataframe(pairdf, timeframe,
|
||||
pair=pair,
|
||||
fill_missing=fill_missing,
|
||||
drop_incomplete=(drop_incomplete and
|
||||
enddate == pairdf.iloc[-1]['date']))
|
||||
self._check_empty_df(pairdf, pair, timeframe, warn_no_data)
|
||||
return pairdf
|
||||
|
||||
def _check_empty_df(self, pairdf: DataFrame, pair: str, timeframe: str, warn_no_data: bool):
|
||||
"""
|
||||
Warn on empty dataframe
|
||||
"""
|
||||
if pairdf.empty:
|
||||
if warn_no_data:
|
||||
logger.warning(
|
||||
f'No history data for pair: "{pair}", timeframe: {timeframe}. '
|
||||
'Use `freqtrade download-data` to download the data'
|
||||
)
|
||||
return df
|
||||
else:
|
||||
enddate = df.iloc[-1]['date']
|
||||
|
||||
if timerange_startup:
|
||||
self._validate_pairdata(pair, df, timerange_startup)
|
||||
df = trim_dataframe(df, timerange_startup)
|
||||
|
||||
# incomplete candles should only be dropped if we didn't trim the end beforehand.
|
||||
return clean_ohlcv_dataframe(df, timeframe,
|
||||
pair=pair,
|
||||
fill_missing=fill_missing,
|
||||
drop_incomplete=(drop_incomplete and
|
||||
enddate == df.iloc[-1]['date']))
|
||||
return True
|
||||
return False
|
||||
|
||||
def _validate_pairdata(self, pair, pairdata: DataFrame, timerange: TimeRange):
|
||||
"""
|
||||
|
@ -23,6 +23,8 @@ from joblib import (Parallel, cpu_count, delayed, dump, load,
|
||||
wrap_non_picklable_objects)
|
||||
from pandas import DataFrame, json_normalize, isna
|
||||
import tabulate
|
||||
from os import path
|
||||
import io
|
||||
|
||||
from freqtrade.data.converter import trim_dataframe
|
||||
from freqtrade.data.history import get_timerange
|
||||
@ -330,10 +332,10 @@ class Hyperopt:
|
||||
lambda x: '{}/{}'.format(str(x).rjust(len(str(total_epochs)), ' '), total_epochs)
|
||||
)
|
||||
trials['Avg profit'] = trials['Avg profit'].apply(
|
||||
lambda x: ('{:,.2f}%'.format(x)).rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')
|
||||
lambda x: '{:,.2f}%'.format(x).rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')
|
||||
)
|
||||
trials['Avg duration'] = trials['Avg duration'].apply(
|
||||
lambda x: ('{:,.1f} m'.format(x)).rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')
|
||||
lambda x: '{:,.1f} m'.format(x).rjust(7, ' ') if not isna(x) else "--".rjust(7, ' ')
|
||||
)
|
||||
trials['Objective'] = trials['Objective'].apply(
|
||||
lambda x: '{:,.5f}'.format(x).rjust(8, ' ') if x != 100000 else "N/A".rjust(8, ' ')
|
||||
@ -381,6 +383,62 @@ class Hyperopt:
|
||||
)
|
||||
print(table)
|
||||
|
||||
@staticmethod
|
||||
def export_csv_file(config: dict, results: list, total_epochs: int, highlight_best: bool,
|
||||
csv_file: str) -> None:
|
||||
"""
|
||||
Log result to csv-file
|
||||
"""
|
||||
if not results:
|
||||
return
|
||||
|
||||
# Verification for overwrite
|
||||
if path.isfile(csv_file):
|
||||
logger.error("CSV-File already exists!")
|
||||
return
|
||||
|
||||
try:
|
||||
io.open(csv_file, 'w+').close()
|
||||
except IOError:
|
||||
logger.error("Filed to create CSV-File!")
|
||||
return
|
||||
|
||||
trials = json_normalize(results, max_level=1)
|
||||
trials['Best'] = ''
|
||||
trials['Stake currency'] = config['stake_currency']
|
||||
trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count',
|
||||
'results_metrics.avg_profit', 'results_metrics.total_profit',
|
||||
'Stake currency', 'results_metrics.profit', 'results_metrics.duration',
|
||||
'loss', 'is_initial_point', 'is_best']]
|
||||
trials.columns = ['Best', 'Epoch', 'Trades', 'Avg profit', 'Total profit', 'Stake currency',
|
||||
'Profit', 'Avg duration', 'Objective', 'is_initial_point', 'is_best']
|
||||
trials['is_profit'] = False
|
||||
trials.loc[trials['is_initial_point'], 'Best'] = '*'
|
||||
trials.loc[trials['is_best'], 'Best'] = 'Best'
|
||||
trials.loc[trials['Total profit'] > 0, 'is_profit'] = True
|
||||
trials['Epoch'] = trials['Epoch'].astype(str)
|
||||
trials['Trades'] = trials['Trades'].astype(str)
|
||||
|
||||
trials['Total profit'] = trials['Total profit'].apply(
|
||||
lambda x: '{:,.8f}'.format(x) if x != 0.0 else ""
|
||||
)
|
||||
trials['Profit'] = trials['Profit'].apply(
|
||||
lambda x: '{:,.2f}'.format(x) if not isna(x) else ""
|
||||
)
|
||||
trials['Avg profit'] = trials['Avg profit'].apply(
|
||||
lambda x: '{:,.2f}%'.format(x) if not isna(x) else ""
|
||||
)
|
||||
trials['Avg duration'] = trials['Avg duration'].apply(
|
||||
lambda x: '{:,.1f} m'.format(x) if not isna(x) else ""
|
||||
)
|
||||
trials['Objective'] = trials['Objective'].apply(
|
||||
lambda x: '{:,.5f}'.format(x) if x != 100000 else ""
|
||||
)
|
||||
|
||||
trials = trials.drop(columns=['is_initial_point', 'is_best', 'is_profit'])
|
||||
trials.to_csv(csv_file, index=False, header=True, mode='w', encoding='UTF-8')
|
||||
print("CSV-File created!")
|
||||
|
||||
def has_space(self, space: str) -> bool:
|
||||
"""
|
||||
Tell if the space value is contained in the configuration
|
||||
|
@ -36,7 +36,7 @@ class SharpeHyperOptLoss(IHyperOptLoss):
|
||||
expected_returns_mean = total_profit.sum() / days_period
|
||||
up_stdev = np.std(total_profit)
|
||||
|
||||
if (np.std(total_profit) != 0.):
|
||||
if up_stdev != 0:
|
||||
sharp_ratio = expected_returns_mean / up_stdev * np.sqrt(365)
|
||||
else:
|
||||
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||
|
@ -51,7 +51,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss):
|
||||
expected_returns_mean = total_profit.mean()
|
||||
up_stdev = total_profit.std()
|
||||
|
||||
if (up_stdev != 0.):
|
||||
if up_stdev != 0:
|
||||
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(days_in_year)
|
||||
else:
|
||||
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||
|
@ -39,7 +39,7 @@ class SortinoHyperOptLoss(IHyperOptLoss):
|
||||
results.loc[total_profit < 0, 'downside_returns'] = results['profit_percent']
|
||||
down_stdev = np.std(results['downside_returns'])
|
||||
|
||||
if np.std(total_profit) != 0.0:
|
||||
if down_stdev != 0:
|
||||
sortino_ratio = expected_returns_mean / down_stdev * np.sqrt(365)
|
||||
else:
|
||||
# Define high (negative) sortino ratio to be clear that this is NOT optimal.
|
||||
|
@ -59,7 +59,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss):
|
||||
# where P = sum_daily["profit_percent_after_slippage"]
|
||||
down_stdev = math.sqrt((total_downside**2).sum() / len(total_downside))
|
||||
|
||||
if (down_stdev != 0.):
|
||||
if down_stdev != 0:
|
||||
sortino_ratio = expected_returns_mean / down_stdev * math.sqrt(days_in_year)
|
||||
else:
|
||||
# Define high (negative) sortino ratio to be clear that this is NOT optimal.
|
||||
|
@ -67,21 +67,37 @@ class IPairList(ABC):
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def verify_blacklist(pairlist: List[str], blacklist: List[str]) -> List[str]:
|
||||
def verify_blacklist(pairlist: List[str], blacklist: List[str],
|
||||
aswarning: bool) -> List[str]:
|
||||
"""
|
||||
Verify and remove items from pairlist - returning a filtered pairlist.
|
||||
Logs a warning or info depending on `aswarning`.
|
||||
Pairlists explicitly using this method shall use `aswarning=False`!
|
||||
:param pairlist: Pairlist to validate
|
||||
:param blacklist: Blacklist to validate pairlist against
|
||||
:param aswarning: Log message as Warning or info
|
||||
:return: pairlist - blacklisted pairs
|
||||
"""
|
||||
for pair in deepcopy(pairlist):
|
||||
if pair in blacklist:
|
||||
if aswarning:
|
||||
logger.warning(f"Pair {pair} in your blacklist. Removing it from whitelist...")
|
||||
else:
|
||||
logger.info(f"Pair {pair} in your blacklist. Removing it from whitelist...")
|
||||
pairlist.remove(pair)
|
||||
return pairlist
|
||||
|
||||
def _verify_blacklist(self, pairlist: List[str]) -> List[str]:
|
||||
def _verify_blacklist(self, pairlist: List[str], aswarning: bool = True) -> List[str]:
|
||||
"""
|
||||
Proxy method to verify_blacklist for easy access for child classes.
|
||||
Logs a warning or info depending on `aswarning`.
|
||||
Pairlists explicitly using this method shall use aswarning=False!
|
||||
:param pairlist: Pairlist to validate
|
||||
:param aswarning: Log message as Warning or info.
|
||||
:return: pairlist - blacklisted pairs
|
||||
"""
|
||||
return IPairList.verify_blacklist(pairlist, self._pairlistmanager.blacklist)
|
||||
return IPairList.verify_blacklist(pairlist, self._pairlistmanager.blacklist,
|
||||
aswarning=aswarning)
|
||||
|
||||
def _whitelist_for_active_markets(self, pairlist: List[str]) -> List[str]:
|
||||
"""
|
||||
@ -113,6 +129,5 @@ class IPairList(ABC):
|
||||
if pair not in sanitized_whitelist:
|
||||
sanitized_whitelist.append(pair)
|
||||
|
||||
sanitized_whitelist = self._verify_blacklist(sanitized_whitelist)
|
||||
# We need to remove pairs that are unknown
|
||||
return sanitized_whitelist
|
||||
|
@ -106,7 +106,7 @@ class VolumePairList(IPairList):
|
||||
|
||||
# Validate whitelist to only have active market pairs
|
||||
pairs = self._whitelist_for_active_markets([s['symbol'] for s in sorted_tickers])
|
||||
pairs = self._verify_blacklist(pairs)
|
||||
pairs = self._verify_blacklist(pairs, aswarning=False)
|
||||
# Limit to X number of pairs
|
||||
pairs = pairs[:self._number_pairs]
|
||||
logger.info(f"Searching {self._number_pairs} pairs: {pairs}")
|
||||
|
@ -91,6 +91,6 @@ class PairListManager():
|
||||
pairlist = pl.filter_pairlist(pairlist, tickers)
|
||||
|
||||
# Validation against blacklist happens after the pairlists to ensure blacklist is respected.
|
||||
pairlist = IPairList.verify_blacklist(pairlist, self.blacklist)
|
||||
pairlist = IPairList.verify_blacklist(pairlist, self.blacklist, True)
|
||||
|
||||
self._whitelist = pairlist
|
||||
|
@ -24,7 +24,7 @@
|
||||
"price_side": "ask",
|
||||
"use_order_book": false,
|
||||
"order_book_min": 1,
|
||||
"order_book_max": 9,
|
||||
"order_book_max": 1,
|
||||
"use_sell_signal": true,
|
||||
"sell_profit_only": false,
|
||||
"ignore_roi_if_buy_signal": false
|
||||
|
@ -21,7 +21,7 @@ class {{ hyperopt }}(IHyperOpt):
|
||||
"""
|
||||
This is a Hyperopt template to get you started.
|
||||
|
||||
More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Add any lib you need to build your hyperopt.
|
||||
@ -29,11 +29,14 @@ class {{ hyperopt }}(IHyperOpt):
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The roi_space, generate_roi_table, stoploss_space methods are no longer required to be
|
||||
copied in every custom hyperopt. However, you may override them if you need the
|
||||
'roi' and the 'stoploss' spaces that differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods can be found in
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/user_data/hyperopts/sample_hyperopt_advanced.py
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need 'roi' and 'stoploss' spaces that
|
||||
differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods will be copied to `user_data/hyperopts` when
|
||||
creating the user-data directory using `freqtrade create-userdir --userdir user_data`,
|
||||
or is available online under the following URL:
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@ -63,6 +66,9 @@ class {{ hyperopt }}(IHyperOpt):
|
||||
dataframe['close'], dataframe['sar']
|
||||
))
|
||||
|
||||
# Check that the candle had volume
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
@ -108,6 +114,9 @@ class {{ hyperopt }}(IHyperOpt):
|
||||
dataframe['sar'], dataframe['close']
|
||||
))
|
||||
|
||||
# Check that the candle had volume
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
|
@ -20,23 +20,28 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
class SampleHyperOpt(IHyperOpt):
|
||||
"""
|
||||
This is a sample Hyperopt to inspire you.
|
||||
Feel free to customize it.
|
||||
|
||||
More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Rename the class name to some unique name.
|
||||
- Add any methods you want to build your hyperopt.
|
||||
- Add any lib you need to build your hyperopt.
|
||||
|
||||
An easier way to get a new hyperopt file is by using
|
||||
`freqtrade new-hyperopt --hyperopt MyCoolHyperopt`.
|
||||
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The roi_space, generate_roi_table, stoploss_space methods are no longer required to be
|
||||
copied in every custom hyperopt. However, you may override them if you need the
|
||||
'roi' and the 'stoploss' spaces that differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods can be found in
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/user_data/hyperopts/sample_hyperopt_advanced.py
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need 'roi' and 'stoploss' spaces that
|
||||
differ from the defaults offered by Freqtrade.
|
||||
Sample implementation of these methods will be copied to `user_data/hyperopts` when
|
||||
creating the user-data directory using `freqtrade create-userdir --userdir user_data`,
|
||||
or is available online under the following URL:
|
||||
https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@ -73,6 +78,9 @@ class SampleHyperOpt(IHyperOpt):
|
||||
dataframe['close'], dataframe['sar']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
@ -133,6 +141,9 @@ class SampleHyperOpt(IHyperOpt):
|
||||
dataframe['sar'], dataframe['close']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
|
@ -22,7 +22,7 @@ class AdvancedSampleHyperOpt(IHyperOpt):
|
||||
This is a sample hyperopt to inspire you.
|
||||
Feel free to customize it.
|
||||
|
||||
More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md
|
||||
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||
|
||||
You should:
|
||||
- Rename the class name to some unique name.
|
||||
@ -32,8 +32,9 @@ class AdvancedSampleHyperOpt(IHyperOpt):
|
||||
You must keep:
|
||||
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||
|
||||
The roi_space, generate_roi_table, stoploss_space methods are no longer required to be
|
||||
copied in every custom hyperopt. However, you may override them if you need the
|
||||
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||
and are provided by default.
|
||||
However, you may override them if you need the
|
||||
'roi' and the 'stoploss' spaces that differ from the defaults offered by Freqtrade.
|
||||
|
||||
This sample illustrates how to override these methods.
|
||||
@ -92,6 +93,9 @@ class AdvancedSampleHyperOpt(IHyperOpt):
|
||||
dataframe['close'], dataframe['sar']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
@ -152,6 +156,9 @@ class AdvancedSampleHyperOpt(IHyperOpt):
|
||||
dataframe['sar'], dataframe['close']
|
||||
))
|
||||
|
||||
# Check that volume is not 0
|
||||
conditions.append(dataframe['volume'] > 0)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
|
@ -1,13 +1,13 @@
|
||||
# requirements without requirements installable via conda
|
||||
# mainly used for Raspberry pi installs
|
||||
ccxt==1.23.30
|
||||
ccxt==1.23.81
|
||||
SQLAlchemy==1.3.13
|
||||
python-telegram-bot==12.4.2
|
||||
arrow==0.15.5
|
||||
cachetools==4.0.0
|
||||
requests==2.23.0
|
||||
urllib3==1.25.8
|
||||
wrapt==1.12.0
|
||||
wrapt==1.12.1
|
||||
jsonschema==3.2.0
|
||||
TA-Lib==0.4.17
|
||||
tabulate==0.8.6
|
||||
@ -30,4 +30,4 @@ flask==1.1.1
|
||||
colorama==0.4.3
|
||||
# Building config files interactively
|
||||
questionary==1.5.1
|
||||
prompt-toolkit==3.0.3
|
||||
prompt-toolkit==3.0.4
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
# Required for hyperopt
|
||||
scipy==1.4.1
|
||||
scikit-learn==0.22.2
|
||||
scikit-learn==0.22.2.post1
|
||||
scikit-optimize==0.7.4
|
||||
filelock==3.0.12
|
||||
joblib==0.14.1
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Include all requirements to run the bot.
|
||||
-r requirements.txt
|
||||
|
||||
plotly==4.5.2
|
||||
plotly==4.5.3
|
||||
|
||||
|
@ -902,6 +902,21 @@ def test_hyperopt_list(mocker, capsys, hyperopt_results):
|
||||
assert all(x not in captured.out
|
||||
for x in [" 1/12", " 3/12", " 4/12", " 5/12", " 7/12", " 8/12"
|
||||
" 9/12", " 10/12", " 11/12", " 12/12"])
|
||||
args = [
|
||||
"hyperopt-list",
|
||||
"--no-details",
|
||||
"--export-csv", "test_file.csv"
|
||||
]
|
||||
pargs = get_args(args)
|
||||
pargs['config'] = None
|
||||
start_hyperopt_list(pargs)
|
||||
captured = capsys.readouterr()
|
||||
assert all(x in captured.out
|
||||
for x in ["CSV-File created!"])
|
||||
f = Path("test_file.csv")
|
||||
assert 'Best,1,2,-1.25%,-0.00125625,,-2.51,"3,930.0 m",0.43662' in f.read_text()
|
||||
assert f.is_file()
|
||||
f.unlink()
|
||||
|
||||
|
||||
def test_hyperopt_show(mocker, capsys, hyperopt_results):
|
||||
|
@ -241,7 +241,7 @@ def test_setup_optimize_configuration_unlimited_stake_amount(mocker, default_con
|
||||
'--strategy', 'DefaultStrategy',
|
||||
]
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||
with pytest.raises(DependencyException, match=r'.`stake_amount`.*'):
|
||||
setup_optimize_configuration(get_args(args), RunMode.BACKTEST)
|
||||
|
||||
|
||||
|
@ -10,10 +10,11 @@ import pytest
|
||||
from arrow import Arrow
|
||||
from filelock import Timeout
|
||||
|
||||
from freqtrade import constants
|
||||
from freqtrade.commands.optimize_commands import (setup_optimize_configuration,
|
||||
start_hyperopt)
|
||||
from freqtrade.data.history import load_data
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.optimize.default_hyperopt import DefaultHyperOpt
|
||||
from freqtrade.optimize.default_hyperopt_loss import DefaultHyperOptLoss
|
||||
from freqtrade.optimize.hyperopt import Hyperopt
|
||||
@ -158,6 +159,21 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
||||
assert log_has('Parameter --print-all detected ...', caplog)
|
||||
|
||||
|
||||
def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None:
|
||||
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
|
||||
args = [
|
||||
'hyperopt',
|
||||
'--config', 'config.json',
|
||||
'--hyperopt', 'DefaultHyperOpt',
|
||||
]
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.`stake_amount`.*'):
|
||||
setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
|
||||
|
||||
|
||||
def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
||||
patched_configuration_load_config_file(mocker, default_conf)
|
||||
|
||||
|
@ -240,8 +240,6 @@ def test_pairlist_class(mocker, whitelist_conf, markets, pairlist):
|
||||
(['ETH/BTC', 'TKN/BTC', 'ETH/USDT'], "is not compatible with your stake currency"),
|
||||
# BCH/BTC not available
|
||||
(['ETH/BTC', 'TKN/BTC', 'BCH/BTC'], "is not compatible with exchange"),
|
||||
# BLK/BTC in blacklist
|
||||
(['ETH/BTC', 'TKN/BTC', 'BLK/BTC'], "in your blacklist. Removing "),
|
||||
# BTT/BTC is inactive
|
||||
(['ETH/BTC', 'TKN/BTC', 'BTT/BTC'], "Market is not active")
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user