Merge pull request #6607 from freqtrade/short_pricing

Short pricing updates
This commit is contained in:
Matthias
2022-03-30 06:59:40 +02:00
committed by GitHub
31 changed files with 459 additions and 259 deletions

View File

@@ -103,14 +103,15 @@ def _validate_price_config(conf: Dict[str, Any]) -> None:
"""
When using market orders, price sides must be using the "other" side of the price
"""
# TODO-lev: check this again when determining how to migrate pricing strategies!
# TODO: The below could be an enforced setting when using market orders
if (conf.get('order_types', {}).get('entry') == 'market'
and conf.get('bid_strategy', {}).get('price_side') != 'ask'):
raise OperationalException('Market buy orders require bid_strategy.price_side = "ask".')
and conf.get('entry_pricing', {}).get('price_side') not in ('ask', 'other')):
raise OperationalException(
'Market entry orders require entry_pricing.price_side = "other".')
if (conf.get('order_types', {}).get('exit') == 'market'
and conf.get('ask_strategy', {}).get('price_side') != 'bid'):
raise OperationalException('Market sell orders require ask_strategy.price_side = "bid".')
and conf.get('exit_pricing', {}).get('price_side') not in ('bid', 'other')):
raise OperationalException('Market exit orders require exit_pricing.price_side = "other".')
def _validate_trailing_stoploss(conf: Dict[str, Any]) -> None:
@@ -193,13 +194,13 @@ def _validate_protections(conf: Dict[str, Any]) -> None:
def _validate_ask_orderbook(conf: Dict[str, Any]) -> None:
ask_strategy = conf.get('ask_strategy', {})
ask_strategy = conf.get('exit_pricing', {})
ob_min = ask_strategy.get('order_book_min')
ob_max = ask_strategy.get('order_book_max')
if ob_min is not None and ob_max is not None and ask_strategy.get('use_order_book'):
if ob_min != ob_max:
raise OperationalException(
"Using order_book_max != order_book_min in ask_strategy is no longer supported."
"Using order_book_max != order_book_min in exit_pricing is no longer supported."
"Please pick one value and use `order_book_top` in the future."
)
else:
@@ -208,7 +209,7 @@ def _validate_ask_orderbook(conf: Dict[str, Any]) -> None:
logger.warning(
"DEPRECATED: "
"Please use `order_book_top` instead of `order_book_min` and `order_book_max` "
"for your `ask_strategy` configuration."
"for your `exit_pricing` configuration."
)
@@ -217,6 +218,7 @@ def validate_migrated_strategy_settings(conf: Dict[str, Any]) -> None:
_validate_time_in_force(conf)
_validate_order_types(conf)
_validate_unfilledtimeout(conf)
_validate_pricing_rules(conf)
def _validate_time_in_force(conf: Dict[str, Any]) -> None:
@@ -279,3 +281,34 @@ def _validate_unfilledtimeout(conf: Dict[str, Any]) -> None:
]:
process_deprecated_setting(conf, 'unfilledtimeout', o, 'unfilledtimeout', n)
def _validate_pricing_rules(conf: Dict[str, Any]) -> None:
if conf.get('ask_strategy') or conf.get('bid_strategy'):
if conf.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT:
raise OperationalException(
"Please migrate your pricing settings to use the new wording.")
else:
logger.warning(
"DEPRECATED: Using 'ask_strategy' and 'bid_strategy' is deprecated."
"Please migrate your settings to use 'entry_pricing' and 'exit_pricing'."
)
conf['entry_pricing'] = {}
for obj in list(conf.get('bid_strategy', {}).keys()):
if obj == 'ask_last_balance':
process_deprecated_setting(conf, 'bid_strategy', obj,
'entry_pricing', 'price_last_balance')
else:
process_deprecated_setting(conf, 'bid_strategy', obj, 'entry_pricing', obj)
del conf['bid_strategy']
conf['exit_pricing'] = {}
for obj in list(conf.get('ask_strategy', {}).keys()):
if obj == 'bid_last_balance':
process_deprecated_setting(conf, 'ask_strategy', obj,
'exit_pricing', 'price_last_balance')
else:
process_deprecated_setting(conf, 'ask_strategy', obj, 'exit_pricing', obj)
del conf['ask_strategy']

