Merge pull request #1750 from hroff-1902/ccxt-to-exchange-only

minor: limit usage of ccxt to freqtrade/exchange only
This commit is contained in:
Matthias 2019-04-19 06:51:08 +02:00 committed by GitHub
commit 577ccd32f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 66 additions and 44 deletions

View File

@ -9,14 +9,15 @@ from argparse import Namespace
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
import ccxt
from jsonschema import Draft4Validator, validate from jsonschema import Draft4Validator, validate
from jsonschema.exceptions import ValidationError, best_match from jsonschema.exceptions import ValidationError, best_match
from freqtrade import OperationalException, constants from freqtrade import OperationalException, constants
from freqtrade.exchange import is_exchange_supported, supported_exchanges
from freqtrade.misc import deep_merge_dicts from freqtrade.misc import deep_merge_dicts
from freqtrade.state import RunMode from freqtrade.state import RunMode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -384,10 +385,11 @@ class Configuration(object):
:return: True or raised an exception if the exchange if not supported :return: True or raised an exception if the exchange if not supported
""" """
exchange = config.get('exchange', {}).get('name').lower() exchange = config.get('exchange', {}).get('name').lower()
if exchange not in ccxt.exchanges: if not is_exchange_supported(exchange):
exception_msg = f'Exchange "{exchange}" not supported.\n' \ exception_msg = f'Exchange "{exchange}" not supported.\n' \
f'The following exchanges are supported: {", ".join(ccxt.exchanges)}' f'The following exchanges are supported: ' \
f'{", ".join(supported_exchanges())}'
logger.critical(exception_msg) logger.critical(exception_msg)
raise OperationalException( raise OperationalException(

View File

@ -2,9 +2,9 @@
Functions to convert data from one format to another Functions to convert data from one format to another
""" """
import logging import logging
import pandas as pd import pandas as pd
from pandas import DataFrame, to_datetime from pandas import DataFrame, to_datetime
from freqtrade.misc import timeframe_to_minutes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -58,6 +58,8 @@ def ohlcv_fill_up_missing_data(dataframe: DataFrame, ticker_interval: str) -> Da
using the previous close as price for "open", "high" "low" and "close", volume is set to 0 using the previous close as price for "open", "high" "low" and "close", volume is set to 0
""" """
from freqtrade.exchange import timeframe_to_minutes
ohlc_dict = { ohlc_dict = {
'open': 'first', 'open': 'first',
'high': 'max', 'high': 'max',

View File

@ -1,10 +1,10 @@
""" """
Handle historic data (ohlcv). Handle historic data (ohlcv).
includes:
Includes:
* load data for a pair (or a list of pairs) from disk * load data for a pair (or a list of pairs) from disk
* download data from exchange and store to disk * download data from exchange and store to disk
""" """
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Optional, List, Dict, Tuple, Any from typing import Optional, List, Dict, Tuple, Any
@ -15,8 +15,7 @@ from pandas import DataFrame
from freqtrade import misc, OperationalException from freqtrade import misc, OperationalException
from freqtrade.arguments import TimeRange from freqtrade.arguments import TimeRange
from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange, timeframe_to_minutes
from freqtrade.misc import timeframe_to_minutes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -1,3 +1,8 @@
from freqtrade.exchange.exchange import Exchange # noqa: F401 from freqtrade.exchange.exchange import Exchange # noqa: F401
from freqtrade.exchange.exchange import (is_exchange_supported, # noqa: F401
supported_exchanges)
from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401
timeframe_to_minutes,
timeframe_to_msecs)
from freqtrade.exchange.kraken import Kraken # noqa: F401 from freqtrade.exchange.kraken import Kraken # noqa: F401
from freqtrade.exchange.binance import Binance # noqa: F401 from freqtrade.exchange.binance import Binance # noqa: F401

View File

@ -1,5 +1,7 @@
# pragma pylint: disable=W0603 # pragma pylint: disable=W0603
""" Cryptocurrency Exchanges support """ """
Cryptocurrency Exchanges support
"""
import logging import logging
import inspect import inspect
from random import randint from random import randint
@ -16,7 +18,6 @@ from pandas import DataFrame
from freqtrade import (constants, DependencyException, OperationalException, from freqtrade import (constants, DependencyException, OperationalException,
TemporaryError, InvalidOrderException) TemporaryError, InvalidOrderException)
from freqtrade.data.converter import parse_ticker_dataframe from freqtrade.data.converter import parse_ticker_dataframe
from freqtrade.misc import timeframe_to_seconds, timeframe_to_msecs
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -138,7 +139,7 @@ class Exchange(object):
# Find matching class for the given exchange name # Find matching class for the given exchange name
name = exchange_config['name'] name = exchange_config['name']
if name not in ccxt_module.exchanges: if not is_exchange_supported(name, ccxt_module):
raise OperationalException(f'Exchange {name} is not supported') raise OperationalException(f'Exchange {name} is not supported')
ex_config = { ex_config = {
@ -689,3 +690,34 @@ class Exchange(object):
f'Could not get fee info due to {e.__class__.__name__}. Message: {e}') f'Could not get fee info due to {e.__class__.__name__}. Message: {e}')
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) raise OperationalException(e)
def is_exchange_supported(exchange: str, ccxt_module=None) -> bool:
return exchange in supported_exchanges(ccxt_module)
def supported_exchanges(ccxt_module=None) -> List[str]:
return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges
def timeframe_to_seconds(ticker_interval: str) -> int:
"""
Translates the timeframe interval value written in the human readable
form ('1m', '5m', '1h', '1d', '1w', etc.) to the number
of seconds for one timeframe interval.
"""
return ccxt.Exchange.parse_timeframe(ticker_interval)
def timeframe_to_minutes(ticker_interval: str) -> int:
"""
Same as above, but returns minutes.
"""
return ccxt.Exchange.parse_timeframe(ticker_interval) // 60
def timeframe_to_msecs(ticker_interval: str) -> int:
"""
Same as above, but returns milliseconds.
"""
return ccxt.Exchange.parse_timeframe(ticker_interval) * 1000

View File

@ -16,7 +16,7 @@ from freqtrade import (DependencyException, OperationalException, InvalidOrderEx
from freqtrade.data.converter import order_book_to_dataframe from freqtrade.data.converter import order_book_to_dataframe
from freqtrade.data.dataprovider import DataProvider from freqtrade.data.dataprovider import DataProvider
from freqtrade.edge import Edge from freqtrade.edge import Edge
from freqtrade.misc import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.rpc import RPCManager, RPCMessageType
from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver, PairListResolver
@ -460,7 +460,7 @@ class FreqtradeBot(object):
def get_real_amount(self, trade: Trade, order: Dict) -> float: def get_real_amount(self, trade: Trade, order: Dict) -> float:
""" """
Get real amount for the trade Get real amount for the trade
Necessary for self.exchanges which charge fees in base currency (e.g. binance) Necessary for exchanges which charge fees in base currency (e.g. binance)
""" """
order_amount = order['amount'] order_amount = order['amount']
# Only run for closed orders # Only run for closed orders

View File

@ -1,18 +1,17 @@
""" """
Various tool function for Freqtrade and scripts Various tool function for Freqtrade and scripts
""" """
import gzip import gzip
import logging import logging
import re import re
from datetime import datetime from datetime import datetime
from typing import Dict from typing import Dict
from ccxt import Exchange
import numpy as np import numpy as np
from pandas import DataFrame from pandas import DataFrame
import rapidjson import rapidjson
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -132,26 +131,3 @@ def deep_merge_dicts(source, destination):
destination[key] = value destination[key] = value
return destination return destination
def timeframe_to_seconds(ticker_interval: str) -> int:
"""
Translates the timeframe interval value written in the human readable
form ('1m', '5m', '1h', '1d', '1w', etc.) to the number
of seconds for one timeframe interval.
"""
return Exchange.parse_timeframe(ticker_interval)
def timeframe_to_minutes(ticker_interval: str) -> int:
"""
Same as above, but returns minutes.
"""
return Exchange.parse_timeframe(ticker_interval) // 60
def timeframe_to_msecs(ticker_interval: str) -> int:
"""
Same as above, but returns milliseconds.
"""
return Exchange.parse_timeframe(ticker_interval) * 1000

View File

@ -19,12 +19,14 @@ from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.data import history from freqtrade.data import history
from freqtrade.data.dataprovider import DataProvider from freqtrade.data.dataprovider import DataProvider
from freqtrade.misc import file_dump_json, timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.misc import file_dump_json
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver
from freqtrade.state import RunMode from freqtrade.state import RunMode
from freqtrade.strategy.interface import SellType, IStrategy from freqtrade.strategy.interface import SellType, IStrategy
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -6,6 +6,7 @@ from freqtrade.strategy.interface import IStrategy
# Import Default-Strategy to have hyperopt correctly resolve # Import Default-Strategy to have hyperopt correctly resolve
from freqtrade.strategy.default_strategy import DefaultStrategy # noqa: F401 from freqtrade.strategy.default_strategy import DefaultStrategy # noqa: F401
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -16,7 +17,6 @@ def import_strategy(strategy: IStrategy, config: dict) -> IStrategy:
""" """
# Copy all attributes from base class and class # Copy all attributes from base class and class
comb = {**strategy.__class__.__dict__, **strategy.__dict__} comb = {**strategy.__class__.__dict__, **strategy.__dict__}
# Delete '_abc_impl' from dict as deepcopy fails on 3.7 with # Delete '_abc_impl' from dict as deepcopy fails on 3.7 with
@ -26,6 +26,7 @@ def import_strategy(strategy: IStrategy, config: dict) -> IStrategy:
del comb['_abc_impl'] del comb['_abc_impl']
attr = deepcopy(comb) attr = deepcopy(comb)
# Adjust module name # Adjust module name
attr['__module__'] = 'freqtrade.strategy' attr['__module__'] = 'freqtrade.strategy'

View File

@ -13,10 +13,11 @@ import arrow
from pandas import DataFrame from pandas import DataFrame
from freqtrade.data.dataprovider import DataProvider from freqtrade.data.dataprovider import DataProvider
from freqtrade.misc import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.wallets import Wallets from freqtrade.wallets import Wallets
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -3,7 +3,7 @@ from typing import NamedTuple, List
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame
from freqtrade.misc import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.strategy.interface import SellType from freqtrade.strategy.interface import SellType
ticker_start_time = arrow.get(2018, 10, 3) ticker_start_time = arrow.get(2018, 10, 3)

View File

@ -2,7 +2,7 @@
from freqtrade import optimize from freqtrade import optimize
from freqtrade.arguments import TimeRange from freqtrade.arguments import TimeRange
from freqtrade.data import history from freqtrade.data import history
from freqtrade.misc import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.strategy.default_strategy import DefaultStrategy from freqtrade.strategy.default_strategy import DefaultStrategy
from freqtrade.tests.conftest import log_has, patch_exchange from freqtrade.tests.conftest import log_has, patch_exchange

View File

@ -27,10 +27,12 @@ from plotly.offline import plot
from freqtrade.arguments import Arguments from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.data import history from freqtrade.data import history
from freqtrade.misc import common_datearray, timeframe_to_seconds from freqtrade.exchange import timeframe_to_seconds
from freqtrade.misc import common_datearray
from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers import StrategyResolver
from freqtrade.state import RunMode from freqtrade.state import RunMode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)