list-pairs, list-markets subcommands

This commit is contained in:
hroff-1902 2019-07-01 14:36:42 +03:00
parent 4823656028
commit dbdeab4639
4 changed files with 115 additions and 5 deletions

View File

@ -5,7 +5,9 @@ This module contains the argument manager class
import argparse import argparse
import os import os
import re import re
from functools import partial
from typing import List, NamedTuple, Optional from typing import List, NamedTuple, Optional
import arrow import arrow
from freqtrade import __version__, constants from freqtrade import __version__, constants
@ -255,6 +257,26 @@ AVAILABLE_CLI_OPTIONS = {
action='store_true', action='store_true',
dest='print_one_column', dest='print_one_column',
), ),
# List pairs / markets
"print_list": Arg(
'--print-list',
help='Print list of pairs or market symbols. By default data is'
'printed in the tabular format.',
action='store_true',
),
"quote_currency": Arg(
'--quote-currency',
help='Select quote currency.',
),
"base_currency": Arg(
'--base-currency',
help='Select base currency.',
),
"active_only": Arg(
'--active-only',
help='Print only active pairs or markets.',
action='store_true',
),
# Common script options # Common script options
"pairs": Arg( "pairs": Arg(
'-p', '--pairs', '-p', '--pairs',
@ -346,9 +368,11 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "position_stacking", "epochs
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
ARGS_LIST_EXCHANGE = ["print_one_column"] ARGS_LIST_EXCHANGE = ["print_one_column"]
ARGS_LIST_PAIRS = ARGS_COMMON + ["exchange", "print_list", "base_currency", "quote_currency",
"active_only"]
ARGS_DOWNLOADER = ARGS_COMMON + ["pairs", "pairs_file", "days", "exchange", "timeframes", "erase"] ARGS_DOWNLOADER = ARGS_COMMON + ["pairs", "pairs_file", "days", "exchange", "timeframes", "erase"]
ARGS_PLOT_DATAFRAME = (ARGS_COMMON + ARGS_STRATEGY + ARGS_PLOT_DATAFRAME = (ARGS_COMMON + ARGS_STRATEGY +
@ -422,7 +446,7 @@ class Arguments(object):
:return: None :return: None
""" """
from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge
from freqtrade.utils import start_list_exchanges from freqtrade.utils import start_list_exchanges, start_list_pairs
subparsers = self.parser.add_subparsers(dest='subparser') subparsers = self.parser.add_subparsers(dest='subparser')
@ -449,6 +473,23 @@ class Arguments(object):
list_exchanges_cmd.set_defaults(func=start_list_exchanges) list_exchanges_cmd.set_defaults(func=start_list_exchanges)
self.build_args(optionlist=ARGS_LIST_EXCHANGE, parser=list_exchanges_cmd) self.build_args(optionlist=ARGS_LIST_EXCHANGE, parser=list_exchanges_cmd)
# Add list-markets subcommand
list_markets_cmd = subparsers.add_parser(
'list-markets',
help='Print markets on exchange.'
)
list_markets_cmd.set_defaults(func=partial(start_list_pairs, pairs_only=False))
self.build_args(optionlist=ARGS_LIST_PAIRS, parser=list_markets_cmd)
# Add list-pairs subcommand
list_pairs_cmd = subparsers.add_parser(
'list-pairs',
help='Print pairs on exchange.'
)
list_pairs_cmd.set_defaults(func=partial(start_list_pairs, pairs_only=True))
self.build_args(optionlist=ARGS_LIST_PAIRS, parser=list_pairs_cmd)
@staticmethod @staticmethod
def parse_timerange(text: Optional[str]) -> TimeRange: def parse_timerange(text: Optional[str]) -> TimeRange:
""" """

View File

@ -196,6 +196,23 @@ class Exchange(object):
self._load_markets() self._load_markets()
return self._api.markets return self._api.markets
def get_markets(self, base_currency: str = None, quote_currency: str = None,
pairs_only: bool = False, active_only: bool = False) -> Dict:
"""
Return exchange ccxt markets, filtered out by base currency and quote currency
if this was requested in parameters.
"""
markets = self.markets
if base_currency:
markets = {k: v for k, v in markets.items() if v['base'] == base_currency}
if quote_currency:
markets = {k: v for k, v in markets.items() if v['quote'] == quote_currency}
if pairs_only:
markets = {k: v for k, v in markets.items() if '/' in v['symbol']}
if active_only:
markets = {k: v for k, v in markets.items() if v['active']}
return markets
def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame: def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame:
if pair_interval in self._klines: if pair_interval in self._klines:
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]

View File

@ -133,3 +133,6 @@ def deep_merge_dicts(source, destination):
destination[key] = value destination[key] = value
return destination return destination
def plural(num, singular: str, plural: str = None) -> str:
return singular if (num == 1 or num == -1) else plural or singular + 's'

View File

@ -3,9 +3,12 @@ from argparse import Namespace
from typing import Any, Dict from typing import Any, Dict
from freqtrade.configuration import Configuration from freqtrade.configuration import Configuration
from freqtrade.exchange import available_exchanges from freqtrade.exchange import available_exchanges, Exchange
from freqtrade.misc import plural
from freqtrade.state import RunMode from freqtrade.state import RunMode
from tabulate import tabulate
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -39,3 +42,49 @@ def start_list_exchanges(args: Namespace) -> None:
else: else:
print(f"Exchanges supported by ccxt and available for Freqtrade: " print(f"Exchanges supported by ccxt and available for Freqtrade: "
f"{', '.join(available_exchanges())}") f"{', '.join(available_exchanges())}")
def start_list_pairs(args: Namespace, pairs_only: bool = False) -> None:
"""
Print pairs on the exchange
:param args: Cli args from Arguments()
:return: None
"""
# Initialize configuration
config = setup_utils_configuration(args, RunMode.OTHER)
# Fetch exchange name from args, use bittrex as default exchange
config['exchange']['name'] = args.exchange or 'bittrex'
# Init exchange
exchange = Exchange(config)
logger.debug(f"Exchange markets: {exchange.markets}")
pairs = exchange.get_markets(base_currency=args.base_currency,
quote_currency=args.quote_currency,
pairs_only=pairs_only,
active_only=args.active_only)
if args.print_list:
# print data as a list
print(f"Exchange {exchange.name} has {len(pairs)} " +
(plural(len(pairs), "pair" if pairs_only else "market")) +
(f" with {args.base_currency} as base currency" if args.base_currency else "") +
(" and" if args.base_currency and args.quote_currency else "") +
(f" with {args.quote_currency} as quote currency" if args.quote_currency else "") +
(f": {sorted(pairs.keys())}" if len(pairs) else "") + ".")
else:
# # print a table of pairs (markets)
# print('{:<15} {:<15} {:<15} {:<15} {:<15}'.format('id', 'symbol', 'base', 'quote', 'active'))
#
# for (k, v) in pairs.items():
# print('{:<15} {:<15} {:<15} {:<15} {:<15}'.format(v['id'], v['symbol'], v['base'], v['quote'], "Yes" if v['active'] else "No"))
tabular_data = []
for _, v in pairs.items():
tabular_data.append([v['id'], v['symbol'], v['base'], v['quote'],
"Yes" if v['active'] else "No"])
headers = ['Id', 'Symbol', 'Base', 'Quote', 'Active']
print(tabulate(tabular_data, headers=headers, tablefmt='pipe'))