Merge branch 'develop' into feat/short

This commit is contained in:
Matthias 2021-11-23 07:35:26 +01:00
commit ce0593c0e1
15 changed files with 45 additions and 34 deletions

View File

@ -204,9 +204,8 @@ There are several methods to configure how much of the stake currency the bot wi
#### Minimum trade stake
The minimum stake amount will depend on exchange and pair and is usually listed in the exchange support pages.
Assuming the minimum tradable amount for XRP/USD is 20 XRP (given by the exchange), and the price is 0.6$.
The minimum stake amount to buy this pair is, therefore, `20 * 0.6 ~= 12`.
Assuming the minimum tradable amount for XRP/USD is 20 XRP (given by the exchange), and the price is 0.6$, the minimum stake amount to buy this pair is `20 * 0.6 ~= 12`.
This exchange has also a limit on USD - where all orders must be > 10$ - which however does not apply in this case.
To guarantee safe execution, freqtrade will not allow buying with a stake-amount of 10.1$, instead, it'll make sure that there's enough space to place a stoploss below the pair (+ an offset, defined by `amount_reserve_percent`, which defaults to 5%).

View File

@ -292,7 +292,7 @@ If the trading range over the last 10 days is <1% or >99%, remove the pair from
#### VolatilityFilter
Volatility is the degree of historical variation of a pairs over time, is is measured by the standard deviation of logarithmic daily returns. Returns are assumed to be normally distributed, although actual distribution might be different. In a normal distribution, 68% of observations fall within one standard deviation and 95% of observations fall within two standard deviations. Assuming a volatility of 0.05 means that the expected returns for 20 out of 30 days is expected to be less than 5% (one standard deviation). Volatility is a positive ratio of the expected deviation of return and can be greater than 1.00. Please refer to the wikipedia definition of [`volatility`](https://en.wikipedia.org/wiki/Volatility_(finance)).
Volatility is the degree of historical variation of a pairs over time, it is measured by the standard deviation of logarithmic daily returns. Returns are assumed to be normally distributed, although actual distribution might be different. In a normal distribution, 68% of observations fall within one standard deviation and 95% of observations fall within two standard deviations. Assuming a volatility of 0.05 means that the expected returns for 20 out of 30 days is expected to be less than 5% (one standard deviation). Volatility is a positive ratio of the expected deviation of return and can be greater than 1.00. Please refer to the wikipedia definition of [`volatility`](https://en.wikipedia.org/wiki/Volatility_(finance)).
This filter removes pairs if the average volatility over a `lookback_days` days is below `min_volatility` or above `max_volatility`. Since this is a filter that requires additional data, the results are cached for `refresh_period`.

View File

@ -70,7 +70,7 @@ class Backtesting:
self.all_results: Dict[str, Dict] = {}
self._exchange_name = self.config['exchange']['name']
self.exchange = ExchangeResolver.load_exchange(self._exchange_name, self.config)
self.dataprovider = DataProvider(self.config, None)
self.dataprovider = DataProvider(self.config, self.exchange)
if self.config.get('strategy_list', None):
for strat in list(self.config['strategy_list']):

View File

@ -144,6 +144,7 @@ class OrderTypes(BaseModel):
class ShowConfig(BaseModel):
version: str
api_version: float
dry_run: bool
trading_mode: str
short_allowed: bool

View File

@ -26,6 +26,11 @@ from freqtrade.rpc.rpc import RPCException
logger = logging.getLogger(__name__)
# API version
# Pre-1.1, no version was provided
# Version increments should happen in "small" steps (1.1, 1.12, ...) unless big changes happen.
API_VERSION = 1.1
# Public API, requires no auth.
router_public = APIRouter()
# Private API, protected by authentication
@ -117,7 +122,9 @@ def show_config(rpc: Optional[RPC] = Depends(get_rpc_optional), config=Depends(g
state = ''
if rpc:
state = rpc._freqtrade.state
return RPC._rpc_show_config(config, state)
resp = RPC._rpc_show_config(config, state)
resp['api_version'] = API_VERSION
return resp
@router.post('/forcebuy', response_model=ForceBuyResponse, tags=['trading'])

View File

@ -274,11 +274,11 @@ class Telegram(RPCHandler):
f"*Buy Tag:* `{msg['buy_tag']}`\n"
f"*Sell Reason:* `{msg['sell_reason']}`\n"
f"*Duration:* `{msg['duration']} ({msg['duration_min']:.1f} min)`\n"
f"*Amount:* `{msg['amount']:.8f}`\n")
f"*Amount:* `{msg['amount']:.8f}`\n"
f"*Open Rate:* `{msg['open_rate']:.8f}`\n")
if msg['type'] == RPCMessageType.SELL:
message += (f"*Open Rate:* `{msg['open_rate']:.8f}`\n"
f"*Current Rate:* `{msg['current_rate']:.8f}`\n"
message += (f"*Current Rate:* `{msg['current_rate']:.8f}`\n"
f"*Close Rate:* `{msg['limit']:.8f}`")
elif msg['type'] == RPCMessageType.SELL_FILL:

View File

@ -80,12 +80,11 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
# Not specifying an asset will define informative dataframe for current pair.
asset = metadata['pair']
if '/' in asset:
base, quote = asset.split('/')
else:
# When futures are supported this may need reevaluation.
# base, quote = asset, ''
raise OperationalException('Not implemented.')
market = strategy.dp.market(asset)
if market is None:
raise OperationalException(f'Market {asset} is not available.')
base = market['base']
quote = market['quote']
# Default format. This optimizes for the common case: informative pairs using same stake
# currency. When quote currency matches stake currency, column name will omit base currency.

View File

@ -20,7 +20,7 @@ time-machine==2.4.0
nbconvert==6.3.0
# mypy types
types-cachetools==4.2.4
types-cachetools==4.2.5
types-filelock==3.2.1
types-requests==2.26.0
types-tabulate==0.8.3

View File

@ -5,7 +5,7 @@
scipy==1.7.2
scikit-learn==1.0.1
scikit-optimize==0.9.0
filelock==3.3.2
filelock==3.4.0
joblib==1.1.0
psutil==5.8.0
progressbar2==3.55.0

View File

@ -1,5 +1,5 @@
# Include all requirements to run the bot.
-r requirements.txt
plotly==5.3.1
plotly==5.4.0

View File

@ -2,10 +2,10 @@ numpy==1.21.4
pandas==1.3.4
pandas-ta==0.3.14b
ccxt==1.61.24
ccxt==1.61.92
# Pin cryptography for now due to rust build errors with piwheels
cryptography==35.0.0
aiohttp==3.7.4.post0
cryptography==36.0.0
aiohttp==3.8.1
SQLAlchemy==1.4.27
python-telegram-bot==13.8.1
arrow==1.2.1

View File

@ -541,6 +541,8 @@ def test_api_show_config(botclient):
assert 'ask_strategy' in response
assert 'unfilledtimeout' in response
assert 'version' in response
assert 'api_version' in response
assert 1.1 <= response['api_version'] <= 1.2
def test_api_daily(botclient, mocker, ticker, fee, markets):

View File

@ -1847,6 +1847,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None:
'*Sell Reason:* `stop_loss`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
'*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00007500`\n'
'*Close Rate:* `0.00003201`'
)

View File

@ -19,7 +19,7 @@ class InformativeDecoratorTest(IStrategy):
startup_candle_count: int = 20
def informative_pairs(self):
return [('BTC/USDT', '5m')]
return [('NEO/USDT', '5m')]
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['buy'] = 0
@ -37,8 +37,8 @@ class InformativeDecoratorTest(IStrategy):
return dataframe
# Simple informative test.
@informative('1h', 'BTC/{stake}')
def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
@informative('1h', 'NEO/{stake}')
def populate_indicators_neo_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = 14
return dataframe
@ -49,7 +49,7 @@ class InformativeDecoratorTest(IStrategy):
return dataframe
# Formatting test.
@informative('30m', 'BTC/{stake}', '{column}_{BASE}_{QUOTE}_{base}_{quote}_{asset}_{timeframe}')
@informative('30m', 'NEO/{stake}', '{column}_{BASE}_{QUOTE}_{base}_{quote}_{asset}_{timeframe}')
def populate_indicators_btc_1h_2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = 14
return dataframe
@ -67,7 +67,7 @@ class InformativeDecoratorTest(IStrategy):
dataframe['rsi_less'] = dataframe['rsi'] < dataframe['rsi_1h']
# Mixing manual informative pairs with decorators.
informative = self.dp.get_pair_dataframe('BTC/USDT', '5m')
informative = self.dp.get_pair_dataframe('NEO/USDT', '5m')
informative['rsi'] = 14
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '5m', ffill=True)

View File

@ -7,6 +7,7 @@ import pytest
from freqtrade.data.dataprovider import DataProvider
from freqtrade.strategy import (merge_informative_pair, stoploss_from_absolute, stoploss_from_open,
timeframe_to_minutes)
from tests.conftest import get_patched_exchange
def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'):
@ -155,9 +156,9 @@ def test_informative_decorator(mocker, default_conf):
('LTC/USDT', '5m'): test_data_5m,
('LTC/USDT', '30m'): test_data_30m,
('LTC/USDT', '1h'): test_data_1h,
('BTC/USDT', '30m'): test_data_30m,
('BTC/USDT', '5m'): test_data_5m,
('BTC/USDT', '1h'): test_data_1h,
('NEO/USDT', '30m'): test_data_30m,
('NEO/USDT', '5m'): test_data_5m,
('NEO/USDT', '1h'): test_data_1h,
('ETH/USDT', '1h'): test_data_1h,
('ETH/USDT', '30m'): test_data_30m,
('ETH/BTC', '1h'): test_data_1h,
@ -165,15 +166,16 @@ def test_informative_decorator(mocker, default_conf):
from .strats.informative_decorator_strategy import InformativeDecoratorTest
default_conf['stake_currency'] = 'USDT'
strategy = InformativeDecoratorTest(config=default_conf)
strategy.dp = DataProvider({}, None, None)
exchange = get_patched_exchange(mocker, default_conf)
strategy.dp = DataProvider({}, exchange, None)
mocker.patch.object(strategy.dp, 'current_whitelist', return_value=[
'XRP/USDT', 'LTC/USDT', 'BTC/USDT'
'XRP/USDT', 'LTC/USDT', 'NEO/USDT'
])
assert len(strategy._ft_informative) == 6 # Equal to number of decorators used
informative_pairs = [('XRP/USDT', '1h'), ('LTC/USDT', '1h'), ('XRP/USDT', '30m'),
('LTC/USDT', '30m'), ('BTC/USDT', '1h'), ('BTC/USDT', '30m'),
('BTC/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')]
('LTC/USDT', '30m'), ('NEO/USDT', '1h'), ('NEO/USDT', '30m'),
('NEO/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')]
for inf_pair in informative_pairs:
assert inf_pair in strategy.gather_informative_pairs()
@ -186,8 +188,8 @@ def test_informative_decorator(mocker, default_conf):
{p: data[(p, strategy.timeframe)] for p in ('XRP/USDT', 'LTC/USDT')})
expected_columns = [
'rsi_1h', 'rsi_30m', # Stacked informative decorators
'btc_usdt_rsi_1h', # BTC 1h informative
'rsi_BTC_USDT_btc_usdt_BTC/USDT_30m', # Column formatting
'neo_usdt_rsi_1h', # NEO 1h informative
'rsi_NEO_USDT_neo_usdt_NEO/USDT_30m', # Column formatting
'rsi_from_callable', # Custom column formatter
'eth_btc_rsi_1h', # Quote currency not matching stake currency
'rsi', 'rsi_less', # Non-informative columns