Merge pull request #576 from xmatthias/obj-ccxt-ticker
objectify ccxt fix backtesting and some tests
This commit is contained in:
commit
aba09b8107
@ -13,19 +13,19 @@
|
|||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"BTC_ETH",
|
"ETH/BTC",
|
||||||
"BTC_LTC",
|
"LTC/BTC",
|
||||||
"BTC_ETC",
|
"ETC/BTC",
|
||||||
"BTC_DASH",
|
"DASH/BTC",
|
||||||
"BTC_ZEC",
|
"ZEC/BTC",
|
||||||
"BTC_XLM",
|
"XLM/BTC",
|
||||||
"BTC_NXT",
|
"NXT/BTC",
|
||||||
"BTC_POWR",
|
"POWR/BTC",
|
||||||
"BTC_ADA",
|
"ADA/BTC",
|
||||||
"BTC_XMR"
|
"XMR/BTC"
|
||||||
],
|
],
|
||||||
"pair_blacklist": [
|
"pair_blacklist": [
|
||||||
"BTC_DOGE"
|
"DOGE/BTC"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"experimental": {
|
"experimental": {
|
||||||
|
@ -21,19 +21,19 @@
|
|||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"BTC_ETH",
|
"ETH/BTC",
|
||||||
"BTC_LTC",
|
"LTC/BTC",
|
||||||
"BTC_ETC",
|
"ETC/BTC",
|
||||||
"BTC_DASH",
|
"DASH/BTC",
|
||||||
"BTC_ZEC",
|
"ZEC/BTC",
|
||||||
"BTC_XLM",
|
"XLM/BTC",
|
||||||
"BTC_NXT",
|
"NXT/BTC",
|
||||||
"BTC_POWR",
|
"POWR/BTC",
|
||||||
"BTC_ADA",
|
"ADA/BTC",
|
||||||
"BTC_XMR"
|
"XMR/BTC"
|
||||||
],
|
],
|
||||||
"pair_blacklist": [
|
"pair_blacklist": [
|
||||||
"BTC_DOGE"
|
"DOGE/BTC"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"experimental": {
|
"experimental": {
|
||||||
|
@ -14,3 +14,11 @@ class OperationalException(BaseException):
|
|||||||
Requires manual intervention.
|
Requires manual intervention.
|
||||||
This happens when an exchange returns an unexpected error during runtime.
|
This happens when an exchange returns an unexpected error during runtime.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkException(BaseException):
|
||||||
|
"""
|
||||||
|
Network related error.
|
||||||
|
This could happen when an exchange is congested, unavailable, or the user
|
||||||
|
has networking problems. Usually resolves itself after a time.
|
||||||
|
"""
|
||||||
|
@ -51,6 +51,7 @@ class Analyze(object):
|
|||||||
unit='ms',
|
unit='ms',
|
||||||
utc=True,
|
utc=True,
|
||||||
infer_datetime_format=True)
|
infer_datetime_format=True)
|
||||||
|
|
||||||
frame.sort_values('date', inplace=True)
|
frame.sort_values('date', inplace=True)
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
|
@ -6,11 +6,12 @@ import ccxt
|
|||||||
from random import randint
|
from random import randint
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
from cachetools import cached, TTLCache
|
from cachetools import cached, TTLCache
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException, NetworkException
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -180,14 +181,25 @@ def get_ticker(pair: str, refresh: Optional[bool] = True) -> dict:
|
|||||||
|
|
||||||
# @cached(TTLCache(maxsize=100, ttl=30))
|
# @cached(TTLCache(maxsize=100, ttl=30))
|
||||||
@retrier
|
@retrier
|
||||||
def get_ticker_history(pair: str, tick_interval) -> List[Dict]:
|
def get_ticker_history(pair: str, tick_interval) -> List[List]:
|
||||||
# TODO: tickers need to be in format 1m,5m
|
# TODO: tickers need to be in format 1m,5m
|
||||||
# fetch_ohlcv returns an [[datetime,o,h,l,c,v]]
|
# fetch_ohlcv returns an [[datetime,o,h,l,c,v]]
|
||||||
if not _API.markets:
|
if 'fetchOHLCV' not in _API.has or not _API.has['fetchOHLCV']:
|
||||||
_API.load_markets()
|
logger.warning('Exhange %s does not support fetching historical candlestick data.',
|
||||||
ohlcv = _API.fetch_ohlcv(pair, str(tick_interval)+'m')
|
_API.name)
|
||||||
|
return []
|
||||||
|
|
||||||
|
try:
|
||||||
|
ohlcv = _API.fetch_ohlcv(pair, timeframe=str(tick_interval)+"m")
|
||||||
|
|
||||||
return ohlcv
|
return ohlcv
|
||||||
|
except IndexError as e:
|
||||||
|
logger.warning('Empty ticker history. Msg %s', str(e))
|
||||||
|
except ccxt.NetworkError as e:
|
||||||
|
logger.warning('Could not load ticker history due to networking error. Message: %s', str(e))
|
||||||
|
except ccxt.BaseError as e:
|
||||||
|
logger.warning('Could not fetch ticker data. Msg: %s', str(e))
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def cancel_order(order_id: str) -> None:
|
def cancel_order(order_id: str) -> None:
|
||||||
@ -235,7 +247,7 @@ def get_fee_taker() -> float:
|
|||||||
|
|
||||||
|
|
||||||
def get_fee() -> float:
|
def get_fee() -> float:
|
||||||
return _API.fees['trading']
|
return get_fee_taker()
|
||||||
|
|
||||||
|
|
||||||
def get_wallet_health() -> List[Dict]:
|
def get_wallet_health() -> List[Dict]:
|
||||||
|
@ -72,3 +72,11 @@ def file_dump_json(filename, data) -> None:
|
|||||||
"""
|
"""
|
||||||
with open(filename, 'w') as fp:
|
with open(filename, 'w') as fp:
|
||||||
json.dump(data, fp, default=str)
|
json.dump(data, fp, default=str)
|
||||||
|
|
||||||
|
|
||||||
|
def format_ms_time(date: str) -> str:
|
||||||
|
"""
|
||||||
|
convert MS date to readable format.
|
||||||
|
: epoch-string in ms
|
||||||
|
"""
|
||||||
|
return datetime.fromtimestamp(date/1000.0).strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
@ -35,7 +35,7 @@ def load_tickerdata_file(
|
|||||||
"""
|
"""
|
||||||
path = make_testdata_path(datadir)
|
path = make_testdata_path(datadir)
|
||||||
file = os.path.join(path, '{pair}-{ticker_interval}.json'.format(
|
file = os.path.join(path, '{pair}-{ticker_interval}.json'.format(
|
||||||
pair=pair,
|
pair=pair.replace('/', '_'),
|
||||||
ticker_interval=ticker_interval,
|
ticker_interval=ticker_interval,
|
||||||
))
|
))
|
||||||
gzipfile = file + '.gz'
|
gzipfile = file + '.gz'
|
||||||
@ -126,7 +126,7 @@ def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) ->
|
|||||||
interval
|
interval
|
||||||
)
|
)
|
||||||
|
|
||||||
filepair = pair.replace("-", "_")
|
filepair = pair.replace("/", "_")
|
||||||
filename = os.path.join(path, '{pair}-{interval}.json'.format(
|
filename = os.path.join(path, '{pair}-{interval}.json'.format(
|
||||||
pair=filepair,
|
pair=filepair,
|
||||||
interval=interval,
|
interval=interval,
|
||||||
@ -135,8 +135,8 @@ def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) ->
|
|||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
with open(filename, "rt") as file:
|
with open(filename, "rt") as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
logger.debug("Current Start: %s", data[1]['T'])
|
logger.debug("Current Start: %s", misc.format_ms_time(data[1][0]))
|
||||||
logger.debug("Current End: %s", data[-1:][0]['T'])
|
logger.debug("Current End: %s", misc.format_ms_time(data[-1:][0][0]))
|
||||||
else:
|
else:
|
||||||
data = []
|
data = []
|
||||||
logger.debug("Current Start: None")
|
logger.debug("Current Start: None")
|
||||||
@ -146,9 +146,9 @@ def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) ->
|
|||||||
for row in new_data:
|
for row in new_data:
|
||||||
if row not in data:
|
if row not in data:
|
||||||
data.append(row)
|
data.append(row)
|
||||||
logger.debug("New Start: %s", data[1]['T'])
|
logger.debug("New Start: %s", misc.format_ms_time(data[0][0]))
|
||||||
logger.debug("New End: %s", data[-1:][0]['T'])
|
logger.debug("New End: %s", misc.format_ms_time(data[-1:][0][0]))
|
||||||
data = sorted(data, key=lambda data: data['T'])
|
data = sorted(data, key=lambda data: data[0])
|
||||||
|
|
||||||
misc.file_dump_json(filename, data)
|
misc.file_dump_json(filename, data)
|
||||||
|
|
||||||
|
@ -53,7 +53,10 @@ class Backtesting(object):
|
|||||||
self.tickerdata_to_dataframe = self.analyze.tickerdata_to_dataframe
|
self.tickerdata_to_dataframe = self.analyze.tickerdata_to_dataframe
|
||||||
self.populate_buy_trend = self.analyze.populate_buy_trend
|
self.populate_buy_trend = self.analyze.populate_buy_trend
|
||||||
self.populate_sell_trend = self.analyze.populate_sell_trend
|
self.populate_sell_trend = self.analyze.populate_sell_trend
|
||||||
exchange.init({'key': '', 'secret': ''})
|
# Reest keys for backtesting
|
||||||
|
self.config['exchange']['key'] = ''
|
||||||
|
self.config['exchange']['secret'] = ''
|
||||||
|
exchange.init(self.config)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
||||||
|
@ -73,11 +73,11 @@ def default_conf():
|
|||||||
"key": "key",
|
"key": "key",
|
||||||
"secret": "secret",
|
"secret": "secret",
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"BTC_ETH",
|
"ETH/BTC",
|
||||||
"BTC_TKN",
|
"TKN/BTC",
|
||||||
"BTC_TRST",
|
"TRST/BTC",
|
||||||
"BTC_SWT",
|
"SWT/BTC",
|
||||||
"BTC_BCC"
|
"BCC/BTC"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"telegram": {
|
"telegram": {
|
||||||
@ -128,32 +128,31 @@ def ticker_sell_down():
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def health():
|
def health():
|
||||||
return MagicMock(return_value=[{
|
return MagicMock(return_value={
|
||||||
'Currency': 'BTC',
|
"ETH/BTC": {
|
||||||
'IsActive': True,
|
'base': 'ETH',
|
||||||
|
'active': True,
|
||||||
'LastChecked': '2017-11-13T20:15:00.00',
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
'Notice': None
|
'Notice': None
|
||||||
}, {
|
},
|
||||||
'Currency': 'ETH',
|
"TRST/BTC": {
|
||||||
'IsActive': True,
|
'base': 'TRST',
|
||||||
|
'active': True,
|
||||||
'LastChecked': '2017-11-13T20:15:00.00',
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
'Notice': None
|
'Notice': None
|
||||||
}, {
|
},
|
||||||
'Currency': 'TRST',
|
"SWT/BTC": {
|
||||||
'IsActive': True,
|
'base': 'SWT',
|
||||||
|
'active': True,
|
||||||
'LastChecked': '2017-11-13T20:15:00.00',
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
'Notice': None
|
'Notice': None
|
||||||
}, {
|
},
|
||||||
'Currency': 'SWT',
|
"BCC/BTC": {
|
||||||
'IsActive': True,
|
'base': 'BCC',
|
||||||
|
'active': False,
|
||||||
'LastChecked': '2017-11-13T20:15:00.00',
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
'Notice': None
|
'Notice': None
|
||||||
}, {
|
}})
|
||||||
'Currency': 'BCC',
|
|
||||||
'IsActive': False,
|
|
||||||
'LastChecked': '2017-11-13T20:15:00.00',
|
|
||||||
'Notice': None
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -175,7 +174,7 @@ def limit_buy_order_old():
|
|||||||
return {
|
return {
|
||||||
'id': 'mocked_limit_buy_old',
|
'id': 'mocked_limit_buy_old',
|
||||||
'type': 'LIMIT_BUY',
|
'type': 'LIMIT_BUY',
|
||||||
'pair': 'BTC_ETH',
|
'pair': 'ETH/BTC',
|
||||||
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
'rate': 0.00001099,
|
'rate': 0.00001099,
|
||||||
'amount': 90.99181073,
|
'amount': 90.99181073,
|
||||||
@ -188,7 +187,7 @@ def limit_sell_order_old():
|
|||||||
return {
|
return {
|
||||||
'id': 'mocked_limit_sell_old',
|
'id': 'mocked_limit_sell_old',
|
||||||
'type': 'LIMIT_SELL',
|
'type': 'LIMIT_SELL',
|
||||||
'pair': 'BTC_ETH',
|
'pair': 'ETH/BTC',
|
||||||
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
'rate': 0.00001099,
|
'rate': 0.00001099,
|
||||||
'amount': 90.99181073,
|
'amount': 90.99181073,
|
||||||
@ -201,7 +200,7 @@ def limit_buy_order_old_partial():
|
|||||||
return {
|
return {
|
||||||
'id': 'mocked_limit_buy_old_partial',
|
'id': 'mocked_limit_buy_old_partial',
|
||||||
'type': 'LIMIT_BUY',
|
'type': 'LIMIT_BUY',
|
||||||
'pair': 'BTC_ETH',
|
'pair': 'ETH/BTC',
|
||||||
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
'rate': 0.00001099,
|
'rate': 0.00001099,
|
||||||
'amount': 90.99181073,
|
'amount': 90.99181073,
|
||||||
@ -307,8 +306,10 @@ def get_market_summaries_data():
|
|||||||
8 entries. 4 BTC, 4 USTD
|
8 entries. 4 BTC, 4 USTD
|
||||||
:return: JSON market summaries
|
:return: JSON market summaries
|
||||||
"""
|
"""
|
||||||
return [
|
return {
|
||||||
{
|
'XWC/BTC': {
|
||||||
|
'symbol': 'XWC/BTC',
|
||||||
|
'info': {
|
||||||
'Ask': 1.316e-05,
|
'Ask': 1.316e-05,
|
||||||
'BaseVolume': 5.72599471,
|
'BaseVolume': 5.72599471,
|
||||||
'Bid': 1.3e-05,
|
'Bid': 1.3e-05,
|
||||||
@ -322,8 +323,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 1.376e-05,
|
'PrevDay': 1.376e-05,
|
||||||
'TimeStamp': '2018-02-05T01:32:40.493',
|
'TimeStamp': '2018-02-05T01:32:40.493',
|
||||||
'Volume': 424041.21418375
|
'Volume': 424041.21418375
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'XZC/BTC': {
|
||||||
|
'symbol': 'XZC/BTC',
|
||||||
|
'info': {
|
||||||
'Ask': 0.00627051,
|
'Ask': 0.00627051,
|
||||||
'BaseVolume': 93.23302388,
|
'BaseVolume': 93.23302388,
|
||||||
'Bid': 0.00618192,
|
'Bid': 0.00618192,
|
||||||
@ -337,8 +341,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 0.00668229,
|
'PrevDay': 0.00668229,
|
||||||
'TimeStamp': '2018-02-05T01:32:43.383',
|
'TimeStamp': '2018-02-05T01:32:43.383',
|
||||||
'Volume': 14863.60730702
|
'Volume': 14863.60730702
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'ZCL/BTC': {
|
||||||
|
'symbol': 'ZCL/BTC',
|
||||||
|
'info': {
|
||||||
'Ask': 0.01137247,
|
'Ask': 0.01137247,
|
||||||
'BaseVolume': 383.55922657,
|
'BaseVolume': 383.55922657,
|
||||||
'Bid': 0.01136006,
|
'Bid': 0.01136006,
|
||||||
@ -352,8 +359,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 0.01179603,
|
'PrevDay': 0.01179603,
|
||||||
'TimeStamp': '2018-02-05T01:32:42.773',
|
'TimeStamp': '2018-02-05T01:32:42.773',
|
||||||
'Volume': 33308.07358285
|
'Volume': 33308.07358285
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'ZEC/BTC': {
|
||||||
|
'symbol': 'ZEC/BTC',
|
||||||
|
'info': {
|
||||||
'Ask': 0.04155821,
|
'Ask': 0.04155821,
|
||||||
'BaseVolume': 274.75369074,
|
'BaseVolume': 274.75369074,
|
||||||
'Bid': 0.04130002,
|
'Bid': 0.04130002,
|
||||||
@ -367,8 +377,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 0.0429,
|
'PrevDay': 0.0429,
|
||||||
'TimeStamp': '2018-02-05T01:32:43.21',
|
'TimeStamp': '2018-02-05T01:32:43.21',
|
||||||
'Volume': 6479.84033259
|
'Volume': 6479.84033259
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'XMR/USDT': {
|
||||||
|
'symbol': 'XMR/USDT',
|
||||||
|
'info': {
|
||||||
'Ask': 210.99999999,
|
'Ask': 210.99999999,
|
||||||
'BaseVolume': 615132.70989532,
|
'BaseVolume': 615132.70989532,
|
||||||
'Bid': 210.05503736,
|
'Bid': 210.05503736,
|
||||||
@ -382,8 +395,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 247.93528899,
|
'PrevDay': 247.93528899,
|
||||||
'TimeStamp': '2018-02-05T01:32:43.117',
|
'TimeStamp': '2018-02-05T01:32:43.117',
|
||||||
'Volume': 2688.17410793
|
'Volume': 2688.17410793
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'XRP/USDT': {
|
||||||
|
'symbol': 'XRP/USDT',
|
||||||
|
'info': {
|
||||||
'Ask': 0.79589979,
|
'Ask': 0.79589979,
|
||||||
'BaseVolume': 9349557.01853031,
|
'BaseVolume': 9349557.01853031,
|
||||||
'Bid': 0.789226,
|
'Bid': 0.789226,
|
||||||
@ -397,8 +413,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 0.93300218,
|
'PrevDay': 0.93300218,
|
||||||
'TimeStamp': '2018-02-05T01:32:42.383',
|
'TimeStamp': '2018-02-05T01:32:42.383',
|
||||||
'Volume': 10801663.00788851
|
'Volume': 10801663.00788851
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'XVG/USDT': {
|
||||||
|
'symbol': 'XVG/USDT',
|
||||||
|
'info': {
|
||||||
'Ask': 0.05154982,
|
'Ask': 0.05154982,
|
||||||
'BaseVolume': 2311087.71232136,
|
'BaseVolume': 2311087.71232136,
|
||||||
'Bid': 0.05040107,
|
'Bid': 0.05040107,
|
||||||
@ -412,8 +431,11 @@ def get_market_summaries_data():
|
|||||||
'PrevDay': 0.0627,
|
'PrevDay': 0.0627,
|
||||||
'TimeStamp': '2018-02-05T01:32:41.507',
|
'TimeStamp': '2018-02-05T01:32:41.507',
|
||||||
'Volume': 40031424.2152716
|
'Volume': 40031424.2152716
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
'ZEC/USDT': {
|
||||||
|
'symbol': 'ZEC/USDT',
|
||||||
|
'info': {
|
||||||
'Ask': 332.65500022,
|
'Ask': 332.65500022,
|
||||||
'BaseVolume': 562911.87455665,
|
'BaseVolume': 562911.87455665,
|
||||||
'Bid': 330.00000001,
|
'Bid': 330.00000001,
|
||||||
@ -428,4 +450,5 @@ def get_market_summaries_data():
|
|||||||
'TimeStamp': '2018-02-05T01:32:42.947',
|
'TimeStamp': '2018-02-05T01:32:42.947',
|
||||||
'Volume': 1571.09647946
|
'Volume': 1571.09647946
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
|
@ -59,7 +59,7 @@ def test_rpc_trade_status(default_conf, ticker, mocker) -> None:
|
|||||||
result_message = [
|
result_message = [
|
||||||
'*Trade ID:* `1`\n'
|
'*Trade ID:* `1`\n'
|
||||||
'*Current Pair:* '
|
'*Current Pair:* '
|
||||||
'[BTC_ETH](https://www.bittrex.com/Market/Index?MarketName=BTC-ETH)\n'
|
'[ETH/BTC](https://bittrex.com/Market/Index?MarketName=BTC-ETH)\n'
|
||||||
'*Open Since:* `just now`\n'
|
'*Open Since:* `just now`\n'
|
||||||
'*Amount:* `90.99181074`\n'
|
'*Amount:* `90.99181074`\n'
|
||||||
'*Open Rate:* `0.00001099`\n'
|
'*Open Rate:* `0.00001099`\n'
|
||||||
@ -70,7 +70,7 @@ def test_rpc_trade_status(default_conf, ticker, mocker) -> None:
|
|||||||
'*Open Order:* `(LIMIT_BUY rem=0.00000000)`'
|
'*Open Order:* `(LIMIT_BUY rem=0.00000000)`'
|
||||||
]
|
]
|
||||||
assert result == result_message
|
assert result == result_message
|
||||||
assert trade.find('[BTC_ETH]') >= 0
|
assert trade.find('[ETH/BTC]') >= 0
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_status_table(default_conf, ticker, mocker) -> None:
|
def test_rpc_status_table(default_conf, ticker, mocker) -> None:
|
||||||
@ -102,7 +102,7 @@ def test_rpc_status_table(default_conf, ticker, mocker) -> None:
|
|||||||
freqtradebot.create_trade()
|
freqtradebot.create_trade()
|
||||||
(error, result) = rpc.rpc_status_table()
|
(error, result) = rpc.rpc_status_table()
|
||||||
assert 'just now' in result['Since'].all()
|
assert 'just now' in result['Since'].all()
|
||||||
assert 'BTC_ETH' in result['Pair'].all()
|
assert 'ETH/BTC' in result['Pair'].all()
|
||||||
assert '-0.59%' in result['Profit'].all()
|
assert '-0.59%' in result['Profit'].all()
|
||||||
|
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ def test_rpc_trade_statistics(
|
|||||||
assert stats['first_trade_date'] == 'just now'
|
assert stats['first_trade_date'] == 'just now'
|
||||||
assert stats['latest_trade_date'] == 'just now'
|
assert stats['latest_trade_date'] == 'just now'
|
||||||
assert stats['avg_duration'] == '0:00:00'
|
assert stats['avg_duration'] == '0:00:00'
|
||||||
assert stats['best_pair'] == 'BTC_ETH'
|
assert stats['best_pair'] == 'ETH/BTC'
|
||||||
assert prec_satoshi(stats['best_rate'], 6.2)
|
assert prec_satoshi(stats['best_rate'], 6.2)
|
||||||
|
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, ticker_sell_u
|
|||||||
assert stats['first_trade_date'] == 'just now'
|
assert stats['first_trade_date'] == 'just now'
|
||||||
assert stats['latest_trade_date'] == 'just now'
|
assert stats['latest_trade_date'] == 'just now'
|
||||||
assert stats['avg_duration'] == '0:00:00'
|
assert stats['avg_duration'] == '0:00:00'
|
||||||
assert stats['best_pair'] == 'BTC_ETH'
|
assert stats['best_pair'] == 'ETH/BTC'
|
||||||
assert prec_satoshi(stats['best_rate'], 6.2)
|
assert prec_satoshi(stats['best_rate'], 6.2)
|
||||||
|
|
||||||
|
|
||||||
@ -509,7 +509,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order,
|
|||||||
(error, res) = rpc.rpc_performance()
|
(error, res) = rpc.rpc_performance()
|
||||||
assert not error
|
assert not error
|
||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
assert res[0]['pair'] == 'BTC_ETH'
|
assert res[0]['pair'] == 'ETH/BTC'
|
||||||
assert res[0]['count'] == 1
|
assert res[0]['count'] == 1
|
||||||
assert prec_satoshi(res[0]['profit'], 6.2)
|
assert prec_satoshi(res[0]['profit'], 6.2)
|
||||||
|
|
||||||
|
@ -248,7 +248,8 @@ def test_status(default_conf, update, mocker, ticker) -> None:
|
|||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.freqtradebot.exchange',
|
'freqtrade.freqtradebot.exchange',
|
||||||
validate_pairs=MagicMock(),
|
validate_pairs=MagicMock(),
|
||||||
get_ticker=ticker
|
get_ticker=ticker,
|
||||||
|
get_pair_detail_url=MagicMock()
|
||||||
)
|
)
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
status_table = MagicMock()
|
status_table = MagicMock()
|
||||||
@ -319,7 +320,7 @@ def test_status_handle(default_conf, update, ticker, mocker) -> None:
|
|||||||
telegram._status(bot=MagicMock(), update=update)
|
telegram._status(bot=MagicMock(), update=update)
|
||||||
|
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
assert '[BTC_ETH]' in msg_mock.call_args_list[0][0][0]
|
assert '[ETH/BTC]' in msg_mock.call_args_list[0][0][0]
|
||||||
|
|
||||||
|
|
||||||
def test_status_table_handle(default_conf, update, ticker, mocker) -> None:
|
def test_status_table_handle(default_conf, update, ticker, mocker) -> None:
|
||||||
@ -369,7 +370,7 @@ def test_status_table_handle(default_conf, update, ticker, mocker) -> None:
|
|||||||
fields = re.sub('[ ]+', ' ', line[2].strip()).split(' ')
|
fields = re.sub('[ ]+', ' ', line[2].strip()).split(' ')
|
||||||
|
|
||||||
assert int(fields[0]) == 1
|
assert int(fields[0]) == 1
|
||||||
assert fields[1] == 'BTC_ETH'
|
assert fields[1] == 'ETH/BTC'
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@ -387,7 +388,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order,
|
|||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.freqtradebot.exchange',
|
'freqtrade.freqtradebot.exchange',
|
||||||
validate_pairs=MagicMock(),
|
validate_pairs=MagicMock(),
|
||||||
get_ticker=ticker
|
get_ticker=ticker,
|
||||||
|
get_pair_detail_url=MagicMock()
|
||||||
)
|
)
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -541,7 +543,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up,
|
|||||||
assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
|
assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
|
||||||
assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
|
assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0]
|
||||||
|
|
||||||
assert '*Best Performing:* `BTC_ETH: 6.20%`' in msg_mock.call_args_list[-1][0][0]
|
assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0]
|
||||||
|
|
||||||
|
|
||||||
def test_telegram_balance_handle(default_conf, update, mocker) -> None:
|
def test_telegram_balance_handle(default_conf, update, mocker) -> None:
|
||||||
@ -779,7 +781,7 @@ def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker)
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0]
|
assert 'profit: 6.11%, 0.00006126' in rpc_mock.call_args_list[-1][0][0]
|
||||||
@ -822,7 +824,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, m
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
||||||
@ -838,6 +840,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, mocker) -> None:
|
|||||||
mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0)
|
mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||||
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
|
mocker.patch('freqtrade.exchange.get_pair_detail_url', MagicMock())
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.freqtradebot.exchange',
|
'freqtrade.freqtradebot.exchange',
|
||||||
validate_pairs=MagicMock(),
|
validate_pairs=MagicMock(),
|
||||||
@ -942,7 +945,7 @@ def test_performance_handle(default_conf, update, ticker, limit_buy_order,
|
|||||||
telegram._performance(bot=MagicMock(), update=update)
|
telegram._performance(bot=MagicMock(), update=update)
|
||||||
assert msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
assert 'Performance' in msg_mock.call_args_list[0][0][0]
|
assert 'Performance' in msg_mock.call_args_list[0][0][0]
|
||||||
assert '<code>BTC_ETH\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0]
|
assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0]
|
||||||
|
|
||||||
|
|
||||||
def test_performance_handle_invalid(default_conf, update, mocker) -> None:
|
def test_performance_handle_invalid(default_conf, update, mocker) -> None:
|
||||||
|
@ -12,23 +12,25 @@ def whitelist_conf():
|
|||||||
|
|
||||||
config['stake_currency'] = 'BTC'
|
config['stake_currency'] = 'BTC'
|
||||||
config['exchange']['pair_whitelist'] = [
|
config['exchange']['pair_whitelist'] = [
|
||||||
'BTC_ETH',
|
'ETH/BTC',
|
||||||
'BTC_TKN',
|
'TKN/BTC',
|
||||||
'BTC_TRST',
|
'TRST/BTC',
|
||||||
'BTC_SWT',
|
'SWT/BTC',
|
||||||
'BTC_BCC'
|
'BCC/BTC'
|
||||||
]
|
]
|
||||||
|
|
||||||
config['exchange']['pair_blacklist'] = [
|
config['exchange']['pair_blacklist'] = [
|
||||||
'BTC_BLK'
|
'BLK/BTC'
|
||||||
]
|
]
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def get_market_summaries():
|
def get_market_summaries():
|
||||||
return [{
|
return {
|
||||||
'MarketName': 'BTC-TKN',
|
'TKN/BTC': {
|
||||||
|
'symbol': 'TKN/BTC',
|
||||||
|
'info': {
|
||||||
'High': 0.00000919,
|
'High': 0.00000919,
|
||||||
'Low': 0.00000820,
|
'Low': 0.00000820,
|
||||||
'Volume': 74339.61396015,
|
'Volume': 74339.61396015,
|
||||||
@ -42,8 +44,11 @@ def get_market_summaries():
|
|||||||
'PrevDay': 0.00000821,
|
'PrevDay': 0.00000821,
|
||||||
'Created': '2014-03-20T06:00:00',
|
'Created': '2014-03-20T06:00:00',
|
||||||
'DisplayMarketName': ''
|
'DisplayMarketName': ''
|
||||||
}, {
|
}
|
||||||
'MarketName': 'BTC-ETH',
|
},
|
||||||
|
'ETH/BTC': {
|
||||||
|
'symbol': 'ETH/BTC',
|
||||||
|
'info': {
|
||||||
'High': 0.00000072,
|
'High': 0.00000072,
|
||||||
'Low': 0.00000001,
|
'Low': 0.00000001,
|
||||||
'Volume': 166340678.42280999,
|
'Volume': 166340678.42280999,
|
||||||
@ -57,8 +62,11 @@ def get_market_summaries():
|
|||||||
'PrevDay': 0.00000002,
|
'PrevDay': 0.00000002,
|
||||||
'Created': '2014-05-30T07:57:49.637',
|
'Created': '2014-05-30T07:57:49.637',
|
||||||
'DisplayMarketName': ''
|
'DisplayMarketName': ''
|
||||||
}, {
|
}
|
||||||
'MarketName': 'BTC-BLK',
|
},
|
||||||
|
'BLK/BTC': {
|
||||||
|
'symbol': 'BLK/BTC',
|
||||||
|
'info': {
|
||||||
'High': 0.00000072,
|
'High': 0.00000072,
|
||||||
'Low': 0.00000001,
|
'Low': 0.00000001,
|
||||||
'Volume': 166340678.42280999,
|
'Volume': 166340678.42280999,
|
||||||
@ -72,17 +80,19 @@ def get_market_summaries():
|
|||||||
'PrevDay': 0.00000002,
|
'PrevDay': 0.00000002,
|
||||||
'Created': '2014-05-30T07:57:49.637',
|
'Created': '2014-05-30T07:57:49.637',
|
||||||
'DisplayMarketName': ''
|
'DisplayMarketName': ''
|
||||||
}]
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_health():
|
def get_health():
|
||||||
return [{'Currency': 'ETH', 'IsActive': True},
|
return {
|
||||||
{'Currency': 'TKN', 'IsActive': True},
|
'ETH/BTC': {'base': 'ETH', 'active': True},
|
||||||
{'Currency': 'BLK', 'IsActive': True}]
|
'TKN/BTC': {'base': 'TKN', 'active': True},
|
||||||
|
'BLK/BTC': {'base': 'BLK', 'active': True}}
|
||||||
|
|
||||||
|
|
||||||
def get_health_empty():
|
def get_health_empty():
|
||||||
return []
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def test_refresh_market_pair_not_in_whitelist(mocker):
|
def test_refresh_market_pair_not_in_whitelist(mocker):
|
||||||
@ -92,10 +102,10 @@ def test_refresh_market_pair_not_in_whitelist(mocker):
|
|||||||
|
|
||||||
mocker.patch('freqtrade.freqtradebot.exchange.get_wallet_health', get_health)
|
mocker.patch('freqtrade.freqtradebot.exchange.get_wallet_health', get_health)
|
||||||
refreshedwhitelist = freqtradebot._refresh_whitelist(
|
refreshedwhitelist = freqtradebot._refresh_whitelist(
|
||||||
conf['exchange']['pair_whitelist'] + ['BTC_XXX']
|
conf['exchange']['pair_whitelist'] + ['XXX/BTC']
|
||||||
)
|
)
|
||||||
# List ordered by BaseVolume
|
# List ordered by BaseVolume
|
||||||
whitelist = ['BTC_ETH', 'BTC_TKN']
|
whitelist = ['ETH/BTC', 'TKN/BTC']
|
||||||
# Ensure all except those in whitelist are removed
|
# Ensure all except those in whitelist are removed
|
||||||
assert whitelist == refreshedwhitelist
|
assert whitelist == refreshedwhitelist
|
||||||
|
|
||||||
@ -108,7 +118,7 @@ def test_refresh_whitelist(mocker):
|
|||||||
refreshedwhitelist = freqtradebot._refresh_whitelist(conf['exchange']['pair_whitelist'])
|
refreshedwhitelist = freqtradebot._refresh_whitelist(conf['exchange']['pair_whitelist'])
|
||||||
|
|
||||||
# List ordered by BaseVolume
|
# List ordered by BaseVolume
|
||||||
whitelist = ['BTC_ETH', 'BTC_TKN']
|
whitelist = ['ETH/BTC', 'TKN/BTC']
|
||||||
# Ensure all except those in whitelist are removed
|
# Ensure all except those in whitelist are removed
|
||||||
assert whitelist == refreshedwhitelist
|
assert whitelist == refreshedwhitelist
|
||||||
|
|
||||||
@ -123,7 +133,7 @@ def test_refresh_whitelist_dynamic(mocker):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# argument: use the whitelist dynamically by exchange-volume
|
# argument: use the whitelist dynamically by exchange-volume
|
||||||
whitelist = ['BTC_TKN', 'BTC_ETH']
|
whitelist = ['TKN/BTC', 'ETH/BTC']
|
||||||
|
|
||||||
refreshedwhitelist = freqtradebot._refresh_whitelist(
|
refreshedwhitelist = freqtradebot._refresh_whitelist(
|
||||||
freqtradebot._gen_pair_whitelist(conf['stake_currency'])
|
freqtradebot._gen_pair_whitelist(conf['stake_currency'])
|
||||||
|
@ -17,7 +17,6 @@ import requests
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
from freqtrade import DependencyException, OperationalException
|
from freqtrade import DependencyException, OperationalException
|
||||||
from freqtrade.exchange import Exchanges
|
|
||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
@ -216,15 +215,15 @@ def test_gen_pair_whitelist(mocker, default_conf, get_market_summaries_data) ->
|
|||||||
|
|
||||||
# Test to retrieved BTC sorted on BaseVolume
|
# Test to retrieved BTC sorted on BaseVolume
|
||||||
whitelist = freqtrade._gen_pair_whitelist(base_currency='BTC')
|
whitelist = freqtrade._gen_pair_whitelist(base_currency='BTC')
|
||||||
assert whitelist == ['BTC_ZCL', 'BTC_ZEC', 'BTC_XZC', 'BTC_XWC']
|
assert whitelist == ['ZCL/BTC', 'ZEC/BTC', 'XZC/BTC', 'XWC/BTC']
|
||||||
|
|
||||||
# Test to retrieved BTC sorted on OpenBuyOrders
|
# Test to retrieved BTC sorted on OpenBuyOrders
|
||||||
whitelist = freqtrade._gen_pair_whitelist(base_currency='BTC', key='OpenBuyOrders')
|
whitelist = freqtrade._gen_pair_whitelist(base_currency='BTC', key='OpenBuyOrders')
|
||||||
assert whitelist == ['BTC_XWC', 'BTC_ZCL', 'BTC_ZEC', 'BTC_XZC']
|
assert whitelist == ['XWC/BTC', 'ZCL/BTC', 'ZEC/BTC', 'XZC/BTC']
|
||||||
|
|
||||||
# Test with USDT sorted on BaseVolume
|
# Test with USDT sorted on BaseVolume
|
||||||
whitelist = freqtrade._gen_pair_whitelist(base_currency='USDT')
|
whitelist = freqtrade._gen_pair_whitelist(base_currency='USDT')
|
||||||
assert whitelist == ['USDT_XRP', 'USDT_XVG', 'USDT_XMR', 'USDT_ZEC']
|
assert whitelist == ['XRP/USDT', 'XVG/USDT', 'XMR/USDT', 'ZEC/USDT']
|
||||||
|
|
||||||
# Test with ETH (our fixture does not have ETH, but Bittrex returns them)
|
# Test with ETH (our fixture does not have ETH, but Bittrex returns them)
|
||||||
whitelist = freqtrade._gen_pair_whitelist(base_currency='ETH')
|
whitelist = freqtrade._gen_pair_whitelist(base_currency='ETH')
|
||||||
@ -263,7 +262,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, mocker) -> None:
|
|||||||
assert trade.stake_amount == 0.001
|
assert trade.stake_amount == 0.001
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
assert trade.open_date is not None
|
assert trade.open_date is not None
|
||||||
assert trade.exchange == Exchanges.BITTREX.name
|
assert trade.exchange == 'BITTREX'
|
||||||
|
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
trade.update(limit_buy_order)
|
trade.update(limit_buy_order)
|
||||||
@ -333,8 +332,8 @@ def test_create_trade_no_pairs(default_conf, ticker, mocker) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['exchange']['pair_whitelist'] = ["BTC_ETH"]
|
conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
|
||||||
conf['exchange']['pair_blacklist'] = ["BTC_ETH"]
|
conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
|
||||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
freqtrade.create_trade()
|
freqtrade.create_trade()
|
||||||
@ -358,8 +357,8 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker, mocker) ->
|
|||||||
)
|
)
|
||||||
|
|
||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['exchange']['pair_whitelist'] = ["BTC_ETH"]
|
conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
|
||||||
conf['exchange']['pair_blacklist'] = ["BTC_ETH"]
|
conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
|
||||||
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
freqtrade.create_trade()
|
freqtrade.create_trade()
|
||||||
@ -425,7 +424,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order,
|
|||||||
assert trade.stake_amount == default_conf['stake_amount']
|
assert trade.stake_amount == default_conf['stake_amount']
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
assert trade.open_date is not None
|
assert trade.open_date is not None
|
||||||
assert trade.exchange == Exchanges.BITTREX.name
|
assert trade.exchange == "BITTREX"
|
||||||
assert trade.open_rate == 0.00001099
|
assert trade.open_rate == 0.00001099
|
||||||
assert trade.amount == 90.99181073703367
|
assert trade.amount == 90.99181073703367
|
||||||
|
|
||||||
@ -793,7 +792,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
|
|||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trade_buy = Trade(
|
trade_buy = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
open_rate=0.00001099,
|
open_rate=0.00001099,
|
||||||
exchange='BITTREX',
|
exchange='BITTREX',
|
||||||
open_order_id='123456789',
|
open_order_id='123456789',
|
||||||
@ -832,7 +831,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
|
|||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trade_sell = Trade(
|
trade_sell = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
open_rate=0.00001099,
|
open_rate=0.00001099,
|
||||||
exchange='BITTREX',
|
exchange='BITTREX',
|
||||||
open_order_id='123456789',
|
open_order_id='123456789',
|
||||||
@ -871,7 +870,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
|
|||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trade_buy = Trade(
|
trade_buy = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
open_rate=0.00001099,
|
open_rate=0.00001099,
|
||||||
exchange='BITTREX',
|
exchange='BITTREX',
|
||||||
open_order_id='123456789',
|
open_order_id='123456789',
|
||||||
@ -918,7 +917,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) -
|
|||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trade_buy = Trade(
|
trade_buy = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
open_rate=0.00001099,
|
open_rate=0.00001099,
|
||||||
exchange='BITTREX',
|
exchange='BITTREX',
|
||||||
open_order_id='123456789',
|
open_order_id='123456789',
|
||||||
@ -931,7 +930,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) -
|
|||||||
|
|
||||||
Trade.session.add(trade_buy)
|
Trade.session.add(trade_buy)
|
||||||
regexp = re.compile(
|
regexp = re.compile(
|
||||||
'Cannot query order for Trade(id=1, pair=BTC_ETH, amount=90.99181073, '
|
'Cannot query order for Trade(id=1, pair=ETH/BTC, amount=90.99181073, '
|
||||||
'open_rate=0.00001099, open_since=10 hours ago) due to Traceback (most '
|
'open_rate=0.00001099, open_since=10 hours ago) due to Traceback (most '
|
||||||
'recent call last):\n.*'
|
'recent call last):\n.*'
|
||||||
)
|
)
|
||||||
@ -1024,7 +1023,7 @@ def test_execute_sell_up(default_conf, ticker, ticker_sell_up, mocker) -> None:
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Profit' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Profit' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
||||||
@ -1064,7 +1063,7 @@ def test_execute_sell_down(default_conf, ticker, ticker_sell_down, mocker) -> No
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
||||||
@ -1103,7 +1102,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, ticker_sell_up,
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Amount' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '(profit: 6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0]
|
assert '(profit: 6.11%, 0.00006126)' in rpc_mock.call_args_list[-1][0][0]
|
||||||
@ -1143,7 +1142,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker,
|
|||||||
|
|
||||||
assert rpc_mock.call_count == 2
|
assert rpc_mock.call_count == 2
|
||||||
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
assert 'Selling' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '[BTC_ETH]' in rpc_mock.call_args_list[-1][0][0]
|
assert '[ETH/BTC]' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
assert '0.00001044' in rpc_mock.call_args_list[-1][0][0]
|
||||||
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
from freqtrade.exchange import Exchanges
|
from freqtrade import exchange
|
||||||
from freqtrade.persistence import Trade, init, clean_dry_run_db
|
from freqtrade.persistence import Trade, init, clean_dry_run_db
|
||||||
|
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order):
|
|||||||
pair='BTC_ETH',
|
pair='BTC_ETH',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate is None
|
assert trade.open_rate is None
|
||||||
@ -146,10 +146,10 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order):
|
|||||||
|
|
||||||
def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order):
|
def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
|
|
||||||
trade.open_order_id = 'something'
|
trade.open_order_id = 'something'
|
||||||
@ -168,10 +168,10 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order):
|
|||||||
|
|
||||||
def test_calc_close_trade_price_exception(limit_buy_order):
|
def test_calc_close_trade_price_exception(limit_buy_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
|
|
||||||
trade.open_order_id = 'something'
|
trade.open_order_id = 'something'
|
||||||
@ -181,10 +181,10 @@ def test_calc_close_trade_price_exception(limit_buy_order):
|
|||||||
|
|
||||||
def test_update_open_order(limit_buy_order):
|
def test_update_open_order(limit_buy_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=1.00,
|
stake_amount=1.00,
|
||||||
fee=0.1,
|
fee=0.1,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
|
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
@ -203,10 +203,10 @@ def test_update_open_order(limit_buy_order):
|
|||||||
|
|
||||||
def test_update_invalid_order(limit_buy_order):
|
def test_update_invalid_order(limit_buy_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=1.00,
|
stake_amount=1.00,
|
||||||
fee=0.1,
|
fee=0.1,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
limit_buy_order['type'] = 'invalid'
|
limit_buy_order['type'] = 'invalid'
|
||||||
with pytest.raises(ValueError, match=r'Unknown order type'):
|
with pytest.raises(ValueError, match=r'Unknown order type'):
|
||||||
@ -215,10 +215,10 @@ def test_update_invalid_order(limit_buy_order):
|
|||||||
|
|
||||||
def test_calc_open_trade_price(limit_buy_order):
|
def test_calc_open_trade_price(limit_buy_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
trade.open_order_id = 'open_trade'
|
trade.open_order_id = 'open_trade'
|
||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
@ -232,10 +232,10 @@ def test_calc_open_trade_price(limit_buy_order):
|
|||||||
|
|
||||||
def test_calc_close_trade_price(limit_buy_order, limit_sell_order):
|
def test_calc_close_trade_price(limit_buy_order, limit_sell_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
trade.open_order_id = 'close_trade'
|
trade.open_order_id = 'close_trade'
|
||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
@ -253,10 +253,10 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order):
|
|||||||
|
|
||||||
def test_calc_profit(limit_buy_order, limit_sell_order):
|
def test_calc_profit(limit_buy_order, limit_sell_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
trade.open_order_id = 'profit_percent'
|
trade.open_order_id = 'profit_percent'
|
||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
@ -283,10 +283,10 @@ def test_calc_profit(limit_buy_order, limit_sell_order):
|
|||||||
|
|
||||||
def test_calc_profit_percent(limit_buy_order, limit_sell_order):
|
def test_calc_profit_percent(limit_buy_order, limit_sell_order):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
exchange=Exchanges.BITTREX,
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
trade.open_order_id = 'profit_percent'
|
trade.open_order_id = 'profit_percent'
|
||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
@ -310,35 +310,35 @@ def test_clean_dry_run_db(default_conf):
|
|||||||
|
|
||||||
# Simulate dry_run entries
|
# Simulate dry_run entries
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETH',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
amount=123.0,
|
amount=123.0,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
open_rate=0.123,
|
open_rate=0.123,
|
||||||
exchange='BITTREX',
|
exchange='bittrex',
|
||||||
open_order_id='dry_run_buy_12345'
|
open_order_id='dry_run_buy_12345'
|
||||||
)
|
)
|
||||||
Trade.session.add(trade)
|
Trade.session.add(trade)
|
||||||
|
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETC',
|
pair='ETC/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
amount=123.0,
|
amount=123.0,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
open_rate=0.123,
|
open_rate=0.123,
|
||||||
exchange='BITTREX',
|
exchange='bittrex',
|
||||||
open_order_id='dry_run_sell_12345'
|
open_order_id='dry_run_sell_12345'
|
||||||
)
|
)
|
||||||
Trade.session.add(trade)
|
Trade.session.add(trade)
|
||||||
|
|
||||||
# Simulate prod entry
|
# Simulate prod entry
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='BTC_ETC',
|
pair='ETC/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
amount=123.0,
|
amount=123.0,
|
||||||
fee=0.0025,
|
fee=0.0025,
|
||||||
open_rate=0.123,
|
open_rate=0.123,
|
||||||
exchange='BITTREX',
|
exchange='bittrex',
|
||||||
open_order_id='prod_buy_12345'
|
open_order_id='prod_buy_12345'
|
||||||
)
|
)
|
||||||
Trade.session.add(trade)
|
Trade.session.add(trade)
|
||||||
|
Loading…
Reference in New Issue
Block a user