mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Enhance list-exchanges with more information
This commit is contained in:
parent
b5d1017779
commit
250ae2d006
|
@ -30,18 +30,34 @@ def start_list_exchanges(args: Dict[str, Any]) -> None:
|
|||
if args['print_one_column']:
|
||||
print('\n'.join([e['name'] for e in exchanges]))
|
||||
else:
|
||||
if args['list_exchanges_all']:
|
||||
print("All exchanges supported by the ccxt library:")
|
||||
else:
|
||||
print("Exchanges available for Freqtrade:")
|
||||
exchanges = [e for e in exchanges if e['valid'] is not False]
|
||||
|
||||
headers = {
|
||||
'name': 'Exchange name',
|
||||
'valid': 'Valid',
|
||||
'comment': 'reason',
|
||||
}
|
||||
print(tabulate(exchanges, headers=headers))
|
||||
'supported': 'Supported',
|
||||
'trade_modes': 'Markets',
|
||||
'comment': 'Reason',
|
||||
}
|
||||
|
||||
def build_entry(exchange, valid):
|
||||
valid_entry = {'valid': exchange['valid']} if valid else {}
|
||||
result = {
|
||||
'name': exchange['name'],
|
||||
**valid_entry,
|
||||
'supported': 'Official' if exchange['supported'] else '',
|
||||
'trade_modes': ', '.join(exchange['trade_modes']),
|
||||
'comment': exchange['comment'],
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
if args['list_exchanges_all']:
|
||||
print("All exchanges supported by the ccxt library:")
|
||||
exchanges = [build_entry(e, True) for e in exchanges]
|
||||
else:
|
||||
print("Exchanges available for Freqtrade:")
|
||||
exchanges = [build_entry(e, False) for e in exchanges if e['valid'] is not False]
|
||||
|
||||
print(tabulate(exchanges, headers=headers, ))
|
||||
|
||||
|
||||
def _print_objs_tabular(objs: List, print_colorized: bool) -> None:
|
||||
|
|
|
@ -9,7 +9,8 @@ import ccxt
|
|||
from ccxt import (DECIMAL_PLACES, ROUND, ROUND_DOWN, ROUND_UP, SIGNIFICANT_DIGITS, TICK_SIZE,
|
||||
TRUNCATE, decimal_to_precision)
|
||||
|
||||
from freqtrade.exchange.common import BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED
|
||||
from freqtrade.exchange.common import (BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED,
|
||||
SUPPORTED_EXCHANGES)
|
||||
from freqtrade.exchange.types import ValidExchangesType
|
||||
from freqtrade.util import FtPrecise
|
||||
from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts
|
||||
|
@ -56,15 +57,39 @@ def validate_exchange(exchange: str) -> Tuple[bool, str]:
|
|||
return True, ''
|
||||
|
||||
|
||||
def build_exchange_list_entry(
|
||||
exchange_name: str, exchangeClasses: Dict[str, Any]) -> ValidExchangesType:
|
||||
valid, comment = validate_exchange(exchange_name)
|
||||
result = {
|
||||
'name': exchange_name,
|
||||
'valid': valid,
|
||||
'supported': exchange_name.lower() in SUPPORTED_EXCHANGES,
|
||||
'comment': comment,
|
||||
'trade_modes': ['spot'],
|
||||
}
|
||||
if resolved := exchangeClasses.get(exchange_name.lower()):
|
||||
supported_modes = ['spot'] + [
|
||||
f"{mm.value} {tm.value}"
|
||||
for tm, mm in resolved['class']._supported_trading_mode_margin_pairs
|
||||
]
|
||||
result.update({
|
||||
'trade_modes': supported_modes,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def validate_exchanges(all_exchanges: bool) -> List[ValidExchangesType]:
|
||||
"""
|
||||
:return: List of tuples with exchangename, valid, reason.
|
||||
"""
|
||||
exchanges = ccxt_exchanges() if all_exchanges else available_exchanges()
|
||||
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
||||
|
||||
subclassed = {e['name'].lower(): e for e in ExchangeResolver.search_all_objects({}, False)}
|
||||
|
||||
exchanges_valid: List[ValidExchangesType] = [
|
||||
{'name': e, 'valid': valid, 'comment': comment}
|
||||
for e, valid, comment in ((e, *validate_exchange(e)) for e in exchanges)
|
||||
build_exchange_list_entry(e, subclassed) for e in exchanges
|
||||
]
|
||||
|
||||
return exchanges_valid
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
This module loads custom exchanges
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional
|
||||
from inspect import isclass
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import freqtrade.exchange as exchanges
|
||||
from freqtrade.constants import Config, ExchangeConfig
|
||||
|
@ -72,3 +73,26 @@ class ExchangeResolver(IResolver):
|
|||
f"Impossible to load Exchange '{exchange_name}'. This class does not exist "
|
||||
"or contains Python code errors."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def search_all_objects(cls, config: Config, enum_failed: bool,
|
||||
recursive: bool = False) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Searches for valid objects
|
||||
:param config: Config object
|
||||
:param enum_failed: If True, will return None for modules which fail.
|
||||
Otherwise, failing modules are skipped.
|
||||
:param recursive: Recursively walk directory tree searching for strategies
|
||||
:return: List of dicts containing 'name', 'class' and 'location' entries
|
||||
"""
|
||||
result = []
|
||||
for exchange_name in dir(exchanges):
|
||||
exchange = getattr(exchanges, exchange_name)
|
||||
if isclass(exchange) and issubclass(exchange, Exchange):
|
||||
result.append({
|
||||
'name': exchange_name,
|
||||
'class': exchange,
|
||||
'location': exchange.__module__,
|
||||
'location_rel: ': exchange.__module__.replace('freqtrade.', ''),
|
||||
})
|
||||
return result
|
||||
|
|
|
@ -41,7 +41,7 @@ class IResolver:
|
|||
object_type: Type[Any]
|
||||
object_type_str: str
|
||||
user_subdir: Optional[str] = None
|
||||
initial_search_path: Optional[Path]
|
||||
initial_search_path: Optional[Path] = None
|
||||
# Optional config setting containing a path (strategy_path, freqaimodel_path)
|
||||
extra_path: Optional[str] = None
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user