Merge pull request #5299 from kevinjulian/feat/kevinjulian/add-buy-signal-name
Add buy signal name
This commit is contained in:
commit
138b126d03
@ -114,6 +114,36 @@ class AwesomeStrategy(IStrategy):
|
||||
|
||||
See [Dataframe access](#dataframe-access) for more information about dataframe use in strategy callbacks.
|
||||
|
||||
## Buy Tag
|
||||
|
||||
When your strategy has multiple buy signals, you can name the signal that triggered.
|
||||
Then you can access you buy signal on `custom_sell`
|
||||
|
||||
```python
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['rsi'] < 35) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
['buy', 'buy_tag']] = (1, 'buy_signal_rsi')
|
||||
|
||||
return dataframe
|
||||
|
||||
def custom_sell(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
|
||||
current_profit: float, **kwargs):
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if trade.buy_tag == 'buy_signal_rsi' and last_candle['rsi'] > 80:
|
||||
return 'sell_signal_rsi'
|
||||
return None
|
||||
|
||||
```
|
||||
|
||||
!!! Note
|
||||
`buy_tag` is limited to 100 characters, remaining data will be truncated.
|
||||
|
||||
|
||||
## Custom stoploss
|
||||
|
||||
The stoploss price can only ever move upwards - if the stoploss value returned from `custom_stoploss` would result in a lower stoploss price than was previously set, it will be ignored. The traditional `stoploss` value serves as an absolute lower level and will be instated as the initial stoploss.
|
||||
|
@ -83,6 +83,7 @@ Possible parameters are:
|
||||
* `fiat_currency`
|
||||
* `order_type`
|
||||
* `current_rate`
|
||||
* `buy_tag`
|
||||
|
||||
### Webhookbuycancel
|
||||
|
||||
@ -100,6 +101,7 @@ Possible parameters are:
|
||||
* `fiat_currency`
|
||||
* `order_type`
|
||||
* `current_rate`
|
||||
* `buy_tag`
|
||||
|
||||
### Webhookbuyfill
|
||||
|
||||
@ -115,6 +117,7 @@ Possible parameters are:
|
||||
* `stake_amount`
|
||||
* `stake_currency`
|
||||
* `fiat_currency`
|
||||
* `buy_tag`
|
||||
|
||||
### Webhooksell
|
||||
|
||||
|
@ -30,7 +30,7 @@ BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date',
|
||||
'fee_open', 'fee_close', 'trade_duration',
|
||||
'profit_ratio', 'profit_abs', 'sell_reason',
|
||||
'initial_stop_loss_abs', 'initial_stop_loss_ratio', 'stop_loss_abs',
|
||||
'stop_loss_ratio', 'min_rate', 'max_rate', 'is_open', ]
|
||||
'stop_loss_ratio', 'min_rate', 'max_rate', 'is_open', 'buy_tag']
|
||||
|
||||
|
||||
def get_latest_optimize_filename(directory: Union[Path, str], variant: str) -> str:
|
||||
|
@ -3,5 +3,5 @@ from freqtrade.enums.backteststate import BacktestState
|
||||
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
|
||||
from freqtrade.enums.signaltype import SignalType
|
||||
from freqtrade.enums.signaltype import SignalTagType, SignalType
|
||||
from freqtrade.enums.state import State
|
||||
|
@ -7,3 +7,10 @@ class SignalType(Enum):
|
||||
"""
|
||||
BUY = "buy"
|
||||
SELL = "sell"
|
||||
|
||||
|
||||
class SignalTagType(Enum):
|
||||
"""
|
||||
Enum for signal columns
|
||||
"""
|
||||
BUY_TAG = "buy_tag"
|
||||
|
@ -420,7 +420,11 @@ class FreqtradeBot(LoggingMixin):
|
||||
return False
|
||||
|
||||
# running get_signal on historical data fetched
|
||||
(buy, sell) = self.strategy.get_signal(pair, self.strategy.timeframe, analyzed_df)
|
||||
(buy, sell, buy_tag) = self.strategy.get_signal(
|
||||
pair,
|
||||
self.strategy.timeframe,
|
||||
analyzed_df
|
||||
)
|
||||
|
||||
if buy and not sell:
|
||||
stake_amount = self.wallets.get_trade_stake_amount(pair, self.edge)
|
||||
@ -429,11 +433,11 @@ class FreqtradeBot(LoggingMixin):
|
||||
if ((bid_check_dom.get('enabled', False)) and
|
||||
(bid_check_dom.get('bids_to_ask_delta', 0) > 0)):
|
||||
if self._check_depth_of_market_buy(pair, bid_check_dom):
|
||||
return self.execute_buy(pair, stake_amount)
|
||||
return self.execute_buy(pair, stake_amount, buy_tag=buy_tag)
|
||||
else:
|
||||
return False
|
||||
|
||||
return self.execute_buy(pair, stake_amount)
|
||||
return self.execute_buy(pair, stake_amount, buy_tag=buy_tag)
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -462,7 +466,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
return False
|
||||
|
||||
def execute_buy(self, pair: str, stake_amount: float, price: Optional[float] = None,
|
||||
forcebuy: bool = False) -> bool:
|
||||
forcebuy: bool = False, buy_tag: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Executes a limit buy for the given pair
|
||||
:param pair: pair for which we want to create a LIMIT_BUY
|
||||
@ -565,6 +569,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
exchange=self.exchange.id,
|
||||
open_order_id=order_id,
|
||||
strategy=self.strategy.get_strategy_name(),
|
||||
buy_tag=buy_tag,
|
||||
timeframe=timeframe_to_minutes(self.config['timeframe'])
|
||||
)
|
||||
trade.orders.append(order_obj)
|
||||
@ -590,6 +595,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
msg = {
|
||||
'trade_id': trade.id,
|
||||
'type': RPCMessageType.BUY,
|
||||
'buy_tag': trade.buy_tag,
|
||||
'exchange': self.exchange.name.capitalize(),
|
||||
'pair': trade.pair,
|
||||
'limit': trade.open_rate,
|
||||
@ -614,6 +620,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
msg = {
|
||||
'trade_id': trade.id,
|
||||
'type': RPCMessageType.BUY_CANCEL,
|
||||
'buy_tag': trade.buy_tag,
|
||||
'exchange': self.exchange.name.capitalize(),
|
||||
'pair': trade.pair,
|
||||
'limit': trade.open_rate,
|
||||
@ -634,6 +641,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
msg = {
|
||||
'trade_id': trade.id,
|
||||
'type': RPCMessageType.BUY_FILL,
|
||||
'buy_tag': trade.buy_tag,
|
||||
'exchange': self.exchange.name.capitalize(),
|
||||
'pair': trade.pair,
|
||||
'open_rate': trade.open_rate,
|
||||
@ -692,7 +700,11 @@ class FreqtradeBot(LoggingMixin):
|
||||
analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair,
|
||||
self.strategy.timeframe)
|
||||
|
||||
(buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.timeframe, analyzed_df)
|
||||
(buy, sell, _) = self.strategy.get_signal(
|
||||
trade.pair,
|
||||
self.strategy.timeframe,
|
||||
analyzed_df
|
||||
)
|
||||
|
||||
logger.debug('checking sell')
|
||||
sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
|
||||
|
@ -43,6 +43,7 @@ CLOSE_IDX = 3
|
||||
SELL_IDX = 4
|
||||
LOW_IDX = 5
|
||||
HIGH_IDX = 6
|
||||
BUY_TAG_IDX = 7
|
||||
|
||||
|
||||
class Backtesting:
|
||||
@ -217,9 +218,13 @@ class Backtesting:
|
||||
for pair, pair_data in processed.items():
|
||||
self.check_abort()
|
||||
self.progress.increment()
|
||||
has_buy_tag = 'buy_tag' in pair_data
|
||||
headers = headers + ['buy_tag'] if has_buy_tag else headers
|
||||
if not pair_data.empty:
|
||||
pair_data.loc[:, 'buy'] = 0 # cleanup if buy_signal is exist
|
||||
pair_data.loc[:, 'sell'] = 0 # cleanup if sell_signal is exist
|
||||
if has_buy_tag:
|
||||
pair_data.loc[:, 'buy_tag'] = None # cleanup if buy_tag is exist
|
||||
|
||||
df_analyzed = self.strategy.advise_sell(
|
||||
self.strategy.advise_buy(pair_data, {'pair': pair}), {'pair': pair})[headers].copy()
|
||||
@ -230,6 +235,8 @@ class Backtesting:
|
||||
# from the previous candle
|
||||
df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1)
|
||||
df_analyzed.loc[:, 'sell'] = df_analyzed.loc[:, 'sell'].shift(1)
|
||||
if has_buy_tag:
|
||||
df_analyzed.loc[:, 'buy_tag'] = df_analyzed.loc[:, 'buy_tag'].shift(1)
|
||||
|
||||
df_analyzed.drop(df_analyzed.head(1).index, inplace=True)
|
||||
|
||||
@ -360,6 +367,7 @@ class Backtesting:
|
||||
|
||||
if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount):
|
||||
# Enter trade
|
||||
has_buy_tag = len(row) >= BUY_TAG_IDX + 1
|
||||
trade = LocalTrade(
|
||||
pair=pair,
|
||||
open_rate=row[OPEN_IDX],
|
||||
@ -369,6 +377,7 @@ class Backtesting:
|
||||
fee_open=self.fee,
|
||||
fee_close=self.fee,
|
||||
is_open=True,
|
||||
buy_tag=row[BUY_TAG_IDX] if has_buy_tag else None,
|
||||
exchange='backtesting',
|
||||
)
|
||||
return trade
|
||||
|
@ -47,6 +47,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
||||
min_rate = get_column_def(cols, 'min_rate', 'null')
|
||||
sell_reason = get_column_def(cols, 'sell_reason', 'null')
|
||||
strategy = get_column_def(cols, 'strategy', 'null')
|
||||
buy_tag = get_column_def(cols, 'buy_tag', 'null')
|
||||
# If ticker-interval existed use that, else null.
|
||||
if has_column(cols, 'ticker_interval'):
|
||||
timeframe = get_column_def(cols, 'timeframe', 'ticker_interval')
|
||||
@ -80,7 +81,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
||||
stake_amount, amount, amount_requested, open_date, close_date, open_order_id,
|
||||
stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct,
|
||||
stoploss_order_id, stoploss_last_update,
|
||||
max_rate, min_rate, sell_reason, sell_order_status, strategy,
|
||||
max_rate, min_rate, sell_reason, sell_order_status, strategy, buy_tag,
|
||||
timeframe, open_trade_value, close_profit_abs
|
||||
)
|
||||
select id, lower(exchange),
|
||||
@ -103,7 +104,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
||||
{stoploss_order_id} stoploss_order_id, {stoploss_last_update} stoploss_last_update,
|
||||
{max_rate} max_rate, {min_rate} min_rate, {sell_reason} sell_reason,
|
||||
{sell_order_status} sell_order_status,
|
||||
{strategy} strategy, {timeframe} timeframe,
|
||||
{strategy} strategy, {buy_tag} buy_tag, {timeframe} timeframe,
|
||||
{open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs
|
||||
from {table_back_name}
|
||||
"""))
|
||||
@ -160,7 +161,7 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
|
||||
table_back_name = get_backup_name(tabs, 'trades_bak')
|
||||
|
||||
# Check for latest column
|
||||
if not has_column(cols, 'open_trade_value'):
|
||||
if not has_column(cols, 'buy_tag'):
|
||||
logger.info(f'Running database migration for trades - backup: {table_back_name}')
|
||||
migrate_trades_table(decl_base, inspector, engine, table_back_name, cols)
|
||||
# Reread columns - the above recreated the table!
|
||||
|
@ -257,6 +257,7 @@ class LocalTrade():
|
||||
sell_reason: str = ''
|
||||
sell_order_status: str = ''
|
||||
strategy: str = ''
|
||||
buy_tag: Optional[str] = None
|
||||
timeframe: Optional[int] = None
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@ -288,6 +289,7 @@ class LocalTrade():
|
||||
'amount_requested': round(self.amount_requested, 8) if self.amount_requested else None,
|
||||
'stake_amount': round(self.stake_amount, 8),
|
||||
'strategy': self.strategy,
|
||||
'buy_tag': self.buy_tag,
|
||||
'timeframe': self.timeframe,
|
||||
|
||||
'fee_open': self.fee_open,
|
||||
@ -703,6 +705,7 @@ class Trade(_DECL_BASE, LocalTrade):
|
||||
sell_reason = Column(String(100), nullable=True)
|
||||
sell_order_status = Column(String(100), nullable=True)
|
||||
strategy = Column(String(100), nullable=True)
|
||||
buy_tag = Column(String(100), nullable=True)
|
||||
timeframe = Column(Integer, nullable=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -151,6 +151,7 @@ class TradeSchema(BaseModel):
|
||||
amount_requested: float
|
||||
stake_amount: float
|
||||
strategy: str
|
||||
buy_tag: Optional[str]
|
||||
timeframe: int
|
||||
fee_open: Optional[float]
|
||||
fee_open_cost: Optional[float]
|
||||
|
@ -208,15 +208,25 @@ class Telegram(RPCHandler):
|
||||
else:
|
||||
msg['stake_amount_fiat'] = 0
|
||||
|
||||
message = (f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}"
|
||||
content = []
|
||||
content.append(
|
||||
f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}"
|
||||
f" (#{msg['trade_id']})\n"
|
||||
f"*Amount:* `{msg['amount']:.8f}`\n"
|
||||
f"*Open Rate:* `{msg['limit']:.8f}`\n"
|
||||
f"*Current Rate:* `{msg['current_rate']:.8f}`\n"
|
||||
f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}")
|
||||
|
||||
)
|
||||
if msg.get('buy_tag', None):
|
||||
content.append(f"*Buy Tag:* `{msg['buy_tag']}`\n")
|
||||
content.append(f"*Amount:* `{msg['amount']:.8f}`\n")
|
||||
content.append(f"*Open Rate:* `{msg['limit']:.8f}`\n")
|
||||
content.append(f"*Current Rate:* `{msg['current_rate']:.8f}`\n")
|
||||
content.append(
|
||||
f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}"
|
||||
)
|
||||
if msg.get('fiat_currency', None):
|
||||
message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}"
|
||||
content.append(
|
||||
f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}"
|
||||
)
|
||||
|
||||
message = ''.join(content)
|
||||
message += ")`"
|
||||
return message
|
||||
|
||||
@ -354,6 +364,7 @@ class Telegram(RPCHandler):
|
||||
"*Trade ID:* `{trade_id}` `(since {open_date_hum})`",
|
||||
"*Current Pair:* {pair}",
|
||||
"*Amount:* `{amount} ({stake_amount} {base_currency})`",
|
||||
"*Buy Tag:* `{buy_tag}`" if r['buy_tag'] else "",
|
||||
"*Open Rate:* `{open_rate:.8f}`",
|
||||
"*Close Rate:* `{close_rate}`" if r['close_rate'] else "",
|
||||
"*Current Rate:* `{current_rate:.8f}`",
|
||||
|
@ -13,7 +13,7 @@ from pandas import DataFrame
|
||||
|
||||
from freqtrade.constants import ListPairsWithTimeframes
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import SellType, SignalType
|
||||
from freqtrade.enums import SellType, SignalTagType, SignalType
|
||||
from freqtrade.exceptions import OperationalException, StrategyError
|
||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||
@ -422,6 +422,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
logger.debug("Skipping TA Analysis for already analyzed candle")
|
||||
dataframe['buy'] = 0
|
||||
dataframe['sell'] = 0
|
||||
dataframe['buy_tag'] = None
|
||||
|
||||
# Other Defs in strategy that want to be called every loop here
|
||||
# twitter_sell = self.watch_twitter_feed(dataframe, metadata)
|
||||
@ -496,7 +497,12 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
else:
|
||||
raise StrategyError(message)
|
||||
|
||||
def get_signal(self, pair: str, timeframe: str, dataframe: DataFrame) -> Tuple[bool, bool]:
|
||||
def get_signal(
|
||||
self,
|
||||
pair: str,
|
||||
timeframe: str,
|
||||
dataframe: DataFrame
|
||||
) -> Tuple[bool, bool, Optional[str]]:
|
||||
"""
|
||||
Calculates current signal based based on the buy / sell columns of the dataframe.
|
||||
Used by Bot to get the signal to buy or sell
|
||||
@ -507,7 +513,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
"""
|
||||
if not isinstance(dataframe, DataFrame) or dataframe.empty:
|
||||
logger.warning(f'Empty candle (OHLCV) data for pair {pair}')
|
||||
return False, False
|
||||
return False, False, None
|
||||
|
||||
latest_date = dataframe['date'].max()
|
||||
latest = dataframe.loc[dataframe['date'] == latest_date].iloc[-1]
|
||||
@ -522,9 +528,12 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
'Outdated history for pair %s. Last tick is %s minutes old',
|
||||
pair, int((arrow.utcnow() - latest_date).total_seconds() // 60)
|
||||
)
|
||||
return False, False
|
||||
return False, False, None
|
||||
|
||||
buy = latest[SignalType.BUY.value] == 1
|
||||
sell = latest[SignalType.SELL.value] == 1
|
||||
buy_tag = latest.get(SignalTagType.BUY_TAG.value, None)
|
||||
|
||||
(buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1
|
||||
logger.debug('trigger: %s (pair=%s) buy=%s sell=%s',
|
||||
latest['date'], pair, str(buy), str(sell))
|
||||
timeframe_seconds = timeframe_to_seconds(timeframe)
|
||||
@ -532,8 +541,8 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
current_time=datetime.now(timezone.utc),
|
||||
timeframe_seconds=timeframe_seconds,
|
||||
buy=buy):
|
||||
return False, sell
|
||||
return buy, sell
|
||||
return False, sell, buy_tag
|
||||
return buy, sell, buy_tag
|
||||
|
||||
def ignore_expired_candle(self, latest_date: datetime, current_time: datetime,
|
||||
timeframe_seconds: int, buy: bool):
|
||||
|
@ -182,7 +182,7 @@ def get_patched_worker(mocker, config) -> Worker:
|
||||
return Worker(args=None, config=config)
|
||||
|
||||
|
||||
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None:
|
||||
def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False, None)) -> None:
|
||||
"""
|
||||
:param mocker: mocker to patch IStrategy class
|
||||
:param value: which value IStrategy.get_signal() must return
|
||||
|
@ -29,7 +29,6 @@ from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe,
|
||||
|
||||
tests_start_time = arrow.get(2018, 10, 3)
|
||||
timeframe_in_minute = 60
|
||||
_ohlc = {'date': 0, 'buy': 1, 'open': 2, 'high': 3, 'low': 4, 'close': 5, 'sell': 6, 'volume': 7}
|
||||
|
||||
# Helpers for this test file
|
||||
|
||||
|
@ -18,6 +18,7 @@ class BTrade(NamedTuple):
|
||||
sell_reason: SellType
|
||||
open_tick: int
|
||||
close_tick: int
|
||||
buy_tag: Optional[str] = None
|
||||
|
||||
|
||||
class BTContainer(NamedTuple):
|
||||
@ -44,6 +45,7 @@ def _get_frame_time_from_offset(offset):
|
||||
|
||||
def _build_backtest_dataframe(data):
|
||||
columns = ['date', 'open', 'high', 'low', 'close', 'volume', 'buy', 'sell']
|
||||
columns = columns + ['buy_tag'] if len(data[0]) == 9 else columns
|
||||
|
||||
frame = DataFrame.from_records(data, columns=columns)
|
||||
frame['date'] = frame['date'].apply(_get_frame_time_from_offset)
|
||||
|
@ -516,6 +516,26 @@ tc32 = BTContainer(data=[
|
||||
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1)]
|
||||
)
|
||||
|
||||
# Test 33: trailing_stop should be triggered immediately on trade open candle.
|
||||
# stop-loss: 1%, ROI: 10% (should not apply)
|
||||
tc33 = BTContainer(data=[
|
||||
# D O H L C V B S BT
|
||||
[0, 5000, 5050, 4950, 5000, 6172, 1, 0, 'buy_signal_01'],
|
||||
[1, 5000, 5500, 5000, 4900, 6172, 0, 0, None], # enter trade (signal on last candle) and stop
|
||||
[2, 4900, 5250, 4500, 5100, 6172, 0, 0, None],
|
||||
[3, 5100, 5100, 4650, 4750, 6172, 0, 0, None],
|
||||
[4, 4750, 4950, 4350, 4750, 6172, 0, 0, None]],
|
||||
stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.01, trailing_stop=True,
|
||||
trailing_only_offset_is_reached=True, trailing_stop_positive_offset=0.02,
|
||||
trailing_stop_positive=0.01, use_custom_stoploss=True,
|
||||
trades=[BTrade(
|
||||
sell_reason=SellType.TRAILING_STOP_LOSS,
|
||||
open_tick=1,
|
||||
close_tick=1,
|
||||
buy_tag='buy_signal_01'
|
||||
)]
|
||||
)
|
||||
|
||||
TESTS = [
|
||||
tc0,
|
||||
tc1,
|
||||
@ -550,6 +570,7 @@ TESTS = [
|
||||
tc30,
|
||||
tc31,
|
||||
tc32,
|
||||
tc33,
|
||||
]
|
||||
|
||||
|
||||
@ -599,5 +620,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
|
||||
for c, trade in enumerate(data.trades):
|
||||
res = results.iloc[c]
|
||||
assert res.sell_reason == trade.sell_reason.value
|
||||
assert res.buy_tag == trade.buy_tag
|
||||
assert res.open_date == _get_frame_time_from_offset(trade.open_tick)
|
||||
assert res.close_date == _get_frame_time_from_offset(trade.close_tick)
|
||||
|
@ -496,6 +496,7 @@ def test_backtest__enter_trade(default_conf, fee, mocker) -> None:
|
||||
0, # Sell
|
||||
0.00099, # Low
|
||||
0.0012, # High
|
||||
'', # Buy Signal Name
|
||||
]
|
||||
trade = backtesting._enter_trade(pair, row=row)
|
||||
assert isinstance(trade, LocalTrade)
|
||||
@ -583,6 +584,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
|
||||
'min_rate': [0.1038, 0.10302485],
|
||||
'max_rate': [0.10501, 0.1038888],
|
||||
'is_open': [False, False],
|
||||
'buy_tag': [None, None],
|
||||
})
|
||||
pd.testing.assert_frame_equal(results, expected)
|
||||
data_pair = processed[pair]
|
||||
|
@ -35,7 +35,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.RUNNING
|
||||
@ -69,6 +69,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
'min_rate': ANY,
|
||||
'max_rate': ANY,
|
||||
'strategy': ANY,
|
||||
'buy_tag': ANY,
|
||||
'timeframe': 5,
|
||||
'open_order_id': ANY,
|
||||
'close_date': None,
|
||||
@ -135,6 +136,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
'min_rate': ANY,
|
||||
'max_rate': ANY,
|
||||
'strategy': ANY,
|
||||
'buy_tag': ANY,
|
||||
'timeframe': ANY,
|
||||
'open_order_id': ANY,
|
||||
'close_date': None,
|
||||
@ -190,7 +192,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
)
|
||||
del default_conf['fiat_display_currency']
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.RUNNING
|
||||
@ -237,7 +239,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@ -369,7 +371,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@ -457,7 +459,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
stake_currency = default_conf['stake_currency']
|
||||
fiat_display_currency = default_conf['fiat_display_currency']
|
||||
|
||||
@ -524,7 +526,7 @@ def test_rpc_balance_handle_error(default_conf, mocker):
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
with pytest.raises(RPCException, match="Error getting current tickers."):
|
||||
@ -565,7 +567,7 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
|
||||
)
|
||||
default_conf['dry_run'] = False
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
rpc._fiat_converter = CryptoToFiatConverter()
|
||||
|
||||
@ -610,7 +612,7 @@ def test_rpc_start(mocker, default_conf) -> None:
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.STOPPED
|
||||
|
||||
@ -631,7 +633,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.RUNNING
|
||||
|
||||
@ -653,7 +655,7 @@ def test_rpc_stopbuy(mocker, default_conf) -> None:
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
freqtradebot.state = State.RUNNING
|
||||
|
||||
@ -685,7 +687,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
|
||||
mocker.patch('freqtrade.wallets.Wallets.get_free', return_value=1000)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
@ -803,7 +805,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
# Create some test data
|
||||
@ -836,7 +838,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
|
||||
counts = rpc._rpc_count()
|
||||
@ -861,7 +863,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order_open) ->
|
||||
)
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
pair = 'ETH/BTC'
|
||||
trade = rpc._rpc_forcebuy(pair, None)
|
||||
@ -887,7 +889,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order_open) ->
|
||||
# Test not buying
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
freqtradebot.config['stake_amount'] = 0
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
pair = 'TKN/BTC'
|
||||
trade = rpc._rpc_forcebuy(pair, None)
|
||||
@ -900,7 +902,7 @@ def test_rpcforcebuy_stopped(mocker, default_conf) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
pair = 'ETH/BTC'
|
||||
with pytest.raises(RPCException, match=r'trader is not running'):
|
||||
@ -911,7 +913,7 @@ def test_rpcforcebuy_disabled(mocker, default_conf) -> None:
|
||||
mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock())
|
||||
|
||||
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
rpc = RPC(freqtradebot)
|
||||
pair = 'ETH/BTC'
|
||||
with pytest.raises(RPCException, match=r'Forcebuy not enabled.'):
|
||||
|
@ -442,7 +442,7 @@ def test_api_balance(botclient, mocker, rpc_balance):
|
||||
|
||||
def test_api_count(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -504,7 +504,7 @@ def test_api_locks(botclient):
|
||||
|
||||
def test_api_show_config(botclient, mocker):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/show_config")
|
||||
assert_response(rc)
|
||||
@ -522,7 +522,7 @@ def test_api_show_config(botclient, mocker):
|
||||
|
||||
def test_api_daily(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -540,7 +540,7 @@ def test_api_daily(botclient, mocker, ticker, fee, markets):
|
||||
|
||||
def test_api_trades(botclient, mocker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets)
|
||||
@ -568,7 +568,7 @@ def test_api_trades(botclient, mocker, fee, markets):
|
||||
|
||||
def test_api_trade_single(botclient, mocker, fee, ticker, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets),
|
||||
@ -588,7 +588,7 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets):
|
||||
|
||||
def test_api_delete_trade(botclient, mocker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
stoploss_mock = MagicMock()
|
||||
cancel_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@ -662,7 +662,7 @@ def test_api_logs(botclient):
|
||||
|
||||
def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -678,7 +678,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets):
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_api_profit(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -729,7 +729,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets):
|
||||
@pytest.mark.usefixtures("init_persistence")
|
||||
def test_api_stats(botclient, mocker, ticker, fee, markets,):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -757,7 +757,7 @@ def test_api_stats(botclient, mocker, ticker, fee, markets,):
|
||||
|
||||
def test_api_performance(botclient, fee):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
|
||||
trade = Trade(
|
||||
pair='LTC/ETH',
|
||||
@ -803,7 +803,7 @@ def test_api_performance(botclient, fee):
|
||||
|
||||
def test_api_status(botclient, mocker, ticker, fee, markets):
|
||||
ftbot, client = botclient
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
@ -875,6 +875,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': 'DefaultStrategy',
|
||||
'buy_tag': None,
|
||||
'timeframe': 5,
|
||||
'exchange': 'binance',
|
||||
}
|
||||
@ -1029,6 +1030,7 @@ def test_api_forcebuy(botclient, mocker, fee):
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': 'DefaultStrategy',
|
||||
'buy_tag': None,
|
||||
'timeframe': 5,
|
||||
'exchange': 'binance',
|
||||
}
|
||||
@ -1044,7 +1046,7 @@ def test_api_forcesell(botclient, mocker, ticker, fee, markets):
|
||||
markets=PropertyMock(return_value=markets),
|
||||
_is_dry_limit_order_filled=MagicMock(return_value=False),
|
||||
)
|
||||
patch_get_signal(ftbot, (True, False))
|
||||
patch_get_signal(ftbot, (True, False, None))
|
||||
|
||||
rc = client_post(client, f"{BASE_URI}/forcesell",
|
||||
data='{"tradeid": "1"}')
|
||||
@ -1185,8 +1187,10 @@ def test_api_plot_config(botclient):
|
||||
assert_response(rc)
|
||||
assert rc.json() == {}
|
||||
|
||||
ftbot.strategy.plot_config = {'main_plot': {'sma': {}},
|
||||
'subplots': {'RSI': {'rsi': {'color': 'red'}}}}
|
||||
ftbot.strategy.plot_config = {
|
||||
'main_plot': {'sma': {}},
|
||||
'subplots': {'RSI': {'rsi': {'color': 'red'}}}
|
||||
}
|
||||
rc = client_get(client, f"{BASE_URI}/plot_config")
|
||||
assert_response(rc)
|
||||
assert rc.json() == ftbot.strategy.plot_config
|
||||
|
@ -119,7 +119,7 @@ def test_authorized_only(default_conf, mocker, caplog, update) -> None:
|
||||
rpc = RPC(bot)
|
||||
dummy = DummyCls(rpc, default_conf)
|
||||
|
||||
patch_get_signal(bot, (True, False))
|
||||
patch_get_signal(bot, (True, False, None))
|
||||
dummy.dummy_handler(update=update, context=MagicMock())
|
||||
assert dummy.state['called'] is True
|
||||
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
|
||||
@ -139,7 +139,7 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
|
||||
rpc = RPC(bot)
|
||||
dummy = DummyCls(rpc, default_conf)
|
||||
|
||||
patch_get_signal(bot, (True, False))
|
||||
patch_get_signal(bot, (True, False, None))
|
||||
dummy.dummy_handler(update=update, context=MagicMock())
|
||||
assert dummy.state['called'] is False
|
||||
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
|
||||
@ -155,7 +155,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog, update) -> None
|
||||
bot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(bot)
|
||||
dummy = DummyCls(rpc, default_conf)
|
||||
patch_get_signal(bot, (True, False))
|
||||
patch_get_signal(bot, (True, False, None))
|
||||
|
||||
dummy.dummy_exception(update=update, context=MagicMock())
|
||||
assert dummy.state['called'] is False
|
||||
@ -185,6 +185,7 @@ def test_telegram_status(default_conf, update, mocker) -> None:
|
||||
'current_rate': 1.098e-05,
|
||||
'amount': 90.99181074,
|
||||
'stake_amount': 90.99181074,
|
||||
'buy_tag': None,
|
||||
'close_profit_pct': None,
|
||||
'profit': -0.0059,
|
||||
'profit_pct': -0.59,
|
||||
@ -228,7 +229,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
# Status is also enabled when stopped
|
||||
@ -285,7 +286,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
# Status table is also enabled when stopped
|
||||
@ -329,7 +330,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
@ -400,7 +401,7 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
|
||||
)
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Try invalid data
|
||||
msg_mock.reset_mock()
|
||||
@ -432,7 +433,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
)
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
telegram._profit(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
@ -487,7 +488,7 @@ def test_telegram_stats(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
telegram._stats(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
@ -513,7 +514,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick
|
||||
side_effect=lambda a, b: f"{a}/{b}")
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
telegram._balance(update=update, context=MagicMock())
|
||||
result = msg_mock.call_args_list[0][0][0]
|
||||
@ -536,7 +537,7 @@ def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value={})
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
freqtradebot.config['dry_run'] = False
|
||||
telegram._balance(update=update, context=MagicMock())
|
||||
@ -549,7 +550,7 @@ def test_balance_handle_empty_response_dry(default_conf, update, mocker) -> None
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value={})
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
telegram._balance(update=update, context=MagicMock())
|
||||
result = msg_mock.call_args_list[0][0][0]
|
||||
@ -578,7 +579,7 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None
|
||||
})
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
telegram._balance(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count > 1
|
||||
@ -677,7 +678,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee,
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
telegram = Telegram(rpc, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
@ -736,7 +737,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee,
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
telegram = Telegram(rpc, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
@ -797,7 +798,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
rpc = RPC(freqtradebot)
|
||||
telegram = Telegram(rpc, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
@ -838,7 +839,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
||||
return_value=15000.0)
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Trader is not running
|
||||
freqtradebot.state = State.STOPPED
|
||||
@ -876,7 +877,7 @@ def test_forcebuy_handle(default_conf, update, mocker) -> None:
|
||||
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
|
||||
|
||||
telegram, freqtradebot, _ = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# /forcebuy ETH/BTC
|
||||
context = MagicMock()
|
||||
@ -905,7 +906,7 @@ def test_forcebuy_handle_exception(default_conf, update, mocker) -> None:
|
||||
mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
update.message.text = '/forcebuy ETH/Nonepair'
|
||||
telegram._forcebuy(update=update, context=MagicMock())
|
||||
@ -922,7 +923,7 @@ def test_forcebuy_no_pair(default_conf, update, mocker) -> None:
|
||||
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
context = MagicMock()
|
||||
context.args = []
|
||||
@ -950,7 +951,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
# Create some test data
|
||||
freqtradebot.enter_positions()
|
||||
@ -978,7 +979,7 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
|
||||
freqtradebot.state = State.STOPPED
|
||||
telegram._count(update=update, context=MagicMock())
|
||||
@ -1007,7 +1008,7 @@ def test_telegram_lock_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
get_fee=fee,
|
||||
)
|
||||
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
patch_get_signal(freqtradebot, (True, False))
|
||||
patch_get_signal(freqtradebot, (True, False, None))
|
||||
telegram._locks(update=update, context=MagicMock())
|
||||
assert msg_mock.call_count == 1
|
||||
assert 'No active locks.' in msg_mock.call_args_list[0][0][0]
|
||||
@ -1253,6 +1254,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None:
|
||||
msg = {
|
||||
'type': RPCMessageType.BUY,
|
||||
'trade_id': 1,
|
||||
'buy_tag': 'buy_signal_01',
|
||||
'exchange': 'Binance',
|
||||
'pair': 'ETH/BTC',
|
||||
'limit': 1.099e-05,
|
||||
@ -1270,6 +1272,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None:
|
||||
telegram.send_msg(msg)
|
||||
assert msg_mock.call_args[0][0] \
|
||||
== '\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n' \
|
||||
'*Buy Tag:* `buy_signal_01`\n' \
|
||||
'*Amount:* `1333.33333333`\n' \
|
||||
'*Open Rate:* `0.00001099`\n' \
|
||||
'*Current Rate:* `0.00001099`\n' \
|
||||
@ -1297,6 +1300,7 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None:
|
||||
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.BUY_CANCEL,
|
||||
'buy_tag': 'buy_signal_01',
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'ETH/BTC',
|
||||
@ -1314,6 +1318,7 @@ def test_send_msg_buy_fill_notification(default_conf, mocker) -> None:
|
||||
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.BUY_FILL,
|
||||
'buy_tag': 'buy_signal_01',
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'ETH/USDT',
|
||||
@ -1498,6 +1503,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None:
|
||||
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.BUY,
|
||||
'buy_tag': 'buy_signal_01',
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'ETH/BTC',
|
||||
@ -1512,6 +1518,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None:
|
||||
'open_date': arrow.utcnow().shift(hours=-1)
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == ('\N{LARGE BLUE CIRCLE} *Binance:* Buying ETH/BTC (#1)\n'
|
||||
'*Buy Tag:* `buy_signal_01`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00001099`\n'
|
||||
'*Current Rate:* `0.00001099`\n'
|
||||
|
@ -38,15 +38,20 @@ def test_returns_latest_signal(mocker, default_conf, ohlcv_history):
|
||||
mocked_history['buy'] = 0
|
||||
mocked_history.loc[1, 'sell'] = 1
|
||||
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True)
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, True, None)
|
||||
mocked_history.loc[1, 'sell'] = 0
|
||||
mocked_history.loc[1, 'buy'] = 1
|
||||
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False)
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, None)
|
||||
mocked_history.loc[1, 'sell'] = 0
|
||||
mocked_history.loc[1, 'buy'] = 0
|
||||
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False)
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (False, False, None)
|
||||
mocked_history.loc[1, 'sell'] = 0
|
||||
mocked_history.loc[1, 'buy'] = 1
|
||||
mocked_history.loc[1, 'buy_tag'] = 'buy_signal_01'
|
||||
|
||||
assert _STRATEGY.get_signal('ETH/BTC', '5m', mocked_history) == (True, False, 'buy_signal_01')
|
||||
|
||||
|
||||
def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
|
||||
@ -63,15 +68,21 @@ def test_analyze_pair_empty(default_conf, mocker, caplog, ohlcv_history):
|
||||
|
||||
|
||||
def test_get_signal_empty(default_conf, mocker, caplog):
|
||||
assert (False, False) == _STRATEGY.get_signal('foo', default_conf['timeframe'], DataFrame())
|
||||
assert (False, False, None) == _STRATEGY.get_signal(
|
||||
'foo', default_conf['timeframe'], DataFrame()
|
||||
)
|
||||
assert log_has('Empty candle (OHLCV) data for pair foo', caplog)
|
||||
caplog.clear()
|
||||
|
||||
assert (False, False) == _STRATEGY.get_signal('bar', default_conf['timeframe'], None)
|
||||
assert (False, False, None) == _STRATEGY.get_signal('bar', default_conf['timeframe'], None)
|
||||
assert log_has('Empty candle (OHLCV) data for pair bar', caplog)
|
||||
caplog.clear()
|
||||
|
||||
assert (False, False) == _STRATEGY.get_signal('baz', default_conf['timeframe'], DataFrame([]))
|
||||
assert (False, False, None) == _STRATEGY.get_signal(
|
||||
'baz',
|
||||
default_conf['timeframe'],
|
||||
DataFrame([])
|
||||
)
|
||||
assert log_has('Empty candle (OHLCV) data for pair baz', caplog)
|
||||
|
||||
|
||||
@ -107,7 +118,11 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history):
|
||||
caplog.set_level(logging.INFO)
|
||||
mocker.patch.object(_STRATEGY, 'assert_df')
|
||||
|
||||
assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], mocked_history)
|
||||
assert (False, False, None) == _STRATEGY.get_signal(
|
||||
'xyz',
|
||||
default_conf['timeframe'],
|
||||
mocked_history
|
||||
)
|
||||
assert log_has('Outdated history for pair xyz. Last tick is 16 minutes old', caplog)
|
||||
|
||||
|
||||
|
@ -536,7 +536,7 @@ def test_create_trade_no_signal(default_conf, fee, mocker) -> None:
|
||||
)
|
||||
default_conf['stake_amount'] = 10
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
patch_get_signal(freqtrade, value=(False, False))
|
||||
patch_get_signal(freqtrade, value=(False, False, None))
|
||||
|
||||
Trade.query = MagicMock()
|
||||
Trade.query.filter = MagicMock()
|
||||
@ -757,7 +757,10 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None:
|
||||
refresh_latest_ohlcv=refresh_mock,
|
||||
)
|
||||
inf_pairs = MagicMock(return_value=[("BTC/ETH", '1m'), ("ETH/USDT", "1h")])
|
||||
mocker.patch('freqtrade.strategy.interface.IStrategy.get_signal', return_value=(False, False))
|
||||
mocker.patch(
|
||||
'freqtrade.strategy.interface.IStrategy.get_signal',
|
||||
return_value=(False, False, '')
|
||||
)
|
||||
mocker.patch('time.sleep', return_value=None)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
@ -1857,7 +1860,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limi
|
||||
assert trade.is_open is True
|
||||
freqtrade.wallets.update()
|
||||
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.open_order_id == limit_sell_order['id']
|
||||
|
||||
@ -1882,7 +1885,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
patch_get_signal(freqtrade, value=(True, True))
|
||||
patch_get_signal(freqtrade, value=(True, True, None))
|
||||
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
|
||||
|
||||
freqtrade.enter_positions()
|
||||
@ -1893,7 +1896,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
|
||||
assert nb_trades == 0
|
||||
|
||||
# Buy is triggering, so buying ...
|
||||
patch_get_signal(freqtrade, value=(True, False))
|
||||
patch_get_signal(freqtrade, value=(True, False, None))
|
||||
freqtrade.enter_positions()
|
||||
trades = Trade.query.all()
|
||||
nb_trades = len(trades)
|
||||
@ -1901,7 +1904,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
|
||||
assert trades[0].is_open is True
|
||||
|
||||
# Buy and Sell are not triggering, so doing nothing ...
|
||||
patch_get_signal(freqtrade, value=(False, False))
|
||||
patch_get_signal(freqtrade, value=(False, False, None))
|
||||
assert freqtrade.handle_trade(trades[0]) is False
|
||||
trades = Trade.query.all()
|
||||
nb_trades = len(trades)
|
||||
@ -1909,7 +1912,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
|
||||
assert trades[0].is_open is True
|
||||
|
||||
# Buy and Sell are triggering, so doing nothing ...
|
||||
patch_get_signal(freqtrade, value=(True, True))
|
||||
patch_get_signal(freqtrade, value=(True, True, None))
|
||||
assert freqtrade.handle_trade(trades[0]) is False
|
||||
trades = Trade.query.all()
|
||||
nb_trades = len(trades)
|
||||
@ -1917,7 +1920,7 @@ def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open,
|
||||
assert trades[0].is_open is True
|
||||
|
||||
# Sell is triggering, guess what : we are Selling!
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
trades = Trade.query.all()
|
||||
assert freqtrade.handle_trade(trades[0]) is True
|
||||
|
||||
@ -1935,7 +1938,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open,
|
||||
)
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
patch_get_signal(freqtrade, value=(True, False))
|
||||
patch_get_signal(freqtrade, value=(True, False, None))
|
||||
freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
|
||||
|
||||
freqtrade.enter_positions()
|
||||
@ -1948,7 +1951,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order_open,
|
||||
# we might just want to check if we are in a sell condition without
|
||||
# executing
|
||||
# if ROI is reached we must sell
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade)
|
||||
assert log_has("ETH/BTC - Required profit reached. sell_type=SellType.ROI",
|
||||
caplog)
|
||||
@ -1974,10 +1977,10 @@ def test_handle_trade_use_sell_signal(
|
||||
trade = Trade.query.first()
|
||||
trade.is_open = True
|
||||
|
||||
patch_get_signal(freqtrade, value=(False, False))
|
||||
patch_get_signal(freqtrade, value=(False, False, None))
|
||||
assert not freqtrade.handle_trade(trade)
|
||||
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade)
|
||||
assert log_has("ETH/BTC - Sell signal received. sell_type=SellType.SELL_SIGNAL",
|
||||
caplog)
|
||||
@ -3013,7 +3016,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
freqtrade.wallets.update()
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is False
|
||||
|
||||
freqtrade.strategy.sell_profit_offset = 0.0
|
||||
@ -3048,7 +3051,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_bu
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
freqtrade.wallets.update()
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.sell_reason == SellType.SELL_SIGNAL.value
|
||||
|
||||
@ -3079,7 +3082,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_o
|
||||
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is False
|
||||
|
||||
|
||||
@ -3111,7 +3114,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, limit_buy_
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
freqtrade.wallets.update()
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.sell_reason == SellType.SELL_SIGNAL.value
|
||||
|
||||
@ -3140,7 +3143,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, limit_buy_order_
|
||||
trade = Trade.query.first()
|
||||
amnt = trade.amount
|
||||
trade.update(limit_buy_order)
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=trade.amount * 0.985))
|
||||
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
@ -3259,11 +3262,11 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
freqtrade.wallets.update()
|
||||
patch_get_signal(freqtrade, value=(True, True))
|
||||
patch_get_signal(freqtrade, value=(True, True, None))
|
||||
assert freqtrade.handle_trade(trade) is False
|
||||
|
||||
# Test if buy-signal is absent (should sell due to roi = true)
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.sell_reason == SellType.ROI.value
|
||||
|
||||
@ -3524,11 +3527,11 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_b
|
||||
trade = Trade.query.first()
|
||||
trade.update(limit_buy_order)
|
||||
# Sell due to min_roi_reached
|
||||
patch_get_signal(freqtrade, value=(True, True))
|
||||
patch_get_signal(freqtrade, value=(True, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
|
||||
# Test if buy-signal is absent
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.sell_reason == SellType.SELL_SIGNAL.value
|
||||
|
||||
@ -4056,7 +4059,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order_open, limit_buy_o
|
||||
freqtrade.wallets.update()
|
||||
assert trade.is_open is True
|
||||
|
||||
patch_get_signal(freqtrade, value=(False, True))
|
||||
patch_get_signal(freqtrade, value=(False, True, None))
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
assert trade.close_rate_requested == order_book_l2.return_value['asks'][0][0]
|
||||
|
||||
|
@ -861,6 +861,7 @@ def test_to_json(default_conf, fee):
|
||||
open_date=arrow.utcnow().shift(hours=-2).datetime,
|
||||
open_rate=0.123,
|
||||
exchange='binance',
|
||||
buy_tag=None,
|
||||
open_order_id='dry_run_buy_12345'
|
||||
)
|
||||
result = trade.to_json()
|
||||
@ -910,6 +911,7 @@ def test_to_json(default_conf, fee):
|
||||
'min_rate': None,
|
||||
'max_rate': None,
|
||||
'strategy': None,
|
||||
'buy_tag': None,
|
||||
'timeframe': None,
|
||||
'exchange': 'binance',
|
||||
}
|
||||
@ -926,6 +928,7 @@ def test_to_json(default_conf, fee):
|
||||
close_date=arrow.utcnow().shift(hours=-1).datetime,
|
||||
open_rate=0.123,
|
||||
close_rate=0.125,
|
||||
buy_tag='buys_signal_001',
|
||||
exchange='binance',
|
||||
)
|
||||
result = trade.to_json()
|
||||
@ -975,6 +978,7 @@ def test_to_json(default_conf, fee):
|
||||
'sell_reason': None,
|
||||
'sell_order_status': None,
|
||||
'strategy': None,
|
||||
'buy_tag': 'buys_signal_001',
|
||||
'timeframe': None,
|
||||
'exchange': 'binance',
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user