View File

@@ -81,8 +81,6 @@ class Configuration:
# Normalize config
if 'internals' not in config:
config['internals'] = {}
if 'ask_strategy' not in config:
config['ask_strategy'] = {}
if 'pairlists' not in config:
config['pairlists'] = []

View File

@@ -21,7 +21,7 @@ UNLIMITED_STAKE_AMOUNT = 'unlimited'
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
REQUIRED_ORDERTIF = ['entry', 'exit']
REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
ORDERBOOK_SIDES = ['ask', 'bid']
PRICING_SIDES = ['ask', 'bid', 'same', 'other']
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
@@ -171,16 +171,16 @@ CONF_SCHEMA = {
'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'}
}
},
'bid_strategy': {
'entry_pricing': {
'type': 'object',
'properties': {
'ask_last_balance': {
'price_last_balance': {
'type': 'number',
'minimum': 0,
'maximum': 1,
'exclusiveMaximum': False,
},
'price_side': {'type': 'string', 'enum': ORDERBOOK_SIDES, 'default': 'bid'},
'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'},
'use_order_book': {'type': 'boolean'},
'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, },
'check_depth_of_market': {
@@ -193,11 +193,11 @@ CONF_SCHEMA = {
},
'required': ['price_side']
},
'ask_strategy': {
'exit_pricing': {
'type': 'object',
'properties': {
'price_side': {'type': 'string', 'enum': ORDERBOOK_SIDES, 'default': 'ask'},
'bid_last_balance': {
'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'},
'price_last_balance': {
'type': 'number',
'minimum': 0,
'maximum': 1,
@@ -445,8 +445,8 @@ SCHEMA_TRADE_REQUIRED = [
'last_stake_amount_min_ratio',
'dry_run',
'dry_run_wallet',
'ask_strategy',
'bid_strategy',
'exit_pricing',
'entry_pricing',
'stoploss',
'minimal_roi',
'internals',

View File

@@ -111,8 +111,8 @@ class Exchange:
# Cache values for 1800 to avoid frequent polling of the exchange for prices
# Caching only applies to RPC methods, so prices for open trades are still
# refreshed once every iteration.
self._sell_rate_cache: TTLCache = TTLCache(maxsize=100, ttl=1800)
self._buy_rate_cache: TTLCache = TTLCache(maxsize=100, ttl=1800)
self._exit_rate_cache: TTLCache = TTLCache(maxsize=100, ttl=1800)
self._entry_rate_cache: TTLCache = TTLCache(maxsize=100, ttl=1800)
# Holds candles
self._klines: Dict[PairWithTimeframe, DataFrame] = {}
@@ -184,8 +184,8 @@ class Exchange:
self.required_candle_call_count = self.validate_required_startup_candles(
config.get('startup_candle_count', 0), config.get('timeframe', ''))
self.validate_trading_mode_and_margin_mode(self.trading_mode, self.margin_mode)
self.validate_pricing(config['ask_strategy'])
self.validate_pricing(config['bid_strategy'])
self.validate_pricing(config['exit_pricing'])
self.validate_pricing(config['entry_pricing'])
# Converts the interval provided in minutes in config to seconds
self.markets_refresh_interval: int = exchange_config.get(
@@ -1438,7 +1438,8 @@ class Exchange:
except ccxt.BaseError as e:
raise OperationalException(e) from e
def get_rate(self, pair: str, refresh: bool, side: str) -> float:
def get_rate(self, pair: str, refresh: bool,
side: Literal['entry', 'exit'], is_short: bool) -> float:
"""
Calculates bid/ask target
bid rate - between current ask price and last price
@@ -1450,9 +1451,10 @@ class Exchange:
:return: float: Price
:raises PricingError if orderbook price could not be determined.
"""
cache_rate: TTLCache = self._buy_rate_cache if side == "buy" else self._sell_rate_cache
[strat_name, name] = ['bid_strategy', 'Buy'] if side == "buy" else ['ask_strategy', 'Sell']
name = side.capitalize()
strat_name = 'entry_pricing' if side == "entry" else 'exit_pricing'
cache_rate: TTLCache = self._entry_rate_cache if side == "entry" else self._exit_rate_cache
if not refresh:
rate = cache_rate.get(pair)
# Check if cache has been invalidated
@@ -1462,6 +1464,23 @@ class Exchange:
conf_strategy = self._config.get(strat_name, {})
price_side = conf_strategy['price_side']
if price_side in ('same', 'other'):
price_map = {
('entry', 'long', 'same'): 'bid',
('entry', 'long', 'other'): 'ask',
('entry', 'short', 'same'): 'ask',
('entry', 'short', 'other'): 'bid',
('exit', 'long', 'same'): 'ask',
('exit', 'long', 'other'): 'bid',
('exit', 'short', 'same'): 'bid',
('exit', 'short', 'other'): 'ask',
}
price_side = price_map[(side, 'short' if is_short else 'long', price_side)]
price_side_word = price_side.capitalize()
if conf_strategy.get('use_order_book', False):
order_book_top = conf_strategy.get('order_book_top', 1)
@@ -1469,26 +1488,25 @@ class Exchange:
logger.debug('order_book %s', order_book)
# top 1 = index 0
try:
rate = order_book[f"{conf_strategy['price_side']}s"][order_book_top - 1][0]
rate = order_book[f"{price_side}s"][order_book_top - 1][0]
except (IndexError, KeyError) as e:
logger.warning(
f"{name} Price at location {order_book_top} from orderbook could not be "
f"determined. Orderbook: {order_book}"
)
raise PricingError from e
price_side = {conf_strategy['price_side'].capitalize()}
logger.debug(f"{name} price from orderbook {price_side}"
logger.debug(f"{name} price from orderbook {price_side_word}"
f"side - top {order_book_top} order book {side} rate {rate:.8f}")
else:
logger.debug(f"Using Last {conf_strategy['price_side'].capitalize()} / Last Price")
logger.debug(f"Using Last {price_side_word} / Last Price")
ticker = self.fetch_ticker(pair)
ticker_rate = ticker[conf_strategy['price_side']]
ticker_rate = ticker[price_side]
if ticker['last'] and ticker_rate:
if side == 'buy' and ticker_rate > ticker['last']:
balance = conf_strategy.get('ask_last_balance', 0.0)
if side == 'entry' and ticker_rate > ticker['last']:
balance = conf_strategy.get('price_last_balance', 0.0)
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
elif side == 'sell' and ticker_rate < ticker['last']:
balance = conf_strategy.get('bid_last_balance', 0.0)
elif side == 'exit' and ticker_rate < ticker['last']:
balance = conf_strategy.get('price_last_balance', 0.0)
ticker_rate = ticker_rate - balance * (ticker_rate - ticker['last'])
rate = ticker_rate

View File

@@ -7,7 +7,7 @@ import traceback
from datetime import datetime, time, timezone
from math import isclose
from threading import Lock
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Literal, Optional, Tuple
from schedule import Scheduler
@@ -459,7 +459,7 @@ class FreqtradeBot(LoggingMixin):
if signal:
stake_amount = self.wallets.get_trade_stake_amount(pair, self.edge)
bid_check_dom = self.config.get('bid_strategy', {}).get('check_depth_of_market', {})
bid_check_dom = self.config.get('entry_pricing', {}).get('check_depth_of_market', {})
if ((bid_check_dom.get('enabled', False)) and
(bid_check_dom.get('bids_to_ask_delta', 0) > 0)):
if self._check_depth_of_market(pair, bid_check_dom, side=signal):
@@ -511,7 +511,8 @@ class FreqtradeBot(LoggingMixin):
return
else:
logger.debug("Max adjustment entries is set to unlimited.")
current_rate = self.exchange.get_rate(trade.pair, refresh=True, side=trade.enter_side)
current_rate = self.exchange.get_rate(
trade.pair, side='entry', is_short=trade.is_short, refresh=True)
current_profit = trade.calc_profit_ratio(current_rate)
min_stake_amount = self.exchange.get_min_pair_stake_amount(trade.pair,
@@ -589,11 +590,11 @@ class FreqtradeBot(LoggingMixin):
time_in_force = self.strategy.order_time_in_force['entry']
[side, name] = ['sell', 'Short'] if is_short else ['buy', 'Long']
trade_side = 'short' if is_short else 'long'
trade_side: Literal['long', 'short'] = 'short' if is_short else 'long'
pos_adjust = trade is not None
enter_limit_requested, stake_amount, leverage = self.get_valid_enter_price_and_stake(
pair, price, stake_amount, side, trade_side, enter_tag, trade)
pair, price, stake_amount, trade_side, enter_tag, trade)
if not stake_amount:
return False
@@ -745,7 +746,7 @@ class FreqtradeBot(LoggingMixin):
def get_valid_enter_price_and_stake(
self, pair: str, price: Optional[float], stake_amount: float,
side: str, trade_side: str,
trade_side: Literal['long', 'short'],
entry_tag: Optional[str],
trade: Optional[Trade]
) -> Tuple[float, float, float]:
@@ -754,7 +755,8 @@ class FreqtradeBot(LoggingMixin):
enter_limit_requested = price
else:
# Calculate price
proposed_enter_rate = self.exchange.get_rate(pair, refresh=True, side=side)
proposed_enter_rate = self.exchange.get_rate(
pair, side='entry', is_short=(trade_side == 'short'), refresh=True)
custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price,
default_retval=proposed_enter_rate)(
pair=pair, current_time=datetime.now(timezone.utc),
@@ -763,7 +765,7 @@ class FreqtradeBot(LoggingMixin):
enter_limit_requested = self.get_valid_price(custom_entry_price, proposed_enter_rate)
if not enter_limit_requested:
raise PricingError(f'Could not determine {side} price.')
raise PricingError('Could not determine entry price.')
if trade is None:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
@@ -824,7 +826,8 @@ class FreqtradeBot(LoggingMixin):
current_rate = trade.open_rate_requested
if self.dataprovider.runmode in (RunMode.DRY_RUN, RunMode.LIVE):
current_rate = self.exchange.get_rate(trade.pair, refresh=False, side=trade.enter_side)
current_rate = self.exchange.get_rate(
trade.pair, side='entry', is_short=trade.is_short, refresh=False)
msg = {
'trade_id': trade.id,
@@ -853,7 +856,8 @@ class FreqtradeBot(LoggingMixin):
"""
Sends rpc notification when a entry order cancel occurred.
"""
current_rate = self.exchange.get_rate(trade.pair, refresh=False, side=trade.enter_side)
current_rate = self.exchange.get_rate(
trade.pair, side='entry', is_short=trade.is_short, refresh=False)
msg_type = RPCMessageType.SHORT_CANCEL if trade.is_short else RPCMessageType.BUY_CANCEL
msg = {
'trade_id': trade.id,
@@ -935,7 +939,8 @@ class FreqtradeBot(LoggingMixin):
)
logger.debug('checking exit')
exit_rate = self.exchange.get_rate(trade.pair, refresh=True, side=trade.exit_side)
exit_rate = self.exchange.get_rate(
trade.pair, side='exit', is_short=trade.is_short, refresh=True)
if self._check_and_execute_exit(trade, exit_rate, enter, exit_, exit_tag):
return True
@@ -1433,7 +1438,7 @@ class FreqtradeBot(LoggingMixin):
profit_trade = trade.calc_profit(rate=profit_rate)
# Use cached rates here - it was updated seconds ago.
current_rate = self.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side) if not fill else None
trade.pair, side='exit', is_short=trade.is_short, refresh=False) if not fill else None
profit_ratio = trade.calc_profit_ratio(profit_rate)
gain = "profit" if profit_ratio > 0 else "loss"
@@ -1482,7 +1487,8 @@ class FreqtradeBot(LoggingMixin):
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
profit_trade = trade.calc_profit(rate=profit_rate)
current_rate = self.exchange.get_rate(trade.pair, refresh=False, side=trade.exit_side)
current_rate = self.exchange.get_rate(
trade.pair, side='exit', is_short=trade.is_short, refresh=False)
profit_ratio = trade.calc_profit_ratio(profit_rate)
gain = "profit" if profit_ratio > 0 else "loss"

View File

@@ -115,9 +115,9 @@ class Hyperopt:
if HyperoptTools.has_space(self.config, 'sell'):
# Make sure use_sell_signal is enabled
if 'ask_strategy' not in self.config:
self.config['ask_strategy'] = {}
self.config['ask_strategy']['use_sell_signal'] = True
if 'exit_pricing' not in self.config:
self.config['exit_pricing'] = {}
self.config['exit_pricing']['use_sell_signal'] = True
self.print_all = self.config.get('print_all', False)
self.hyperopt_table_header = 0

View File

@@ -175,8 +175,8 @@ class ShowConfig(BaseModel):
exchange: str
strategy: Optional[str]
forcebuy_enabled: bool
ask_strategy: Dict[str, Any]
bid_strategy: Dict[str, Any]
exit_pricing: Dict[str, Any]
entry_pricing: Dict[str, Any]
bot_name: str
state: str
runmode: str

View File

@@ -136,8 +136,8 @@ class RPC:
'exchange': config['exchange']['name'],
'strategy': config['strategy'],
'forcebuy_enabled': config.get('forcebuy_enable', False),
'ask_strategy': config.get('ask_strategy', {}),
'bid_strategy': config.get('bid_strategy', {}),
'exit_pricing': config.get('exit_pricing', {}),
'entry_pricing': config.get('entry_pricing', {}),
'state': str(botstate),
'runmode': config['runmode'].value,
'position_adjustment_enable': config.get('position_adjustment_enable', False),
@@ -171,7 +171,7 @@ class RPC:
if trade.is_open:
try:
current_rate = self._freqtrade.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side)
trade.pair, side='exit', is_short=trade.is_short, refresh=False)
except (ExchangeError, PricingError):
current_rate = NAN
else:
@@ -231,7 +231,7 @@ class RPC:
# calculate profit and send message to user
try:
current_rate = self._freqtrade.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side)
trade.pair, side='exit', is_short=trade.is_short, refresh=False)
except (PricingError, ExchangeError):
current_rate = NAN
trade_profit = trade.calc_profit(current_rate)
@@ -485,7 +485,7 @@ class RPC:
# Get current rate
try:
current_rate = self._freqtrade.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side)
trade.pair, side='exit', is_short=trade.is_short, refresh=False)
except (PricingError, ExchangeError):
current_rate = NAN
profit_ratio = trade.calc_profit_ratio(rate=current_rate)
@@ -705,7 +705,7 @@ class RPC:
if not fully_canceled:
# Get current rate and execute sell
current_rate = self._freqtrade.exchange.get_rate(
trade.pair, refresh=False, side=trade.exit_side)
trade.pair, side='exit', is_short=trade.is_short, refresh=True)
exit_check = ExitCheckTuple(exit_type=ExitType.FORCE_SELL)
order_type = ordertype or self._freqtrade.strategy.order_types.get(
"forceexit", self._freqtrade.strategy.order_types["exit"])

View File

@@ -1490,8 +1490,8 @@ class Telegram(RPCHandler):
f"*Stake per trade:* `{val['stake_amount']} {val['stake_currency']}`\n"
f"*Max open Trades:* `{val['max_open_trades']}`\n"
f"*Minimum ROI:* `{val['minimal_roi']}`\n"
f"*Ask strategy:* ```\n{json.dumps(val['ask_strategy'])}```\n"
f"*Bid strategy:* ```\n{json.dumps(val['bid_strategy'])}```\n"
f"*Entry strategy:* ```\n{json.dumps(val['entry_pricing'])}```\n"
f"*Exit strategy:* ```\n{json.dumps(val['exit_pricing'])}```\n"
f"{sl_info}"
f"{pa_info}"
f"*Timeframe:* `{val['timeframe']}`\n"

View File

@@ -331,7 +331,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New stoploss value, relative to the current_rate
@@ -349,7 +349,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in ask_strategy.
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing.
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New entry price value if provided
@@ -369,7 +369,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in ask_strategy.
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New exit price value if provided
@@ -393,7 +393,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return: To execute exit, return a string with custom sell reason or True. Otherwise return
@@ -417,7 +417,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return: To execute exit, return a string with custom sell reason or True. Otherwise return
@@ -433,7 +433,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param proposed_stake: A stake amount proposed by the bot.
:param min_stake: Minimal stake size allowed by exchange.
:param max_stake: Balance available for trading.
@@ -474,7 +474,7 @@ class IStrategy(ABC, HyperStrategyMixin):
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param proposed_leverage: A leverage proposed by the bot.
:param max_leverage: Max leverage allowed on this pair
:param side: 'long' or 'short' - indicating the direction of the proposed trade

View File

@@ -21,18 +21,18 @@
"exit_timeout_count": 0,
"unit": "minutes"
},
"bid_strategy": {
"price_side": "bid",
"ask_last_balance": 0.0,
"entry_pricing": {
"price_side": "same",
"use_order_book": true,
"order_book_top": 1,
"price_last_balance": 0.0,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"ask_strategy": {
"price_side": "ask",
"exit_pricing":{
"price_side": "same",
"use_order_book": true,
"order_book_top": 1
},

View File

@@ -64,7 +64,7 @@ class {{ strategy }}(IStrategy):
# Run "populate_indicators()" only for new candle.
process_only_new_candles = False
# These values can be overridden in the "ask_strategy" section in the config.
# These values can be overridden in the config.
use_sell_signal = True
sell_profit_only = False
ignore_roi_if_buy_signal = False

View File

@@ -64,7 +64,7 @@ class SampleStrategy(IStrategy):
# Run "populate_indicators()" only for new candle.
process_only_new_candles = False
# These values can be overridden in the "ask_strategy" section in the config.
# These values can be overridden in the config.
use_sell_signal = True
sell_profit_only = False
ignore_roi_if_buy_signal = False

View File

@@ -23,7 +23,7 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate:
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in ask_strategy.
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing.
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New entry price value if provided
@@ -43,7 +43,7 @@ def custom_exit_price(self, pair: str, trade: 'Trade',
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in ask_strategy.
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New exit price value if provided
@@ -58,7 +58,7 @@ def custom_stake_amount(self, pair: str, current_time: 'datetime', current_rate:
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param proposed_stake: A stake amount proposed by the bot.
:param min_stake: Minimal stake size allowed by exchange.
:param max_stake: Balance available for trading.
@@ -85,7 +85,7 @@ def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New stoploss value, relative to the current_rate
@@ -108,7 +108,7 @@ def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', curre
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return: To execute sell, return a string with custom sell reason or True. Otherwise return
@@ -241,7 +241,7 @@ def leverage(self, pair: str, current_time: datetime, current_rate: float,
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param proposed_leverage: A leverage proposed by the bot.
:param max_leverage: Max leverage allowed on this pair
:param side: 'long' or 'short' - indicating the direction of the proposed trade