Merge remote-tracking branch 'origin/develop' into feat/convolutional-neural-net
This commit is contained in:
@@ -408,6 +408,11 @@ def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool
|
||||
Trade.commit()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_gc(mocker) -> None:
|
||||
mocker.patch("freqtrade.main.gc_set_threshold")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_coingekko(mocker) -> None:
|
||||
"""
|
||||
|
@@ -2,13 +2,13 @@ from datetime import datetime, timezone
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
from pandas import DataFrame, Timestamp
|
||||
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import CandleType, RunMode
|
||||
from freqtrade.exceptions import ExchangeError, OperationalException
|
||||
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||
from tests.conftest import get_patched_exchange
|
||||
from tests.conftest import generate_test_data, get_patched_exchange
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candle_type', [
|
||||
@@ -144,7 +144,7 @@ def test_available_pairs(mocker, default_conf, ohlcv_history):
|
||||
assert dp.available_pairs == [("XRP/BTC", timeframe), ("UNITTEST/BTC", timeframe), ]
|
||||
|
||||
|
||||
def test_producer_pairs(mocker, default_conf, ohlcv_history):
|
||||
def test_producer_pairs(default_conf):
|
||||
dataprovider = DataProvider(default_conf, None)
|
||||
|
||||
producer = "default"
|
||||
@@ -161,9 +161,9 @@ def test_producer_pairs(mocker, default_conf, ohlcv_history):
|
||||
assert dataprovider.get_producer_pairs("bad") == []
|
||||
|
||||
|
||||
def test_get_producer_df(mocker, default_conf, ohlcv_history):
|
||||
def test_get_producer_df(default_conf):
|
||||
dataprovider = DataProvider(default_conf, None)
|
||||
|
||||
ohlcv_history = generate_test_data('5m', 150)
|
||||
pair = 'BTC/USDT'
|
||||
timeframe = default_conf['timeframe']
|
||||
candle_type = CandleType.SPOT
|
||||
@@ -207,15 +207,21 @@ def test_emit_df(mocker, default_conf, ohlcv_history):
|
||||
assert send_mock.call_count == 0
|
||||
|
||||
# Rpc is added, we call emit, should call send_msg
|
||||
dataprovider._emit_df(pair, ohlcv_history)
|
||||
dataprovider._emit_df(pair, ohlcv_history, False)
|
||||
assert send_mock.call_count == 1
|
||||
|
||||
send_mock.reset_mock()
|
||||
dataprovider._emit_df(pair, ohlcv_history, True)
|
||||
assert send_mock.call_count == 2
|
||||
|
||||
send_mock.reset_mock()
|
||||
|
||||
# No rpc added, emit called, should not call send_msg
|
||||
dataprovider_no_rpc._emit_df(pair, ohlcv_history)
|
||||
assert send_mock.call_count == 1
|
||||
dataprovider_no_rpc._emit_df(pair, ohlcv_history, False)
|
||||
assert send_mock.call_count == 0
|
||||
|
||||
|
||||
def test_refresh(mocker, default_conf, ohlcv_history):
|
||||
def test_refresh(mocker, default_conf):
|
||||
refresh_mock = MagicMock()
|
||||
mocker.patch("freqtrade.exchange.Exchange.refresh_latest_ohlcv", refresh_mock)
|
||||
|
||||
@@ -406,3 +412,80 @@ def test_dp_send_msg(default_conf):
|
||||
dp = DataProvider(default_conf, None)
|
||||
dp.send_msg(msg, always_send=True)
|
||||
assert msg not in dp._msg_queue
|
||||
|
||||
|
||||
def test_dp__add_external_df(default_conf_usdt):
|
||||
timeframe = '1h'
|
||||
default_conf_usdt["timeframe"] = timeframe
|
||||
dp = DataProvider(default_conf_usdt, None)
|
||||
df = generate_test_data(timeframe, 24, '2022-01-01 00:00:00+00:00')
|
||||
last_analyzed = datetime.now(timezone.utc)
|
||||
|
||||
res = dp._add_external_df('ETH/USDT', df, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is False
|
||||
# Why 1000 ??
|
||||
assert res[1] == 1000
|
||||
|
||||
# Hard add dataframe
|
||||
dp._replace_external_df('ETH/USDT', df, last_analyzed, timeframe, CandleType.SPOT)
|
||||
# BTC is not stored yet
|
||||
res = dp._add_external_df('BTC/USDT', df, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is False
|
||||
df_res, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
assert len(df_res) == 24
|
||||
|
||||
# Add the same dataframe again - dataframe size shall not change.
|
||||
res = dp._add_external_df('ETH/USDT', df, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is True
|
||||
assert res[1] == 0
|
||||
df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
assert len(df) == 24
|
||||
|
||||
# Add a new day.
|
||||
df2 = generate_test_data(timeframe, 24, '2022-01-02 00:00:00+00:00')
|
||||
|
||||
res = dp._add_external_df('ETH/USDT', df2, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is True
|
||||
assert res[1] == 0
|
||||
df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
assert len(df) == 48
|
||||
|
||||
# Add a dataframe with a 12 hour offset - so 12 candles are overlapping, and 12 valid.
|
||||
df3 = generate_test_data(timeframe, 24, '2022-01-02 12:00:00+00:00')
|
||||
|
||||
res = dp._add_external_df('ETH/USDT', df3, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is True
|
||||
assert res[1] == 0
|
||||
df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
# New length = 48 + 12 (since we have a 12 hour offset).
|
||||
assert len(df) == 60
|
||||
assert df.iloc[-1]['date'] == df3.iloc[-1]['date']
|
||||
assert df.iloc[-1]['date'] == Timestamp('2022-01-03 11:00:00+00:00')
|
||||
|
||||
# Generate 1 new candle
|
||||
df4 = generate_test_data(timeframe, 1, '2022-01-03 12:00:00+00:00')
|
||||
res = dp._add_external_df('ETH/USDT', df4, last_analyzed, timeframe, CandleType.SPOT)
|
||||
# assert res[0] is True
|
||||
# assert res[1] == 0
|
||||
df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
# New length = 61 + 1
|
||||
assert len(df) == 61
|
||||
assert df.iloc[-2]['date'] == Timestamp('2022-01-03 11:00:00+00:00')
|
||||
assert df.iloc[-1]['date'] == Timestamp('2022-01-03 12:00:00+00:00')
|
||||
|
||||
# Gap in the data ...
|
||||
df4 = generate_test_data(timeframe, 1, '2022-01-05 00:00:00+00:00')
|
||||
res = dp._add_external_df('ETH/USDT', df4, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is False
|
||||
# 36 hours - from 2022-01-03 12:00:00+00:00 to 2022-01-05 00:00:00+00:00
|
||||
assert res[1] == 36
|
||||
df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT)
|
||||
# New length = 61 + 1
|
||||
assert len(df) == 61
|
||||
|
||||
# Empty dataframe
|
||||
df4 = generate_test_data(timeframe, 0, '2022-01-05 00:00:00+00:00')
|
||||
res = dp._add_external_df('ETH/USDT', df4, last_analyzed, timeframe, CandleType.SPOT)
|
||||
assert res[0] is False
|
||||
# 36 hours - from 2022-01-03 12:00:00+00:00 to 2022-01-05 00:00:00+00:00
|
||||
assert res[1] == 0
|
||||
|
@@ -224,8 +224,13 @@ class TestCCXTExchange():
|
||||
for val in [1, 2, 5, 25, 100]:
|
||||
l2 = exchange.fetch_l2_order_book(pair, val)
|
||||
if not l2_limit_range or val in l2_limit_range:
|
||||
assert len(l2['asks']) == val
|
||||
assert len(l2['bids']) == val
|
||||
if val > 50:
|
||||
# Orderbooks are not always this deep.
|
||||
assert val - 5 < len(l2['asks']) <= val
|
||||
assert val - 5 < len(l2['bids']) <= val
|
||||
else:
|
||||
assert len(l2['asks']) == val
|
||||
assert len(l2['bids']) == val
|
||||
else:
|
||||
next_limit = exchange.get_next_limit_in_list(
|
||||
val, l2_limit_range, l2_limit_range_required)
|
||||
|
@@ -4014,9 +4014,6 @@ def test_validate_trading_mode_and_margin_mode(
|
||||
("binance", "spot", {}),
|
||||
("binance", "margin", {"options": {"defaultType": "margin"}}),
|
||||
("binance", "futures", {"options": {"defaultType": "future"}}),
|
||||
("bibox", "spot", {"has": {"fetchCurrencies": False}}),
|
||||
("bibox", "margin", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "margin"}}),
|
||||
("bibox", "futures", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "swap"}}),
|
||||
("bybit", "spot", {"options": {"defaultType": "spot"}}),
|
||||
("bybit", "futures", {"options": {"defaultType": "linear"}}),
|
||||
("gateio", "futures", {"options": {"defaultType": "swap"}}),
|
||||
|
@@ -242,7 +242,6 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat, caplog)
|
||||
df = freqai.cache_corr_pairlist_dfs(df, freqai.dk)
|
||||
for i in range(5):
|
||||
df[f'%-constant_{i}'] = i
|
||||
# df.loc[:, f'%-constant_{i}'] = i
|
||||
|
||||
metadata = {"pair": "LTC/BTC"}
|
||||
freqai.start_backtesting(df, metadata, freqai.dk)
|
||||
|
@@ -588,7 +588,7 @@ def test_api_show_config(botclient):
|
||||
assert 'unfilledtimeout' in response
|
||||
assert 'version' in response
|
||||
assert 'api_version' in response
|
||||
assert 2.1 <= response['api_version'] <= 2.2
|
||||
assert 2.1 <= response['api_version'] < 3.0
|
||||
|
||||
|
||||
def test_api_daily(botclient, mocker, ticker, fee, markets):
|
||||
|
@@ -83,6 +83,7 @@ def test_emc_init(patched_emc):
|
||||
def test_emc_handle_producer_message(patched_emc, caplog, ohlcv_history):
|
||||
test_producer = {"name": "test", "url": "ws://test", "ws_token": "test"}
|
||||
producer_name = test_producer['name']
|
||||
invalid_msg = r"Invalid message .+"
|
||||
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
@@ -94,7 +95,7 @@ def test_emc_handle_producer_message(patched_emc, caplog, ohlcv_history):
|
||||
assert log_has(
|
||||
f"Consumed message from `{producer_name}` of type `RPCMessageType.WHITELIST`", caplog)
|
||||
|
||||
# Test handle analyzed_df message
|
||||
# Test handle analyzed_df single candle message
|
||||
df_message = {
|
||||
"type": "analyzed_df",
|
||||
"data": {
|
||||
@@ -106,8 +107,7 @@ def test_emc_handle_producer_message(patched_emc, caplog, ohlcv_history):
|
||||
patched_emc.handle_producer_message(test_producer, df_message)
|
||||
|
||||
assert log_has(f"Received message of type `analyzed_df` from `{producer_name}`", caplog)
|
||||
assert log_has(
|
||||
f"Consumed message from `{producer_name}` of type `RPCMessageType.ANALYZED_DF`", caplog)
|
||||
assert log_has_re(r"Holes in data or no existing df,.+", caplog)
|
||||
|
||||
# Test unhandled message
|
||||
unhandled_message = {"type": "status", "data": "RUNNING"}
|
||||
@@ -120,7 +120,8 @@ def test_emc_handle_producer_message(patched_emc, caplog, ohlcv_history):
|
||||
malformed_message = {"type": "whitelist", "data": {"pair": "BTC/USDT"}}
|
||||
patched_emc.handle_producer_message(test_producer, malformed_message)
|
||||
|
||||
assert log_has_re(r"Invalid message .+", caplog)
|
||||
assert log_has_re(invalid_msg, caplog)
|
||||
caplog.clear()
|
||||
|
||||
malformed_message = {
|
||||
"type": "analyzed_df",
|
||||
@@ -133,13 +134,30 @@ def test_emc_handle_producer_message(patched_emc, caplog, ohlcv_history):
|
||||
patched_emc.handle_producer_message(test_producer, malformed_message)
|
||||
|
||||
assert log_has(f"Received message of type `analyzed_df` from `{producer_name}`", caplog)
|
||||
assert log_has_re(r"Invalid message .+", caplog)
|
||||
assert log_has_re(invalid_msg, caplog)
|
||||
caplog.clear()
|
||||
|
||||
# Empty dataframe
|
||||
malformed_message = {
|
||||
"type": "analyzed_df",
|
||||
"data": {
|
||||
"key": ("BTC/USDT", "5m", "spot"),
|
||||
"df": ohlcv_history.loc[ohlcv_history['open'] < 0],
|
||||
"la": datetime.now(timezone.utc)
|
||||
}
|
||||
}
|
||||
patched_emc.handle_producer_message(test_producer, malformed_message)
|
||||
|
||||
assert log_has(f"Received message of type `analyzed_df` from `{producer_name}`", caplog)
|
||||
assert not log_has_re(invalid_msg, caplog)
|
||||
assert log_has_re(r"Received Empty Dataframe for.+", caplog)
|
||||
|
||||
caplog.clear()
|
||||
malformed_message = {"some": "stuff"}
|
||||
patched_emc.handle_producer_message(test_producer, malformed_message)
|
||||
|
||||
assert log_has_re(r"Invalid message .+", caplog)
|
||||
assert log_has_re(invalid_msg, caplog)
|
||||
caplog.clear()
|
||||
|
||||
caplog.clear()
|
||||
malformed_message = {"type": "whitelist", "data": None}
|
||||
@@ -183,7 +201,7 @@ async def test_emc_create_connection_success(default_conf, caplog, mocker):
|
||||
async with websockets.serve(eat, _TEST_WS_HOST, _TEST_WS_PORT):
|
||||
await emc._create_connection(test_producer, lock)
|
||||
|
||||
assert log_has_re(r"Producer connection success.+", caplog)
|
||||
assert log_has_re(r"Connected to channel.+", caplog)
|
||||
finally:
|
||||
emc.shutdown()
|
||||
|
||||
@@ -212,7 +230,8 @@ async def test_emc_create_connection_invalid_url(default_conf, caplog, mocker, h
|
||||
|
||||
dp = DataProvider(default_conf, None, None, None)
|
||||
# Handle start explicitly to avoid messing with threading in tests
|
||||
mocker.patch("freqtrade.rpc.external_message_consumer.ExternalMessageConsumer.start",)
|
||||
mocker.patch("freqtrade.rpc.external_message_consumer.ExternalMessageConsumer.start")
|
||||
mocker.patch("freqtrade.rpc.api_server.ws.channel.create_channel")
|
||||
emc = ExternalMessageConsumer(default_conf, dp)
|
||||
|
||||
try:
|
||||
@@ -390,7 +409,9 @@ async def test_emc_receive_messages_timeout(default_conf, caplog, mocker):
|
||||
try:
|
||||
change_running(emc)
|
||||
loop.call_soon(functools.partial(change_running, emc=emc))
|
||||
await emc._receive_messages(TestChannel(), test_producer, lock)
|
||||
|
||||
with pytest.raises(asyncio.TimeoutError):
|
||||
await emc._receive_messages(TestChannel(), test_producer, lock)
|
||||
|
||||
assert log_has_re(r"Ping error.+", caplog)
|
||||
finally:
|
||||
|
@@ -12,6 +12,7 @@ from unittest.mock import ANY, MagicMock
|
||||
|
||||
import arrow
|
||||
import pytest
|
||||
import time_machine
|
||||
from pandas import DataFrame
|
||||
from telegram import Chat, Message, ReplyKeyboardMarkup, Update
|
||||
from telegram.error import BadRequest, NetworkError, TelegramError
|
||||
@@ -1906,119 +1907,120 @@ def test_send_msg_entry_fill_notification(default_conf, mocker, message_type, en
|
||||
|
||||
def test_send_msg_sell_notification(default_conf, mocker) -> None:
|
||||
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
with time_machine.travel("2022-09-01 05:00:00 +00:00", tick=False):
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
old_convamount = telegram._rpc._fiat_converter.convert_amount
|
||||
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'leverage': 1.0,
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(hours=-1),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1:00:00 (60.0 min)`'
|
||||
)
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'cumulative_profit': -0.15746268,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
'stake_amount': 0.01,
|
||||
'sub_trade': True,
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Sub Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
|
||||
'*Cumulative Profit:* (`-0.15746268 ETH / -24.812 USD`)\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Remaining:* `(0.01 ETH, -24.812 USD)`'
|
||||
old_convamount = telegram._rpc._fiat_converter.convert_amount
|
||||
telegram._rpc._fiat_converter.convert_amount = lambda a, b, c: -24.812
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'leverage': 1.0,
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(hours=-1),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1:00:00 (60.0 min)`'
|
||||
)
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH)`\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
|
||||
)
|
||||
# Reset singleton function to avoid random breaks
|
||||
telegram._rpc._fiat_converter.convert_amount = old_convamount
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'cumulative_profit': -0.15746268,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'fiat_currency': 'USD',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
'stake_amount': 0.01,
|
||||
'sub_trade': True,
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Sub Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
|
||||
'*Cumulative Profit:* (`-0.15746268 ETH / -24.812 USD`)\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Remaining:* `(0.01 ETH, -24.812 USD)`'
|
||||
)
|
||||
|
||||
msg_mock.reset_mock()
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'direction': 'Long',
|
||||
'gain': 'loss',
|
||||
'order_rate': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'current_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'enter_tag': 'buy_signal1',
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n'
|
||||
'*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH)`\n'
|
||||
'*Enter Tag:* `buy_signal1`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
'*Direction:* `Long`\n'
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Current Rate:* `0.00003201`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
|
||||
)
|
||||
# Reset singleton function to avoid random breaks
|
||||
telegram._rpc._fiat_converter.convert_amount = old_convamount
|
||||
|
||||
|
||||
def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None:
|
||||
@@ -2065,41 +2067,42 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction,
|
||||
default_conf['telegram']['notification_settings']['exit_fill'] = 'on'
|
||||
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT_FILL,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'leverage': leverage,
|
||||
'direction': direction,
|
||||
'gain': 'loss',
|
||||
'limit': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'close_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'enter_tag': enter_signal,
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
with time_machine.travel("2022-09-01 05:00:00 +00:00", tick=False):
|
||||
telegram.send_msg({
|
||||
'type': RPCMessageType.EXIT_FILL,
|
||||
'trade_id': 1,
|
||||
'exchange': 'Binance',
|
||||
'pair': 'KEY/ETH',
|
||||
'leverage': leverage,
|
||||
'direction': direction,
|
||||
'gain': 'loss',
|
||||
'limit': 3.201e-05,
|
||||
'amount': 1333.3333333333335,
|
||||
'order_type': 'market',
|
||||
'open_rate': 7.5e-05,
|
||||
'close_rate': 3.201e-05,
|
||||
'profit_amount': -0.05746268,
|
||||
'profit_ratio': -0.57405275,
|
||||
'stake_currency': 'ETH',
|
||||
'enter_tag': enter_signal,
|
||||
'exit_reason': ExitType.STOP_LOSS.value,
|
||||
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
|
||||
'close_date': arrow.utcnow(),
|
||||
})
|
||||
|
||||
leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else ''
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exited KEY/ETH (#1)\n'
|
||||
'*Profit:* `-57.41% (loss: -0.05746268 ETH)`\n'
|
||||
f'*Enter Tag:* `{enter_signal}`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
f"*Direction:* `{direction}`\n"
|
||||
f"{leverage_text}"
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
|
||||
)
|
||||
leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else ''
|
||||
assert msg_mock.call_args[0][0] == (
|
||||
'\N{WARNING SIGN} *Binance (dry):* Exited KEY/ETH (#1)\n'
|
||||
'*Profit:* `-57.41% (loss: -0.05746268 ETH)`\n'
|
||||
f'*Enter Tag:* `{enter_signal}`\n'
|
||||
'*Exit Reason:* `stop_loss`\n'
|
||||
f"*Direction:* `{direction}`\n"
|
||||
f"{leverage_text}"
|
||||
'*Amount:* `1333.33333333`\n'
|
||||
'*Open Rate:* `0.00007500`\n'
|
||||
'*Exit Rate:* `0.00003201`\n'
|
||||
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
|
||||
)
|
||||
|
||||
|
||||
def test_send_msg_status_notification(default_conf, mocker) -> None:
|
||||
|
@@ -1046,8 +1046,13 @@ def test__validate_freqai_include_timeframes(default_conf, caplog) -> None:
|
||||
# Validation pass
|
||||
conf.update({'timeframe': '1m'})
|
||||
validate_config_consistency(conf)
|
||||
conf.update({'analyze_per_epoch': True})
|
||||
|
||||
# Ensure base timeframe is in include_timeframes
|
||||
conf['freqai']['feature_parameters']['include_timeframes'] = ["5m", "15m"]
|
||||
validate_config_consistency(conf)
|
||||
assert conf['freqai']['feature_parameters']['include_timeframes'] == ["1m", "5m", "15m"]
|
||||
|
||||
conf.update({'analyze_per_epoch': True})
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Using analyze-per-epoch .* not supported with a FreqAI strategy."):
|
||||
validate_config_consistency(conf)
|
||||
|
@@ -88,6 +88,18 @@ def test_bot_cleanup(mocker, default_conf_usdt, caplog) -> None:
|
||||
assert coo_mock.call_count == 1
|
||||
|
||||
|
||||
def test_bot_cleanup_db_errors(mocker, default_conf_usdt, caplog) -> None:
|
||||
mocker.patch('freqtrade.freqtradebot.Trade.commit',
|
||||
side_effect=OperationalException())
|
||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.check_for_open_trades',
|
||||
side_effect=OperationalException())
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
freqtrade.emc = MagicMock()
|
||||
freqtrade.emc.shutdown = MagicMock()
|
||||
freqtrade.cleanup()
|
||||
assert freqtrade.emc.shutdown.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('runmode', [
|
||||
RunMode.DRY_RUN,
|
||||
RunMode.LIVE
|
||||
|
Reference in New Issue
Block a user