Merge pull request #576 from xmatthias/obj-ccxt-ticker

objectify ccxt fix backtesting and some tests
This commit is contained in:
Samuel Husso 2018-03-26 08:28:40 +03:00 committed by GitHub
commit aba09b8107
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 369 additions and 302 deletions

View File

@ -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": {

View File

@ -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": {

View File

@ -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.
"""

View File

@ -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

View File

@ -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 []
return ohlcv try:
ohlcv = _API.fetch_ohlcv(pair, timeframe=str(tick_interval)+"m")
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]:

View File

@ -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')

View File

@ -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)

View File

@ -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]:

View File

@ -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',
'LastChecked': '2017-11-13T20:15:00.00', 'active': True,
'Notice': None 'LastChecked': '2017-11-13T20:15:00.00',
}, { 'Notice': None
'Currency': 'ETH', },
'IsActive': True, "TRST/BTC": {
'LastChecked': '2017-11-13T20:15:00.00', 'base': 'TRST',
'Notice': None 'active': True,
}, { 'LastChecked': '2017-11-13T20:15:00.00',
'Currency': 'TRST', 'Notice': None
'IsActive': True, },
'LastChecked': '2017-11-13T20:15:00.00', "SWT/BTC": {
'Notice': None 'base': 'SWT',
}, { 'active': True,
'Currency': 'SWT', 'LastChecked': '2017-11-13T20:15:00.00',
'IsActive': True, 'Notice': None
'LastChecked': '2017-11-13T20:15:00.00', },
'Notice': None "BCC/BTC": {
}, { 'base': 'BCC',
'Currency': 'BCC', 'active': False,
'IsActive': False, 'LastChecked': '2017-11-13T20:15:00.00',
'LastChecked': '2017-11-13T20:15:00.00', 'Notice': None
'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,125 +306,149 @@ 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': {
'Ask': 1.316e-05, 'symbol': 'XWC/BTC',
'BaseVolume': 5.72599471, 'info': {
'Bid': 1.3e-05, 'Ask': 1.316e-05,
'Created': '2014-04-14T00:00:00', 'BaseVolume': 5.72599471,
'High': 1.414e-05, 'Bid': 1.3e-05,
'Last': 1.298e-05, 'Created': '2014-04-14T00:00:00',
'Low': 1.282e-05, 'High': 1.414e-05,
'MarketName': 'BTC-XWC', 'Last': 1.298e-05,
'OpenBuyOrders': 2000, 'Low': 1.282e-05,
'OpenSellOrders': 1484, 'MarketName': 'BTC-XWC',
'PrevDay': 1.376e-05, 'OpenBuyOrders': 2000,
'TimeStamp': '2018-02-05T01:32:40.493', 'OpenSellOrders': 1484,
'Volume': 424041.21418375 'PrevDay': 1.376e-05,
'TimeStamp': '2018-02-05T01:32:40.493',
'Volume': 424041.21418375
}
}, },
{ 'XZC/BTC': {
'Ask': 0.00627051, 'symbol': 'XZC/BTC',
'BaseVolume': 93.23302388, 'info': {
'Bid': 0.00618192, 'Ask': 0.00627051,
'Created': '2016-10-20T04:48:30.387', 'BaseVolume': 93.23302388,
'High': 0.00669897, 'Bid': 0.00618192,
'Last': 0.00618192, 'Created': '2016-10-20T04:48:30.387',
'Low': 0.006, 'High': 0.00669897,
'MarketName': 'BTC-XZC', 'Last': 0.00618192,
'OpenBuyOrders': 343, 'Low': 0.006,
'OpenSellOrders': 2037, 'MarketName': 'BTC-XZC',
'PrevDay': 0.00668229, 'OpenBuyOrders': 343,
'TimeStamp': '2018-02-05T01:32:43.383', 'OpenSellOrders': 2037,
'Volume': 14863.60730702 'PrevDay': 0.00668229,
'TimeStamp': '2018-02-05T01:32:43.383',
'Volume': 14863.60730702
}
}, },
{ 'ZCL/BTC': {
'Ask': 0.01137247, 'symbol': 'ZCL/BTC',
'BaseVolume': 383.55922657, 'info': {
'Bid': 0.01136006, 'Ask': 0.01137247,
'Created': '2016-11-15T20:29:59.73', 'BaseVolume': 383.55922657,
'High': 0.012, 'Bid': 0.01136006,
'Last': 0.01137247, 'Created': '2016-11-15T20:29:59.73',
'Low': 0.01119883, 'High': 0.012,
'MarketName': 'BTC-ZCL', 'Last': 0.01137247,
'OpenBuyOrders': 1332, 'Low': 0.01119883,
'OpenSellOrders': 5317, 'MarketName': 'BTC-ZCL',
'PrevDay': 0.01179603, 'OpenBuyOrders': 1332,
'TimeStamp': '2018-02-05T01:32:42.773', 'OpenSellOrders': 5317,
'Volume': 33308.07358285 'PrevDay': 0.01179603,
'TimeStamp': '2018-02-05T01:32:42.773',
'Volume': 33308.07358285
}
}, },
{ 'ZEC/BTC': {
'Ask': 0.04155821, 'symbol': 'ZEC/BTC',
'BaseVolume': 274.75369074, 'info': {
'Bid': 0.04130002, 'Ask': 0.04155821,
'Created': '2016-10-28T17:13:10.833', 'BaseVolume': 274.75369074,
'High': 0.04354429, 'Bid': 0.04130002,
'Last': 0.041585, 'Created': '2016-10-28T17:13:10.833',
'Low': 0.0413, 'High': 0.04354429,
'MarketName': 'BTC-ZEC', 'Last': 0.041585,
'OpenBuyOrders': 863, 'Low': 0.0413,
'OpenSellOrders': 5579, 'MarketName': 'BTC-ZEC',
'PrevDay': 0.0429, 'OpenBuyOrders': 863,
'TimeStamp': '2018-02-05T01:32:43.21', 'OpenSellOrders': 5579,
'Volume': 6479.84033259 'PrevDay': 0.0429,
'TimeStamp': '2018-02-05T01:32:43.21',
'Volume': 6479.84033259
}
}, },
{ 'XMR/USDT': {
'Ask': 210.99999999, 'symbol': 'XMR/USDT',
'BaseVolume': 615132.70989532, 'info': {
'Bid': 210.05503736, 'Ask': 210.99999999,
'Created': '2017-07-21T01:08:49.397', 'BaseVolume': 615132.70989532,
'High': 257.396, 'Bid': 210.05503736,
'Last': 211.0, 'Created': '2017-07-21T01:08:49.397',
'Low': 209.05333589, 'High': 257.396,
'MarketName': 'USDT-XMR', 'Last': 211.0,
'OpenBuyOrders': 180, 'Low': 209.05333589,
'OpenSellOrders': 1203, 'MarketName': 'USDT-XMR',
'PrevDay': 247.93528899, 'OpenBuyOrders': 180,
'TimeStamp': '2018-02-05T01:32:43.117', 'OpenSellOrders': 1203,
'Volume': 2688.17410793 'PrevDay': 247.93528899,
'TimeStamp': '2018-02-05T01:32:43.117',
'Volume': 2688.17410793
}
}, },
{ 'XRP/USDT': {
'Ask': 0.79589979, 'symbol': 'XRP/USDT',
'BaseVolume': 9349557.01853031, 'info': {
'Bid': 0.789226, 'Ask': 0.79589979,
'Created': '2017-07-14T17:10:10.737', 'BaseVolume': 9349557.01853031,
'High': 0.977, 'Bid': 0.789226,
'Last': 0.79589979, 'Created': '2017-07-14T17:10:10.737',
'Low': 0.781, 'High': 0.977,
'MarketName': 'USDT-XRP', 'Last': 0.79589979,
'OpenBuyOrders': 1075, 'Low': 0.781,
'OpenSellOrders': 6508, 'MarketName': 'USDT-XRP',
'PrevDay': 0.93300218, 'OpenBuyOrders': 1075,
'TimeStamp': '2018-02-05T01:32:42.383', 'OpenSellOrders': 6508,
'Volume': 10801663.00788851 'PrevDay': 0.93300218,
'TimeStamp': '2018-02-05T01:32:42.383',
'Volume': 10801663.00788851
}
}, },
{ 'XVG/USDT': {
'Ask': 0.05154982, 'symbol': 'XVG/USDT',
'BaseVolume': 2311087.71232136, 'info': {
'Bid': 0.05040107, 'Ask': 0.05154982,
'Created': '2017-12-29T19:29:18.357', 'BaseVolume': 2311087.71232136,
'High': 0.06668561, 'Bid': 0.05040107,
'Last': 0.0508, 'Created': '2017-12-29T19:29:18.357',
'Low': 0.05006731, 'High': 0.06668561,
'MarketName': 'USDT-XVG', 'Last': 0.0508,
'OpenBuyOrders': 655, 'Low': 0.05006731,
'OpenSellOrders': 5544, 'MarketName': 'USDT-XVG',
'PrevDay': 0.0627, 'OpenBuyOrders': 655,
'TimeStamp': '2018-02-05T01:32:41.507', 'OpenSellOrders': 5544,
'Volume': 40031424.2152716 'PrevDay': 0.0627,
'TimeStamp': '2018-02-05T01:32:41.507',
'Volume': 40031424.2152716
}
}, },
{ 'ZEC/USDT': {
'Ask': 332.65500022, 'symbol': 'ZEC/USDT',
'BaseVolume': 562911.87455665, 'info': {
'Bid': 330.00000001, 'Ask': 332.65500022,
'Created': '2017-07-14T17:10:10.673', 'BaseVolume': 562911.87455665,
'High': 401.59999999, 'Bid': 330.00000001,
'Last': 332.65500019, 'Created': '2017-07-14T17:10:10.673',
'Low': 330.0, 'High': 401.59999999,
'MarketName': 'USDT-ZEC', 'Last': 332.65500019,
'OpenBuyOrders': 161, 'Low': 330.0,
'OpenSellOrders': 1731, 'MarketName': 'USDT-ZEC',
'PrevDay': 391.42, 'OpenBuyOrders': 161,
'TimeStamp': '2018-02-05T01:32:42.947', 'OpenSellOrders': 1731,
'Volume': 1571.09647946 'PrevDay': 391.42,
'TimeStamp': '2018-02-05T01:32:42.947',
'Volume': 1571.09647946
}
} }
] }

View File

@ -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)

View File

@ -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:

View File

@ -12,77 +12,87 @@ 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': {
'High': 0.00000919, 'symbol': 'TKN/BTC',
'Low': 0.00000820, 'info': {
'Volume': 74339.61396015, 'High': 0.00000919,
'Last': 0.00000820, 'Low': 0.00000820,
'BaseVolume': 1664, 'Volume': 74339.61396015,
'TimeStamp': '2014-07-09T07:19:30.15', 'Last': 0.00000820,
'Bid': 0.00000820, 'BaseVolume': 1664,
'Ask': 0.00000831, 'TimeStamp': '2014-07-09T07:19:30.15',
'OpenBuyOrders': 15, 'Bid': 0.00000820,
'OpenSellOrders': 15, 'Ask': 0.00000831,
'PrevDay': 0.00000821, 'OpenBuyOrders': 15,
'Created': '2014-03-20T06:00:00', 'OpenSellOrders': 15,
'DisplayMarketName': '' 'PrevDay': 0.00000821,
}, { 'Created': '2014-03-20T06:00:00',
'MarketName': 'BTC-ETH', 'DisplayMarketName': ''
'High': 0.00000072, }
'Low': 0.00000001, },
'Volume': 166340678.42280999, 'ETH/BTC': {
'Last': 0.00000005, 'symbol': 'ETH/BTC',
'BaseVolume': 42, 'info': {
'TimeStamp': '2014-07-09T07:21:40.51', 'High': 0.00000072,
'Bid': 0.00000004, 'Low': 0.00000001,
'Ask': 0.00000005, 'Volume': 166340678.42280999,
'OpenBuyOrders': 18, 'Last': 0.00000005,
'OpenSellOrders': 18, 'BaseVolume': 42,
'PrevDay': 0.00000002, 'TimeStamp': '2014-07-09T07:21:40.51',
'Created': '2014-05-30T07:57:49.637', 'Bid': 0.00000004,
'DisplayMarketName': '' 'Ask': 0.00000005,
}, { 'OpenBuyOrders': 18,
'MarketName': 'BTC-BLK', 'OpenSellOrders': 18,
'High': 0.00000072, 'PrevDay': 0.00000002,
'Low': 0.00000001, 'Created': '2014-05-30T07:57:49.637',
'Volume': 166340678.42280999, 'DisplayMarketName': ''
'Last': 0.00000005, }
'BaseVolume': 3, },
'TimeStamp': '2014-07-09T07:21:40.51', 'BLK/BTC': {
'Bid': 0.00000004, 'symbol': 'BLK/BTC',
'Ask': 0.00000005, 'info': {
'OpenBuyOrders': 18, 'High': 0.00000072,
'OpenSellOrders': 18, 'Low': 0.00000001,
'PrevDay': 0.00000002, 'Volume': 166340678.42280999,
'Created': '2014-05-30T07:57:49.637', 'Last': 0.00000005,
'DisplayMarketName': '' 'BaseVolume': 3,
}] 'TimeStamp': '2014-07-09T07:21:40.51',
'Bid': 0.00000004,
'Ask': 0.00000005,
'OpenBuyOrders': 18,
'OpenSellOrders': 18,
'PrevDay': 0.00000002,
'Created': '2014-05-30T07:57:49.637',
'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'])

View File

@ -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]

View File

@ -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)