diff --git a/catalyst/exchange/bitfinex/bitfinex.py b/catalyst/exchange/bitfinex/bitfinex.py index e4e236a1..f1339fd0 100644 --- a/catalyst/exchange/bitfinex/bitfinex.py +++ b/catalyst/exchange/bitfinex/bitfinex.py @@ -301,7 +301,7 @@ class Bitfinex(Exchange): # Making sure that assets are iterable asset_list = [assets] if isinstance(assets, Asset) else assets - ohlc_list = dict() + ohlc_map = dict() for asset in asset_list: symbol = self._get_v2_symbol(asset) url = '{url}/v2/candles/trade:{frequency}:{symbol}'.format( @@ -339,8 +339,7 @@ class Bitfinex(Exchange): volume=np.float64(candle[5]), price=np.float64(candle[2]), last_traded=pd.Timestamp.utcfromtimestamp( - candle[0] / 1000.0), - minute_dt=pd.Timestamp.utcnow().floor('1 min') + candle[0] / 1000.0) ) return ohlc @@ -351,14 +350,14 @@ class Bitfinex(Exchange): ohlc = ohlc_from_candle(candle) ohlc_bars.append(ohlc) - ohlc_list[asset] = ohlc_bars + ohlc_map[asset] = ohlc_bars else: ohlc = ohlc_from_candle(candles) - ohlc_list[asset] = ohlc + ohlc_map[asset] = ohlc - return ohlc_list[assets] \ - if isinstance(assets, Asset) else ohlc_list + return ohlc_map[assets] \ + if isinstance(assets, Asset) else ohlc_map def order(self, asset, amount, limit_price, stop_price, style): """Place an order. diff --git a/catalyst/exchange/bittrex/bittrex.py b/catalyst/exchange/bittrex/bittrex.py index ec5c5f50..f443bb9e 100644 --- a/catalyst/exchange/bittrex/bittrex.py +++ b/catalyst/exchange/bittrex/bittrex.py @@ -1,3 +1,5 @@ +from catalyst.exchange.exchange_errors import InvalidHistoryFrequencyError, \ + ExchangeRequestError from logbook import Logger from six.moves import urllib import json @@ -5,9 +7,12 @@ import pandas as pd from catalyst.exchange.exchange import Exchange from catalyst.exchange.bittrex.bittrex_api import Bittrex_api +from catalyst.assets._assets import Asset log = Logger('Bittrex') +URL2 = 'https://bittrex.com/Api/v2.0' + class Bittrex(Exchange): def __init__(self, key, secret, base_currency, portfolio=None): @@ -90,13 +95,81 @@ class Bittrex(Exchange): log.info('cancel order') pass - def get_candles(self): + def get_candles(self, data_frequency, assets, bar_count=None): + """ + + Supported Intervals + ------------------- + day, oneMin, fiveMin, thirtyMin, hour + :param data_frequency: + :param assets: + :param bar_count: + :return: + """ log.info('retrieving candles') - url = 'https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-NEO&tickInterval=day&_=1499127220008' - with urllib.request.urlopen(url) as url: - data = json.loads(url.read().decode()) - result = data['result'] - pass + if data_frequency == 'minute' or data_frequency == '1m': + frequency = 'oneMin' + elif data_frequency == '5m': + frequency = 'fiveMin' + elif data_frequency == '30m': + frequency = 'thirtyMin' + elif data_frequency == '1h': + frequency = 'hour' + elif data_frequency == 'daily' or data_frequency == '1D': + frequency = 'day' + else: + raise InvalidHistoryFrequencyError( + frequency=data_frequency + ) + + # Making sure that assets are iterable + asset_list = [assets] if isinstance(assets, Asset) else assets + ohlc_map = dict() + for asset in asset_list: + url = '{url}/pub/market/GetTicks?marketName={symbol}' \ + '&tickInterval={frequency}&_=1499127220008'.format( + url=URL2, + symbol=self.get_symbol(asset), + frequency=frequency + ) + + try: + data = json.loads(urllib.request.urlopen(url).read().decode()) + except Exception as e: + raise ExchangeRequestError(error=e) + + if data['message']: + raise ExchangeRequestError( + error='Unable to fetch candles {}'.format(data['message']) + ) + + candles = data['result'] + + def ohlc_from_candle(candle): + ohlc = dict( + open=candle['O'], + high=candle['H'], + low=candle['L'], + close=candle['C'], + volume=candle['V'], + price=candle['C'], + last_traded=pd.to_datetime(candle['T'], utc=True) + ) + return ohlc + + ordered_candles = list(reversed(candles)) + if bar_count is None: + ohlc_map[asset] = ohlc_from_candle(ordered_candles[-1]) + else: + ohlc_bars = [] + for candle in ordered_candles[:bar_count]: + ohlc = ohlc_from_candle(candle) + ohlc_bars.append(ohlc) + + ohlc_map[asset] = ohlc_bars + + return ohlc_map[assets] \ + if isinstance(assets, Asset) else ohlc_map def tickers(self): log.info('retrieving tickers') diff --git a/tests/exchange/test_bittrex.py b/tests/exchange/test_bittrex.py index 9de8882d..edb1c19f 100644 --- a/tests/exchange/test_bittrex.py +++ b/tests/exchange/test_bittrex.py @@ -40,6 +40,18 @@ class BittrexTestCase(BaseExchangeTestCase): def test_get_candles(self): log.info('retrieving candles') + ohlcv_neo = self.exchange.get_candles( + data_frequency='5m', + assets=self.exchange.get_asset('neo_btc') + ) + ohlcv_neo_ubq = self.exchange.get_candles( + data_frequency='5m', + assets=[ + self.exchange.get_asset('neo_btc'), + self.exchange.get_asset('ubq_btc') + ], + bar_count=14 + ) pass def test_tickers(self):