Пример #1
0
def get_exchange(exchange_name):
    exchange_auth = get_exchange_auth(exchange_name)
    if exchange_name == 'bitfinex':
        return Bitfinex(
            key=exchange_auth['key'],
            secret=exchange_auth['secret'],
            base_currency=None,  # TODO: make optional at the exchange
            portfolio=None
        )
    elif exchange_name == 'bittrex':
        return Bittrex(
            key=exchange_auth['key'],
            secret=exchange_auth['secret'],
            base_currency=None,
            portfolio=None
        )
    elif exchange_name == 'poloniex':
        return Poloniex(
            key=exchange_auth['key'],
            secret=exchange_auth['secret'],
            base_currency=None,
            portfolio=None
        )
    else:
        raise ExchangeNotFoundError(exchange_name=exchange_name)
Пример #2
0
    def __init__(self, exchange_name, key,
                 secret, password, quote_currency):
        log.debug(
            'finding {} in CCXT exchanges:\n{}'.format(
                exchange_name, ccxt.exchanges
            )
        )
        try:
            # Making instantiation as explicit as possible for code tracking.
            if exchange_name in SUPPORTED_EXCHANGES:
                exchange_attr = SUPPORTED_EXCHANGES[exchange_name]

            else:
                exchange_attr = getattr(ccxt, exchange_name)

            self.api = exchange_attr({
                'apiKey': key,
                'secret': secret,
                'password': password,
            })
            self.api.enableRateLimit = True

        except Exception:
            raise ExchangeNotFoundError(exchange_name=exchange_name)

        self._symbol_maps = [None, None]

        self.name = exchange_name

        self.quote_currency = quote_currency
        self.transactions = defaultdict(list)

        self.num_candles_limit = 2000
        self.max_requests_per_minute = 60
        self.low_balance_threshold = 0.1
        self.request_cpt = dict()
        self._common_symbols = dict()

        # Operations with retry features
        self.attempts = dict(
            missing_order_attempts=5,
            retry_sleeptime=5,
        )

        self.bundle = ExchangeBundle(self.name)
        self.markets = None
        self._is_init = False
Пример #3
0
    def __init__(self, exchange_name, key, secret, base_currency):
        log.debug('finding {} in CCXT exchanges:\n{}'.format(
            exchange_name, ccxt.exchanges))
        try:
            # Making instantiation as explicit as possible for code tracking.
            if exchange_name in SUPPORTED_EXCHANGES:
                exchange_attr = SUPPORTED_EXCHANGES[exchange_name]

            else:
                exchange_attr = getattr(ccxt, exchange_name)

            self.api = exchange_attr({
                'apiKey': key,
                'secret': secret,
            })

        except Exception:
            raise ExchangeNotFoundError(exchange_name=exchange_name)

        self._symbol_maps = [None, None]

        try:
            markets_symbols = self.api.load_markets()
            log.debug('the markets:\n{}'.format(markets_symbols))

        except ExchangeNotAvailable as e:
            raise ExchangeRequestError(error=e)

        self.name = exchange_name

        self.markets = self.api.fetch_markets()
        self.load_assets()

        self.base_currency = base_currency
        self.transactions = defaultdict(list)

        self.num_candles_limit = 2000
        self.max_requests_per_minute = 60
        self.request_cpt = dict()

        self.bundle = ExchangeBundle(self.name)
