Merge branch 'develop' into feat/short
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
from freqtrade.enums.backteststate import BacktestState
|
||||
from freqtrade.enums.candletype import CandleType
|
||||
from freqtrade.enums.collateral import Collateral
|
||||
from freqtrade.enums.ordertypevalue import OrderTypeValues
|
||||
from freqtrade.enums.rpcmessagetype import RPCMessageType
|
||||
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
|
||||
from freqtrade.enums.selltype import SellType
|
||||
|
6
freqtrade/enums/ordertypevalue.py
Normal file
6
freqtrade/enums/ordertypevalue.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class OrderTypeValues(str, Enum):
|
||||
limit = 'limit'
|
||||
market = 'market'
|
@@ -356,10 +356,7 @@ class Backtesting:
|
||||
# use Open rate if open_rate > calculated sell rate
|
||||
return sell_row[OPEN_IDX]
|
||||
|
||||
# Use the maximum between close_rate and low as we
|
||||
# cannot sell outside of a candle.
|
||||
# Applies when a new ROI setting comes in place and the whole candle is above that.
|
||||
return min(max(close_rate, sell_row[LOW_IDX]), sell_row[HIGH_IDX])
|
||||
return close_rate
|
||||
|
||||
else:
|
||||
# This should not be reached...
|
||||
@@ -387,6 +384,17 @@ class Backtesting:
|
||||
|
||||
trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60)
|
||||
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
||||
# call the custom exit price,with default value as previous closerate
|
||||
current_profit = trade.calc_profit_ratio(closerate)
|
||||
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
|
||||
# Custom exit pricing only for sell-signals
|
||||
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
|
||||
default_retval=closerate)(
|
||||
pair=trade.pair, trade=trade,
|
||||
current_time=sell_row[DATE_IDX],
|
||||
proposed_rate=closerate, current_profit=current_profit)
|
||||
# Use the maximum between close_rate and low as we cannot sell outside of a candle.
|
||||
closerate = min(max(closerate, sell_row[LOW_IDX]), sell_row[HIGH_IDX])
|
||||
|
||||
# Confirm trade exit:
|
||||
time_in_force = self.strategy.order_time_in_force['sell']
|
||||
@@ -449,12 +457,22 @@ class Backtesting:
|
||||
except DependencyException:
|
||||
return None
|
||||
current_time = row[DATE_IDX].to_pydatetime()
|
||||
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, row[OPEN_IDX], -0.05) or 0
|
||||
|
||||
# let's call the custom entry price, using the open price as default price
|
||||
propose_rate = strategy_safe_wrapper(self.strategy.custom_entry_price,
|
||||
default_retval=row[OPEN_IDX])(
|
||||
pair=pair, current_time=row[DATE_IDX].to_pydatetime(),
|
||||
proposed_rate=row[OPEN_IDX]) # default value is the open rate
|
||||
|
||||
# Move rate to within the candle's low/high rate
|
||||
propose_rate = min(max(propose_rate, row[LOW_IDX]), row[HIGH_IDX])
|
||||
|
||||
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, propose_rate, -0.05) or 0
|
||||
max_stake_amount = self.wallets.get_available_stake_amount()
|
||||
|
||||
stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount,
|
||||
default_retval=stake_amount)(
|
||||
pair=pair, current_time=current_time, current_rate=row[OPEN_IDX],
|
||||
pair=pair, current_time=current_time, current_rate=propose_rate,
|
||||
proposed_stake=stake_amount, min_stake=min_stake_amount, max_stake=max_stake_amount,
|
||||
side=direction)
|
||||
stake_amount = self.wallets.validate_stake_amount(pair, stake_amount, min_stake_amount)
|
||||
@@ -478,7 +496,7 @@ class Backtesting:
|
||||
time_in_force = self.strategy.order_time_in_force['sell']
|
||||
# Confirm trade entry:
|
||||
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
|
||||
pair=pair, order_type=order_type, amount=stake_amount, rate=row[OPEN_IDX],
|
||||
pair=pair, order_type=order_type, amount=stake_amount, rate=propose_rate,
|
||||
time_in_force=time_in_force, current_time=current_time,
|
||||
side=direction):
|
||||
return None
|
||||
@@ -491,7 +509,7 @@ class Backtesting:
|
||||
open_rate=row[OPEN_IDX],
|
||||
open_date=current_time,
|
||||
stake_amount=stake_amount,
|
||||
amount=round((stake_amount / row[OPEN_IDX]) * leverage, 8),
|
||||
amount=round((stake_amount / propose_rate) * leverage, 8),
|
||||
fee_open=self.fee,
|
||||
fee_close=self.fee,
|
||||
is_open=True,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
from datetime import date, datetime
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from freqtrade.constants import DATETIME_PRINT_FORMAT
|
||||
from freqtrade.enums import OrderTypeValues
|
||||
|
||||
|
||||
class Ping(BaseModel):
|
||||
@@ -132,11 +132,6 @@ class UnfilledTimeout(BaseModel):
|
||||
exit_timeout_count: Optional[int]
|
||||
|
||||
|
||||
class OrderTypeValues(str, Enum):
|
||||
limit = 'limit'
|
||||
market = 'market'
|
||||
|
||||
|
||||
class OrderTypes(BaseModel):
|
||||
buy: OrderTypeValues
|
||||
sell: OrderTypeValues
|
||||
@@ -150,6 +145,7 @@ class OrderTypes(BaseModel):
|
||||
|
||||
class ShowConfig(BaseModel):
|
||||
version: str
|
||||
strategy_version: Optional[str]
|
||||
api_version: float
|
||||
dry_run: bool
|
||||
trading_mode: str
|
||||
|
@@ -122,9 +122,11 @@ def edge(rpc: RPC = Depends(get_rpc)):
|
||||
@router.get('/show_config', response_model=ShowConfig, tags=['info'])
|
||||
def show_config(rpc: Optional[RPC] = Depends(get_rpc_optional), config=Depends(get_config)):
|
||||
state = ''
|
||||
strategy_version = None
|
||||
if rpc:
|
||||
state = rpc._freqtrade.state
|
||||
resp = RPC._rpc_show_config(config, state)
|
||||
strategy_version = rpc._freqtrade.strategy.version()
|
||||
resp = RPC._rpc_show_config(config, state, strategy_version)
|
||||
resp['api_version'] = API_VERSION
|
||||
return resp
|
||||
|
||||
|
@@ -99,7 +99,8 @@ class RPC:
|
||||
self._fiat_converter = CryptoToFiatConverter()
|
||||
|
||||
@staticmethod
|
||||
def _rpc_show_config(config, botstate: Union[State, str]) -> Dict[str, Any]:
|
||||
def _rpc_show_config(config, botstate: Union[State, str],
|
||||
strategy_version: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Return a dict of config options.
|
||||
Explicitly does NOT return the full config to avoid leakage of sensitive
|
||||
@@ -107,6 +108,7 @@ class RPC:
|
||||
"""
|
||||
val = {
|
||||
'version': __version__,
|
||||
'strategy_version': strategy_version,
|
||||
'dry_run': config['dry_run'],
|
||||
'trading_mode': config.get('trading_mode', 'spot'),
|
||||
'short_allowed': config.get('trading_mode', 'spot') != 'spot',
|
||||
|
@@ -1307,7 +1307,12 @@ class Telegram(RPCHandler):
|
||||
:param update: message update
|
||||
:return: None
|
||||
"""
|
||||
self._send_msg('*Version:* `{}`'.format(__version__))
|
||||
strategy_version = self._rpc._freqtrade.strategy.version()
|
||||
version_string = f'*Version:* `{__version__}`'
|
||||
if strategy_version is not None:
|
||||
version_string += f', *Strategy version: * `{strategy_version}`'
|
||||
|
||||
self._send_msg(version_string)
|
||||
|
||||
@authorized_only
|
||||
def _show_config(self, update: Update, context: CallbackContext) -> None:
|
||||
|
@@ -413,6 +413,12 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
"""
|
||||
return []
|
||||
|
||||
def version(self) -> Optional[str]:
|
||||
"""
|
||||
Returns version of the strategy.
|
||||
"""
|
||||
return None
|
||||
|
||||
###
|
||||
# END - Intended to be overridden by strategy
|
||||
###
|
||||
|
@@ -113,8 +113,12 @@ class Worker:
|
||||
if self._heartbeat_interval:
|
||||
now = time.time()
|
||||
if (now - self._heartbeat_msg) > self._heartbeat_interval:
|
||||
version = __version__
|
||||
strategy_version = self.freqtrade.strategy.version()
|
||||
if (strategy_version is not None):
|
||||
version += ', strategy_version: ' + strategy_version
|
||||
logger.info(f"Bot heartbeat. PID={getpid()}, "
|
||||
f"version='{__version__}', state='{state.name}'")
|
||||
f"version='{version}', state='{state.name}'")
|
||||
self._heartbeat_msg = now
|
||||
|
||||
return state
|
||||
|
Reference in New Issue
Block a user