limit usage of ccxt to freqtrade/exchange only
This commit is contained in:
parent
6856848efc
commit
9fbe573cca
@ -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__)
|
||||||
|
|
||||||
|
|
||||||
@ -374,10 +375,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(
|
||||||
|
@ -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',
|
||||||
|
@ -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__)
|
||||||
|
@ -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
|
||||||
|
@ -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 = {
|
||||||
@ -690,3 +691,35 @@ 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) -> str:
|
||||||
|
exchanges = ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges
|
||||||
|
return 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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
|
@ -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__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
@ -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__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from freqtrade.exchange import is_exchange_supported, supported_exchanges
|
||||||
|
|
||||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
sys.path.append(root + '/python')
|
sys.path.append(root + '/python')
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ def dump(*args):
|
|||||||
|
|
||||||
|
|
||||||
def print_supported_exchanges():
|
def print_supported_exchanges():
|
||||||
dump('Supported exchanges:', green(', '.join(ccxt.exchanges)))
|
dump('Supported exchanges:', green(', '.join(supported_exchanges())))
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -52,9 +54,7 @@ try:
|
|||||||
id = sys.argv[1] # get exchange id from command line arguments
|
id = sys.argv[1] # get exchange id from command line arguments
|
||||||
|
|
||||||
# check if the exchange is supported by ccxt
|
# check if the exchange is supported by ccxt
|
||||||
exchange_found = id in ccxt.exchanges
|
if is_exchange_supported(id):
|
||||||
|
|
||||||
if exchange_found:
|
|
||||||
dump('Instantiating', green(id), 'exchange')
|
dump('Instantiating', green(id), 'exchange')
|
||||||
|
|
||||||
# instantiate the exchange by id
|
# instantiate the exchange by id
|
||||||
@ -79,9 +79,7 @@ try:
|
|||||||
|
|
||||||
for (k, v) in tuples:
|
for (k, v) in tuples:
|
||||||
dump('{:<15} {:<15} {:<15} {:<15}'.format(v['id'], v['symbol'], v['base'], v['quote']))
|
dump('{:<15} {:<15} {:<15} {:<15}'.format(v['id'], v['symbol'], v['base'], v['quote']))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
dump('Exchange ' + red(id) + ' not found')
|
dump('Exchange ' + red(id) + ' not found')
|
||||||
print_supported_exchanges()
|
print_supported_exchanges()
|
||||||
|
|
||||||
|
@ -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__)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user