Пример #4
0
def _run(handle_data, initialize, before_trading_start, analyze, algofile,
         algotext, defines, data_frequency, capital_base, data, bundle,
         bundle_timestamp, start, end, output, print_algo, local_namespace,
         environ, live, exchange, algo_namespace, base_currency, live_graph):
    """Run a backtest for the given algorithm.

    This is shared between the cli and :func:`catalyst.run_algo`.
    """
    if algotext is not None:
        if local_namespace:
            ip = get_ipython()  # noqa
            namespace = ip.user_ns
        else:
            namespace = {}

        for assign in defines:
            try:
                name, value = assign.split('=', 2)
            except ValueError:
                raise ValueError(
                    'invalid define %r, should be of the form name=value' %
                    assign, )
            try:
                # evaluate in the same namespace so names may refer to
                # eachother
                namespace[name] = eval(value, namespace)
            except Exception as e:
                raise ValueError(
                    'failed to execute definition for name %r: %s' %
                    (name, e), )
    elif defines:
        raise _RunAlgoError(
            'cannot pass define without `algotext`',
            "cannot pass '-D' / '--define' without '-t' / '--algotext'",
        )
    else:
        namespace = {}
        if algofile is not None:
            algotext = algofile.read()

    if print_algo:
        if PYGMENTS:
            highlight(
                algotext,
                PythonLexer(),
                TerminalFormatter(),
                outfile=sys.stdout,
            )
        else:
            click.echo(algotext)

    mode = 'live' if live else 'backtest'
    log.info('running algo in {mode} mode'.format(mode=mode))

    exchange_name = exchange
    if exchange_name is None:
        raise ValueError('Please specify at least one exchange.')

    exchange_list = [x.strip().lower() for x in exchange.split(',')]

    exchanges = dict()
    for exchange_name in exchange_list:

        # Looking for the portfolio from the cache first
        portfolio = get_algo_object(algo_name=algo_namespace,
                                    key='portfolio_{}'.format(exchange_name),
                                    environ=environ)

        if portfolio is None:
            portfolio = ExchangePortfolio(start_date=pd.Timestamp.utcnow())

        # This corresponds to the json file containing api token info
        exchange_auth = get_exchange_auth(exchange_name)

        if live and (exchange_auth['key'] == ''
                     or exchange_auth['secret'] == ''):
            raise ExchangeAuthEmpty(exchange=exchange_name.title(),
                                    filename=os.path.join(
                                        get_exchange_folder(
                                            exchange_name, environ),
                                        'auth.json'))

        if exchange_name == 'bitfinex':
            exchanges[exchange_name] = Bitfinex(key=exchange_auth['key'],
                                                secret=exchange_auth['secret'],
                                                base_currency=base_currency,
                                                portfolio=portfolio)
        elif exchange_name == 'bittrex':
            exchanges[exchange_name] = Bittrex(key=exchange_auth['key'],
                                               secret=exchange_auth['secret'],
                                               base_currency=base_currency,
                                               portfolio=portfolio)
        elif exchange_name == 'poloniex':
            exchanges[exchange_name] = Poloniex(key=exchange_auth['key'],
                                                secret=exchange_auth['secret'],
                                                base_currency=base_currency,
                                                portfolio=portfolio)
        else:
            raise ExchangeNotFoundError(exchange_name=exchange_name)

    open_calendar = get_calendar('OPEN')

    env = TradingEnvironment(
        load=partial(load_crypto_market_data,
                     environ=environ,
                     start_dt=start,
                     end_dt=end),
        environ=environ,
        exchange_tz='UTC',
        asset_db_path=None  # We don't need an asset db, we have exchanges
    )
    env.asset_finder = AssetFinderExchange()
    choose_loader = None  # TODO: use the DataPortal for in the algorithm class for this

    if live:
        start = pd.Timestamp.utcnow()

        # TODO: fix the end data.
        end = start + timedelta(hours=8760)

        data = DataPortalExchangeLive(exchanges=exchanges,
                                      asset_finder=env.asset_finder,
                                      trading_calendar=open_calendar,
                                      first_trading_day=pd.to_datetime(
                                          'today', utc=True))

        def fetch_capital_base(exchange, attempt_index=0):
            """
            Fetch the base currency amount required to bootstrap
            the algorithm against the exchange.

            The algorithm cannot continue without this value.

            :param exchange: the targeted exchange
            :param attempt_index:
            :return capital_base: the amount of base currency available for
            trading
            """
            try:
                log.debug('retrieving capital base in {} to bootstrap '
                          'exchange {}'.format(base_currency, exchange_name))
                balances = exchange.get_balances()
            except ExchangeRequestError as e:
                if attempt_index < 20:
                    log.warn('could not retrieve balances on {}: {}'.format(
                        exchange.name, e))
                    sleep(5)
                    return fetch_capital_base(exchange, attempt_index + 1)

                else:
                    raise ExchangeRequestErrorTooManyAttempts(
                        attempts=attempt_index, error=e)

            if base_currency in balances:
                return balances[base_currency]
            else:
                raise BaseCurrencyNotFoundError(base_currency=base_currency,
                                                exchange=exchange_name)

        capital_base = 0
        for exchange_name in exchanges:
            exchange = exchanges[exchange_name]
            capital_base += fetch_capital_base(exchange)

        sim_params = create_simulation_parameters(start=start,
                                                  end=end,
                                                  capital_base=capital_base,
                                                  emission_rate='minute',
                                                  data_frequency='minute')

        # TODO: use the constructor instead
        sim_params._arena = 'live'

        algorithm_class = partial(ExchangeTradingAlgorithmLive,
                                  exchanges=exchanges,
                                  algo_namespace=algo_namespace,
                                  live_graph=live_graph)
    else:
        # Removed the existing Poloniex fork to keep things simple
        # We can add back the complexity if required.

        # I don't think that we should have arbitrary price data bundles
        # Instead, we should center this data around exchanges.
        # We still need to support bundles for other misc data, but we
        # can handle this later.

        data = DataPortalExchangeBacktest(exchanges=exchanges,
                                          asset_finder=None,
                                          trading_calendar=open_calendar,
                                          first_trading_day=start,
                                          last_available_session=end)

        sim_params = create_simulation_parameters(
            start=start,
            end=end,
            capital_base=capital_base,
            data_frequency=data_frequency,
            emission_rate=data_frequency,
        )

        algorithm_class = partial(ExchangeTradingAlgorithmBacktest,
                                  exchanges=exchanges)

    perf = algorithm_class(
        namespace=namespace,
        env=env,
        get_pipeline_loader=choose_loader,
        sim_params=sim_params,
        **{
            'initialize': initialize,
            'handle_data': handle_data,
            'before_trading_start': before_trading_start,
            'analyze': analyze,
        } if algotext is None else {
            'algo_filename': getattr(algofile, 'name', '<algorithm>'),
            'script': algotext,
        }).run(
            data,
            overwrite_sim_params=False,
        )

    if output == '-':
        click.echo(str(perf))
    elif output != os.devnull:  # make the catalyst magic not write any data
        perf.to_pickle(output)

    return perf