2018-11-14 11:37:15 +00:00
|
|
|
# pragma pylint: disable=missing-docstring, W0212, too-many-arguments
|
|
|
|
|
|
|
|
"""
|
2018-12-12 19:03:41 +00:00
|
|
|
This module contains the edge backtesting interface
|
2018-11-14 11:37:15 +00:00
|
|
|
"""
|
|
|
|
import logging
|
2019-11-05 11:39:19 +00:00
|
|
|
from typing import Any, Dict
|
|
|
|
|
2018-11-14 12:25:44 +00:00
|
|
|
from tabulate import tabulate
|
2019-11-05 11:39:19 +00:00
|
|
|
|
2019-06-15 10:20:32 +00:00
|
|
|
from freqtrade import constants
|
2019-11-23 14:49:46 +00:00
|
|
|
from freqtrade.configuration import (TimeRange, remove_credentials,
|
|
|
|
validate_config_consistency)
|
2018-11-14 15:49:16 +00:00
|
|
|
from freqtrade.edge import Edge
|
2018-11-14 11:37:15 +00:00
|
|
|
from freqtrade.exchange import Exchange
|
2018-11-24 19:00:02 +00:00
|
|
|
from freqtrade.resolvers import StrategyResolver
|
2018-11-14 11:37:15 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2019-09-12 01:39:52 +00:00
|
|
|
class EdgeCli:
|
2018-11-14 11:37:15 +00:00
|
|
|
"""
|
2018-12-12 19:03:41 +00:00
|
|
|
EdgeCli class, this class contains all the logic to run edge backtesting
|
2018-11-14 11:37:15 +00:00
|
|
|
|
2018-12-12 19:03:41 +00:00
|
|
|
To run a edge backtest:
|
|
|
|
edge = EdgeCli(config)
|
|
|
|
edge.start()
|
2018-11-14 11:37:15 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, config: Dict[str, Any]) -> None:
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
# Reset keys for edge
|
2019-11-05 11:39:19 +00:00
|
|
|
remove_credentials(self.config)
|
2019-06-15 10:20:32 +00:00
|
|
|
self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
2018-11-14 11:37:15 +00:00
|
|
|
self.exchange = Exchange(self.config)
|
|
|
|
self.strategy = StrategyResolver(self.config).strategy
|
|
|
|
|
2019-11-23 14:49:46 +00:00
|
|
|
validate_config_consistency(self.config)
|
|
|
|
|
2018-11-14 11:37:15 +00:00
|
|
|
self.edge = Edge(config, self.exchange, self.strategy)
|
2019-09-20 18:22:51 +00:00
|
|
|
# Set refresh_pairs to false for edge-cli (it must be true for edge)
|
2019-09-20 18:02:07 +00:00
|
|
|
self.edge._refresh_pairs = False
|
2018-11-14 11:37:15 +00:00
|
|
|
|
2019-12-19 18:55:21 +00:00
|
|
|
self.edge._timerange = TimeRange.parse_timerange(None if self.config.get(
|
2018-11-14 16:14:37 +00:00
|
|
|
'timerange') is None else str(self.config.get('timerange')))
|
|
|
|
|
2018-11-14 12:25:44 +00:00
|
|
|
def _generate_edge_table(self, results: dict) -> str:
|
|
|
|
|
2018-11-14 15:31:23 +00:00
|
|
|
floatfmt = ('s', '.10g', '.2f', '.2f', '.2f', '.2f', 'd', '.d')
|
2018-11-14 12:25:44 +00:00
|
|
|
tabular_data = []
|
|
|
|
headers = ['pair', 'stoploss', 'win rate', 'risk reward ratio',
|
2018-11-14 15:49:16 +00:00
|
|
|
'required risk reward', 'expectancy', 'total number of trades',
|
|
|
|
'average duration (min)']
|
2018-11-14 12:25:44 +00:00
|
|
|
|
|
|
|
for result in results.items():
|
2018-11-14 12:38:23 +00:00
|
|
|
if result[1].nb_trades > 0:
|
|
|
|
tabular_data.append([
|
|
|
|
result[0],
|
|
|
|
result[1].stoploss,
|
|
|
|
result[1].winrate,
|
|
|
|
result[1].risk_reward_ratio,
|
|
|
|
result[1].required_risk_reward,
|
|
|
|
result[1].expectancy,
|
|
|
|
result[1].nb_trades,
|
|
|
|
round(result[1].avg_trade_duration)
|
|
|
|
])
|
2018-11-14 12:25:44 +00:00
|
|
|
|
2019-01-17 19:28:21 +00:00
|
|
|
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
2019-09-30 17:32:13 +00:00
|
|
|
return tabulate(tabular_data, headers=headers,
|
|
|
|
floatfmt=floatfmt, tablefmt="pipe") # type: ignore
|
2018-11-14 12:25:44 +00:00
|
|
|
|
2018-11-14 11:37:15 +00:00
|
|
|
def start(self) -> None:
|
2019-05-22 11:21:36 +00:00
|
|
|
result = self.edge.calculate()
|
|
|
|
if result:
|
2019-05-22 11:34:35 +00:00
|
|
|
print('') # blank line for readability
|
2019-05-22 11:21:36 +00:00
|
|
|
print(self._generate_edge_table(self.edge._cached_pairs))
|