diff --git a/config.json.example b/config.json.example
index 2c464a925..6a4f20cd6 100644
--- a/config.json.example
+++ b/config.json.example
@@ -13,19 +13,19 @@
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"pair_whitelist": [
- "BTC_ETH",
- "BTC_LTC",
- "BTC_ETC",
- "BTC_DASH",
- "BTC_ZEC",
- "BTC_XLM",
- "BTC_NXT",
- "BTC_POWR",
- "BTC_ADA",
- "BTC_XMR"
+ "ETH/BTC",
+ "LTC/BTC",
+ "ETC/BTC",
+ "DASH/BTC",
+ "ZEC/BTC",
+ "XLM/BTC",
+ "NXT/BTC",
+ "POWR/BTC",
+ "ADA/BTC",
+ "XMR/BTC"
],
"pair_blacklist": [
- "BTC_DOGE"
+ "DOGE/BTC"
]
},
"experimental": {
diff --git a/config_full.json.example b/config_full.json.example
index c74b59660..d0f9d1260 100644
--- a/config_full.json.example
+++ b/config_full.json.example
@@ -21,19 +21,19 @@
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"pair_whitelist": [
- "BTC_ETH",
- "BTC_LTC",
- "BTC_ETC",
- "BTC_DASH",
- "BTC_ZEC",
- "BTC_XLM",
- "BTC_NXT",
- "BTC_POWR",
- "BTC_ADA",
- "BTC_XMR"
+ "ETH/BTC",
+ "LTC/BTC",
+ "ETC/BTC",
+ "DASH/BTC",
+ "ZEC/BTC",
+ "XLM/BTC",
+ "NXT/BTC",
+ "POWR/BTC",
+ "ADA/BTC",
+ "XMR/BTC"
],
"pair_blacklist": [
- "BTC_DOGE"
+ "DOGE/BTC"
]
},
"experimental": {
diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py
index f52de835e..16f8b3b4a 100644
--- a/freqtrade/__init__.py
+++ b/freqtrade/__init__.py
@@ -21,4 +21,4 @@ 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.
- """
\ No newline at end of file
+ """
diff --git a/freqtrade/analyze.py b/freqtrade/analyze.py
index 8bc552d74..e6e8023f0 100644
--- a/freqtrade/analyze.py
+++ b/freqtrade/analyze.py
@@ -44,12 +44,14 @@ class Analyze(object):
:param ticker: See exchange.get_ticker_history
:return: DataFrame
"""
- columns = {'C': 'close', 'V': 'volume', 'O': 'open', 'H': 'high', 'L': 'low', 'T': 'date'}
- frame = DataFrame(ticker) \
- .rename(columns=columns)
- if 'BV' in frame:
- frame.drop('BV', 1, inplace=True)
- frame['date'] = to_datetime(frame['date'], utc=True, infer_datetime_format=True)
+ cols = ['date', 'open', 'high', 'low', 'close', 'volume']
+ frame = DataFrame(ticker, columns=cols)
+
+ frame['date'] = to_datetime(frame['date'],
+ unit='ms',
+ utc=True,
+ infer_datetime_format=True)
+
frame.sort_values('date', inplace=True)
return frame
diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py
index 9a7cd08a5..931fd366c 100644
--- a/freqtrade/exchange/__init__.py
+++ b/freqtrade/exchange/__init__.py
@@ -2,8 +2,11 @@
""" Cryptocurrency Exchanges support """
import enum
import logging
+import ccxt
from random import randint
from typing import List, Dict, Any, Optional
+from cachetools import cached, TTLCache
+from datetime import datetime
import ccxt
import arrow
@@ -11,10 +14,12 @@ from cachetools import cached, TTLCache
from freqtrade import OperationalException, DependencyException, NetworkException
+
logger = logging.getLogger(__name__)
# Current selected exchange
_API: ccxt.Exchange = None
+
_CONF: dict = {}
API_RETRY_COUNT = 4
@@ -23,7 +28,6 @@ _DRY_RUN_OPEN_ORDERS: Dict[str, Any] = {}
_TICKER_CACHE: dict = {}
-
def retrier(f):
def wrapper(*args, **kwargs):
count = kwargs.pop('count', API_RETRY_COUNT)
@@ -85,6 +89,10 @@ def validate_pairs(pairs: List[str]) -> None:
:param pairs: list of pairs
:return: None
"""
+
+ if not _API.markets:
+ _API.load_markets()
+
try:
markets = _API.load_markets()
except ccxt.BaseError as e:
@@ -314,7 +322,15 @@ def get_markets() -> List[dict]:
def get_name() -> str:
- return _API.name
+ return _API.__class__.__name__.capitalize()
+
+
+def get_fee_maker() -> float:
+ return _API.fees['trading']['maker']
+
+
+def get_fee_taker() -> float:
+ return _API.fees['trading']['taker']
def get_fee() -> float:
diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py
index 29790515e..1cdaff749 100644
--- a/freqtrade/freqtradebot.py
+++ b/freqtrade/freqtradebot.py
@@ -193,13 +193,12 @@ class FreqtradeBot(object):
:return: List of pairs
"""
summaries = sorted(
- (s for s in exchange.get_market_summaries() if
- s['MarketName'].startswith(base_currency)),
- key=lambda s: s.get(key) or 0.0,
+ (v for s, v in exchange.get_market_summaries().items() if v['symbol'].endswith(base_currency)),
+ key=lambda v: v.get('info').get(key) or 0.0,
reverse=True
)
- return [s['MarketName'].replace('-', '_') for s in summaries]
+ return [s['symbol'] for s in summaries]
def _refresh_whitelist(self, whitelist: List[str]) -> List[str]:
"""
@@ -212,15 +211,15 @@ class FreqtradeBot(object):
sanitized_whitelist = whitelist
health = exchange.get_wallet_health()
known_pairs = set()
- for status in health:
- pair = '{}_{}'.format(self.config['stake_currency'], status['Currency'])
+ for symbol, status in health.items():
+ pair = f"{status['base']}/{self.config['stake_currency']}"
# pair is not int the generated dynamic market, or in the blacklist ... ignore it
if pair not in whitelist or pair in self.config['exchange'].get('pair_blacklist', []):
continue
# else the pair is valid
known_pairs.add(pair)
# Market is not active
- if not status['IsActive']:
+ if not status['active']:
sanitized_whitelist.remove(pair)
self.logger.info(
'Ignoring %s from whitelist (reason: %s).',
@@ -313,7 +312,7 @@ class FreqtradeBot(object):
pair=pair,
stake_amount=stake_amount,
amount=amount,
- fee=exchange.get_fee(),
+ fee=exchange.get_fee_maker(),
open_rate=buy_limit,
open_date=datetime.utcnow(),
exchange=exchange.get_name().upper(),
diff --git a/freqtrade/misc.py b/freqtrade/misc.py
index f5d045c44..bc04d6b88 100644
--- a/freqtrade/misc.py
+++ b/freqtrade/misc.py
@@ -72,3 +72,11 @@ def file_dump_json(filename, data) -> None:
"""
with open(filename, 'w') as fp:
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')
diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py
index a26744691..30be5dc33 100644
--- a/freqtrade/optimize/__init__.py
+++ b/freqtrade/optimize/__init__.py
@@ -35,7 +35,7 @@ def load_tickerdata_file(
"""
path = make_testdata_path(datadir)
file = os.path.join(path, '{pair}-{ticker_interval}.json'.format(
- pair=pair,
+ pair=pair.replace('/', '_'),
ticker_interval=ticker_interval,
))
gzipfile = file + '.gz'
@@ -126,7 +126,7 @@ def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) ->
interval
)
- filepair = pair.replace("-", "_")
+ filepair = pair.replace("/", "_")
filename = os.path.join(path, '{pair}-{interval}.json'.format(
pair=filepair,
interval=interval,
@@ -135,8 +135,8 @@ def download_backtesting_testdata(datadir: str, pair: str, interval: int = 5) ->
if os.path.isfile(filename):
with open(filename, "rt") as file:
data = json.load(file)
- logger.debug("Current Start: %s", data[1]['T'])
- logger.debug("Current End: %s", data[-1:][0]['T'])
+ logger.debug("Current Start: %s", misc.format_ms_time(data[1][0]))
+ logger.debug("Current End: %s", misc.format_ms_time(data[-1:][0][0]))
else:
data = []
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:
if row not in data:
data.append(row)
- logger.debug("New Start: %s", data[1]['T'])
- logger.debug("New End: %s", data[-1:][0]['T'])
- data = sorted(data, key=lambda data: data['T'])
+ logger.debug("New Start: %s", misc.format_ms_time(data[0][0]))
+ logger.debug("New End: %s", misc.format_ms_time(data[-1:][0][0]))
+ data = sorted(data, key=lambda data: data[0])
misc.file_dump_json(filename, data)
diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py
index a3edfaa7d..6a06c6616 100644
--- a/freqtrade/optimize/backtesting.py
+++ b/freqtrade/optimize/backtesting.py
@@ -12,6 +12,7 @@ from pandas import DataFrame, Series
from tabulate import tabulate
import freqtrade.optimize as optimize
+import freqtrade.exchange as exchange
from freqtrade import exchange
from freqtrade.analyze import Analyze
from freqtrade.arguments import Arguments
@@ -52,7 +53,11 @@ class Backtesting(object):
self.tickerdata_to_dataframe = self.analyze.tickerdata_to_dataframe
self.populate_buy_trend = self.analyze.populate_buy_trend
self.populate_sell_trend = self.analyze.populate_sell_trend
- exchange._API = ccxt.bittrex({'key': '', 'secret': ''})
+
+ # Reset keys for backtesting
+ self.config['exchange']['key'] = ''
+ self.config['exchange']['secret'] = ''
+ exchange.init(self.config)
@staticmethod
def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]:
diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py
index 0b0b6d3da..3f14ef87b 100644
--- a/freqtrade/tests/conftest.py
+++ b/freqtrade/tests/conftest.py
@@ -128,32 +128,31 @@ def ticker_sell_down():
@pytest.fixture
def health():
- return MagicMock(return_value=[{
- 'Currency': 'BTC',
- 'IsActive': True,
- 'LastChecked': '2017-11-13T20:15:00.00',
- 'Notice': None
- }, {
- 'Currency': 'ETH',
- 'IsActive': True,
- 'LastChecked': '2017-11-13T20:15:00.00',
- 'Notice': None
- }, {
- 'Currency': 'TRST',
- 'IsActive': True,
- 'LastChecked': '2017-11-13T20:15:00.00',
- 'Notice': None
- }, {
- 'Currency': 'SWT',
- 'IsActive': True,
- 'LastChecked': '2017-11-13T20:15:00.00',
- 'Notice': None
- }, {
- 'Currency': 'BCC',
- 'IsActive': False,
- 'LastChecked': '2017-11-13T20:15:00.00',
- 'Notice': None
- }])
+ return MagicMock(return_value={
+ "ETH/BTC": {
+ 'base': 'ETH',
+ 'active': True,
+ 'LastChecked': '2017-11-13T20:15:00.00',
+ 'Notice': None
+ },
+ "TRST/BTC": {
+ 'base': 'TRST',
+ 'active': True,
+ 'LastChecked': '2017-11-13T20:15:00.00',
+ 'Notice': None
+ },
+ "SWT/BTC": {
+ 'base': 'SWT',
+ 'active': True,
+ 'LastChecked': '2017-11-13T20:15:00.00',
+ 'Notice': None
+ },
+ "BCC/BTC": {
+ 'base': 'BCC',
+ 'active': False,
+ 'LastChecked': '2017-11-13T20:15:00.00',
+ 'Notice': None
+ }})
@pytest.fixture
@@ -336,4 +335,3 @@ def result():
# that inserts a trade of some type and open-status
# return the open-order-id
# See tests in rpc/main that could use this
-
diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py
index 8805cfab3..88dee0b26 100644
--- a/freqtrade/tests/exchange/test_exchange.py
+++ b/freqtrade/tests/exchange/test_exchange.py
@@ -334,7 +334,8 @@ def test_get_ticker_history(default_conf, mocker):
type(api_mock).has = has
api_mock.fetch_ohlcv = MagicMock(return_value=tick)
mocker.patch('freqtrade.exchange._API', api_mock)
-
+ mocker.patch('freqtrade.exchange._API.has', {'fetchOHLCV': True})
+ mocker.patch('freqtrade.exchange._API.fetch_ohlcv', return_value=tick)
# retrieve original ticker
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0]['O'] == 1
diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py
index 84b06bee2..bbaa2385f 100644
--- a/freqtrade/tests/rpc/test_rpc.py
+++ b/freqtrade/tests/rpc/test_rpc.py
@@ -59,7 +59,7 @@ def test_rpc_trade_status(default_conf, ticker, mocker) -> None:
result_message = [
'*Trade ID:* `1`\n'
'*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'
'*Amount:* `90.99181074`\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)`'
]
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:
@@ -102,7 +102,7 @@ def test_rpc_status_table(default_conf, ticker, mocker) -> None:
freqtradebot.create_trade()
(error, result) = rpc.rpc_status_table()
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()
@@ -214,7 +214,7 @@ def test_rpc_trade_statistics(
assert stats['first_trade_date'] == 'just now'
assert stats['latest_trade_date'] == 'just now'
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)
@@ -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['latest_trade_date'] == 'just now'
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)
@@ -509,7 +509,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order,
(error, res) = rpc.rpc_performance()
assert not error
assert len(res) == 1
- assert res[0]['pair'] == 'BTC_ETH'
+ assert res[0]['pair'] == 'ETH/BTC'
assert res[0]['count'] == 1
assert prec_satoshi(res[0]['profit'], 6.2)
diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py
index 86dfd6f41..6dbe6c710 100644
--- a/freqtrade/tests/rpc/test_rpc_telegram.py
+++ b/freqtrade/tests/rpc/test_rpc_telegram.py
@@ -248,7 +248,8 @@ def test_status(default_conf, update, mocker, ticker) -> None:
mocker.patch.multiple(
'freqtrade.freqtradebot.exchange',
validate_pairs=MagicMock(),
- get_ticker=ticker
+ get_ticker=ticker,
+ get_pair_detail_url=MagicMock()
)
msg_mock = MagicMock()
status_table = MagicMock()
@@ -319,7 +320,7 @@ def test_status_handle(default_conf, update, ticker, mocker) -> None:
telegram._status(bot=MagicMock(), update=update)
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:
@@ -369,7 +370,7 @@ def test_status_table_handle(default_conf, update, ticker, mocker) -> None:
fields = re.sub('[ ]+', ' ', line[2].strip()).split(' ')
assert int(fields[0]) == 1
- assert fields[1] == 'BTC_ETH'
+ assert fields[1] == 'ETH/BTC'
assert msg_mock.call_count == 1
@@ -387,7 +388,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order,
mocker.patch.multiple(
'freqtrade.freqtradebot.exchange',
validate_pairs=MagicMock(),
- get_ticker=ticker
+ get_ticker=ticker,
+ get_pair_detail_url=MagicMock()
)
msg_mock = MagicMock()
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.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:
@@ -779,7 +781,7 @@ def test_forcesell_handle(default_conf, update, ticker, ticker_sell_up, mocker)
assert rpc_mock.call_count == 2
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 '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]
@@ -822,7 +824,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, ticker_sell_down, m
assert rpc_mock.call_count == 2
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 '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]
@@ -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)
rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
+ mocker.patch('freqtrade.exchange.get_pair_detail_url', MagicMock())
mocker.patch.multiple(
'freqtrade.freqtradebot.exchange',
validate_pairs=MagicMock(),
@@ -942,7 +945,7 @@ def test_performance_handle(default_conf, update, ticker, limit_buy_order,
telegram._performance(bot=MagicMock(), update=update)
assert msg_mock.call_count == 1
assert 'Performance' in msg_mock.call_args_list[0][0][0]
- assert 'BTC_ETH\t6.20% (1)
' in msg_mock.call_args_list[0][0][0]
+ assert 'ETH/BTC\t6.20% (1)
' in msg_mock.call_args_list[0][0][0]
def test_performance_handle_invalid(default_conf, update, mocker) -> None:
diff --git a/freqtrade/tests/test_acl_pair.py b/freqtrade/tests/test_acl_pair.py
index b5f52774d..174f1fde9 100644
--- a/freqtrade/tests/test_acl_pair.py
+++ b/freqtrade/tests/test_acl_pair.py
@@ -12,77 +12,87 @@ def whitelist_conf():
config['stake_currency'] = 'BTC'
config['exchange']['pair_whitelist'] = [
- 'BTC_ETH',
- 'BTC_TKN',
- 'BTC_TRST',
- 'BTC_SWT',
- 'BTC_BCC'
+ 'ETH/BTC',
+ 'TKN/BTC',
+ 'TRST/BTC',
+ 'SWT/BTC',
+ 'BCC/BTC'
]
config['exchange']['pair_blacklist'] = [
- 'BTC_BLK'
+ 'BLK/BTC'
]
return config
def get_market_summaries():
- return [{
- 'MarketName': 'BTC-TKN',
- 'High': 0.00000919,
- 'Low': 0.00000820,
- 'Volume': 74339.61396015,
- 'Last': 0.00000820,
- 'BaseVolume': 1664,
- 'TimeStamp': '2014-07-09T07:19:30.15',
- 'Bid': 0.00000820,
- 'Ask': 0.00000831,
- 'OpenBuyOrders': 15,
- 'OpenSellOrders': 15,
- 'PrevDay': 0.00000821,
- 'Created': '2014-03-20T06:00:00',
- 'DisplayMarketName': ''
- }, {
- 'MarketName': 'BTC-ETH',
- 'High': 0.00000072,
- 'Low': 0.00000001,
- 'Volume': 166340678.42280999,
- 'Last': 0.00000005,
- 'BaseVolume': 42,
- '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': ''
- }, {
- 'MarketName': 'BTC-BLK',
- 'High': 0.00000072,
- 'Low': 0.00000001,
- 'Volume': 166340678.42280999,
- 'Last': 0.00000005,
- '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': ''
- }]
+ return {
+ 'TKN/BTC': {
+ 'symbol': 'TKN/BTC',
+ 'info': {
+ 'High': 0.00000919,
+ 'Low': 0.00000820,
+ 'Volume': 74339.61396015,
+ 'Last': 0.00000820,
+ 'BaseVolume': 1664,
+ 'TimeStamp': '2014-07-09T07:19:30.15',
+ 'Bid': 0.00000820,
+ 'Ask': 0.00000831,
+ 'OpenBuyOrders': 15,
+ 'OpenSellOrders': 15,
+ 'PrevDay': 0.00000821,
+ 'Created': '2014-03-20T06:00:00',
+ 'DisplayMarketName': ''
+ }
+ },
+ 'ETH/BTC': {
+ 'symbol': 'ETH/BTC',
+ 'info': {
+ 'High': 0.00000072,
+ 'Low': 0.00000001,
+ 'Volume': 166340678.42280999,
+ 'Last': 0.00000005,
+ 'BaseVolume': 42,
+ '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': ''
+ }
+ },
+ 'BLK/BTC': {
+ 'symbol': 'BLK/BTC',
+ 'info': {
+ 'High': 0.00000072,
+ 'Low': 0.00000001,
+ 'Volume': 166340678.42280999,
+ 'Last': 0.00000005,
+ '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():
- return [{'Currency': 'ETH', 'IsActive': True},
- {'Currency': 'TKN', 'IsActive': True},
- {'Currency': 'BLK', 'IsActive': True}]
+ return {
+ 'ETH/BTC': {'base': 'ETH', 'active': True},
+ 'TKN/BTC': {'base': 'TKN', 'active': True},
+ 'BLK/BTC': {'base': 'BLK', 'active': True}}
def get_health_empty():
- return []
+ return {}
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)
refreshedwhitelist = freqtradebot._refresh_whitelist(
- conf['exchange']['pair_whitelist'] + ['BTC_XXX']
+ conf['exchange']['pair_whitelist'] + ['XXX/BTC']
)
# List ordered by BaseVolume
- whitelist = ['BTC_ETH', 'BTC_TKN']
+ whitelist = ['ETH/BTC', 'TKN/BTC']
# Ensure all except those in whitelist are removed
assert whitelist == refreshedwhitelist
@@ -108,7 +118,7 @@ def test_refresh_whitelist(mocker):
refreshedwhitelist = freqtradebot._refresh_whitelist(conf['exchange']['pair_whitelist'])
# List ordered by BaseVolume
- whitelist = ['BTC_ETH', 'BTC_TKN']
+ whitelist = ['ETH/BTC', 'TKN/BTC']
# Ensure all except those in whitelist are removed
assert whitelist == refreshedwhitelist
@@ -123,7 +133,7 @@ def test_refresh_whitelist_dynamic(mocker):
)
# argument: use the whitelist dynamically by exchange-volume
- whitelist = ['BTC_TKN', 'BTC_ETH']
+ whitelist = ['TKN/BTC', 'ETH/BTC']
refreshedwhitelist = freqtradebot._refresh_whitelist(
freqtradebot._gen_pair_whitelist(conf['stake_currency'])
diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py
index caf07868c..3792fd88d 100644
--- a/freqtrade/tests/test_freqtradebot.py
+++ b/freqtrade/tests/test_freqtradebot.py
@@ -213,15 +213,15 @@ def test_gen_pair_whitelist(mocker, default_conf, get_market_summaries_data) ->
# Test to retrieved BTC sorted on BaseVolume
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
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
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)
whitelist = freqtrade._gen_pair_whitelist(base_currency='ETH')
@@ -330,8 +330,8 @@ def test_create_trade_no_pairs(default_conf, ticker, mocker) -> None:
)
conf = deepcopy(default_conf)
- conf['exchange']['pair_whitelist'] = ["BTC_ETH"]
- conf['exchange']['pair_blacklist'] = ["BTC_ETH"]
+ conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
+ conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
freqtrade.create_trade()
@@ -355,8 +355,8 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker, mocker) ->
)
conf = deepcopy(default_conf)
- conf['exchange']['pair_whitelist'] = ["BTC_ETH"]
- conf['exchange']['pair_blacklist'] = ["BTC_ETH"]
+ conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
+ conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
freqtrade.create_trade()
@@ -790,7 +790,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
trade_buy = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
open_rate=0.00001099,
exchange='BITTREX',
open_order_id='123456789',
@@ -829,7 +829,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
trade_sell = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
open_rate=0.00001099,
exchange='BITTREX',
open_order_id='123456789',
@@ -868,7 +868,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
trade_buy = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
open_rate=0.00001099,
exchange='BITTREX',
open_order_id='123456789',
@@ -915,7 +915,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) -
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
trade_buy = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
open_rate=0.00001099,
exchange='BITTREX',
open_order_id='123456789',
@@ -928,7 +928,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) -
Trade.session.add(trade_buy)
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 '
'recent call last):\n.*'
)
@@ -1021,7 +1021,7 @@ def test_execute_sell_up(default_conf, ticker, ticker_sell_up, mocker) -> None:
assert rpc_mock.call_count == 2
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 'Profit' in rpc_mock.call_args_list[-1][0][0]
assert '0.00001172' in rpc_mock.call_args_list[-1][0][0]
@@ -1061,7 +1061,7 @@ def test_execute_sell_down(default_conf, ticker, ticker_sell_down, mocker) -> No
assert rpc_mock.call_count == 2
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 '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]
@@ -1100,7 +1100,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, ticker_sell_up,
assert rpc_mock.call_count == 2
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 '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]
@@ -1140,7 +1140,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker,
assert rpc_mock.call_count == 2
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 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py
index adf1b37f3..5e80c632b 100644
--- a/freqtrade/tests/test_persistence.py
+++ b/freqtrade/tests/test_persistence.py
@@ -145,7 +145,7 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order):
def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -167,7 +167,7 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order):
def test_calc_close_trade_price_exception(limit_buy_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -180,7 +180,7 @@ def test_calc_close_trade_price_exception(limit_buy_order):
def test_update_open_order(limit_buy_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=1.00,
fee=0.1,
exchange='bittrex',
@@ -202,7 +202,7 @@ def test_update_open_order(limit_buy_order):
def test_update_invalid_order(limit_buy_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=1.00,
fee=0.1,
exchange='bittrex',
@@ -214,7 +214,7 @@ def test_update_invalid_order(limit_buy_order):
def test_calc_open_trade_price(limit_buy_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -231,7 +231,7 @@ def test_calc_open_trade_price(limit_buy_order):
def test_calc_close_trade_price(limit_buy_order, limit_sell_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -252,7 +252,7 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order):
def test_calc_profit(limit_buy_order, limit_sell_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -282,7 +282,7 @@ def test_calc_profit(limit_buy_order, limit_sell_order):
def test_calc_profit_percent(limit_buy_order, limit_sell_order):
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
fee=0.0025,
exchange='bittrex',
@@ -309,35 +309,35 @@ def test_clean_dry_run_db(default_conf):
# Simulate dry_run entries
trade = Trade(
- pair='BTC_ETH',
+ pair='ETH/BTC',
stake_amount=0.001,
amount=123.0,
fee=0.0025,
open_rate=0.123,
- exchange='BITTREX',
+ exchange='bittrex',
open_order_id='dry_run_buy_12345'
)
Trade.session.add(trade)
trade = Trade(
- pair='BTC_ETC',
+ pair='ETC/BTC',
stake_amount=0.001,
amount=123.0,
fee=0.0025,
open_rate=0.123,
- exchange='BITTREX',
+ exchange='bittrex',
open_order_id='dry_run_sell_12345'
)
Trade.session.add(trade)
# Simulate prod entry
trade = Trade(
- pair='BTC_ETC',
+ pair='ETC/BTC',
stake_amount=0.001,
amount=123.0,
fee=0.0025,
open_rate=0.123,
- exchange='BITTREX',
+ exchange='bittrex',
open_order_id='prod_buy_12345'
)
Trade.session.add(trade)
diff --git a/requirements.txt b/requirements.txt
index f802f7ae4..6295164bb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-python-bittrex==0.3.0
+ccxt==1.11.149
SQLAlchemy==1.2.5
python-telegram-bot==10.0.1
arrow==0.12.1
diff --git a/scripts/plot_dataframe.py b/scripts/plot_dataframe.py
index 285ba6d97..5c5e17661 100755
--- a/scripts/plot_dataframe.py
+++ b/scripts/plot_dataframe.py
@@ -55,7 +55,7 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
if args.live:
logger.info('Downloading pair.')
# Init Bittrex to use public API
- exchange._API = exchange.Bittrex({'key': '', 'secret': ''})
+ exchange.init({'key': '', 'secret': ''})
tickers[pair] = exchange.get_ticker_history(pair, tick_interval)
else:
tickers = optimize.load_data(
diff --git a/setup.py b/setup.py
index 4b0635efa..856a47181 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ setup(name='freqtrade',
setup_requires=['pytest-runner'],
tests_require=['pytest', 'pytest-mock', 'pytest-cov'],
install_requires=[
- 'python-bittrex',
+ 'ccxt',
'SQLAlchemy',
'python-telegram-bot',
'arrow',