diff --git a/catalyst/exchange/ccxt/ccxt_exchange.py b/catalyst/exchange/ccxt/ccxt_exchange.py index 875661e9..0c8eb808 100644 --- a/catalyst/exchange/ccxt/ccxt_exchange.py +++ b/catalyst/exchange/ccxt/ccxt_exchange.py @@ -190,6 +190,9 @@ class CCXT(Exchange): if data_frequency == 'minute' and not freq.endswith('T'): continue + elif data_frequency == 'hourly' and not freq.endswith('D'): + continue + elif data_frequency == 'daily' and not freq.endswith('D'): continue diff --git a/catalyst/exchange/exchange.py b/catalyst/exchange/exchange.py index 73593c6d..e5bea0fe 100644 --- a/catalyst/exchange/exchange.py +++ b/catalyst/exchange/exchange.py @@ -13,7 +13,6 @@ from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \ PricingDataNotLoadedError, \ NoDataAvailableOnExchange, NoValueForField, \ NoCandlesReceivedFromExchange, \ - InvalidHistoryFrequencyAlias, \ TickerNotFoundError, NotEnoughCashError from catalyst.exchange.utils.datetime_utils import get_delta, \ get_periods_range, \ @@ -509,10 +508,6 @@ class Exchange: frequency, data_frequency, supported_freqs=['T', 'D', 'H'] ) - if unit == 'H': - raise InvalidHistoryFrequencyAlias( - freq=frequency) - # we want to avoid receiving empty candles # so we request more than needed # TODO: consider defining a const per asset @@ -616,7 +611,7 @@ class Exchange: # TODO: this function needs some work, # we're currently using it just for benchmark data freq, candle_size, unit, data_frequency = get_frequency( - frequency, data_frequency + frequency, data_frequency, supported_freqs=['T', 'D'] ) adj_bar_count = candle_size * bar_count try: diff --git a/catalyst/exchange/exchange_data_portal.py b/catalyst/exchange/exchange_data_portal.py index c6523326..d2dab705 100644 --- a/catalyst/exchange/exchange_data_portal.py +++ b/catalyst/exchange/exchange_data_portal.py @@ -296,7 +296,7 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase): bundle = self.exchange_bundles[exchange_name] # type: ExchangeBundle freq, candle_size, unit, adj_data_frequency = get_frequency( - frequency, data_frequency + frequency, data_frequency, supported_freqs=['T', 'D'] ) adj_bar_count = candle_size * bar_count @@ -312,7 +312,7 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase): algo_end_dt=self._last_available_session, ) - start_dt = get_start_dt(end_dt, adj_bar_count, data_frequency) + start_dt = get_start_dt(end_dt, adj_bar_count, adj_data_frequency) df = resample_history_df(pd.DataFrame(series), freq, field, start_dt) return df diff --git a/catalyst/exchange/utils/datetime_utils.py b/catalyst/exchange/utils/datetime_utils.py index b5a03c49..38269947 100644 --- a/catalyst/exchange/utils/datetime_utils.py +++ b/catalyst/exchange/utils/datetime_utils.py @@ -249,9 +249,12 @@ def get_year_start_end(dt, first_day=None, last_day=None): return year_start, year_end -def get_frequency(freq, data_frequency=None, supported_freqs=['D', 'T']): +def get_frequency(freq, data_frequency=None, supported_freqs=['D', 'H', 'T']): """ - Get the frequency parameters. + Takes an arbitrary candle size (e.g. 15T) and converts to the lowest + common denominator supported by the data bundles (e.g. 1T). The data + bundles only support 1T and 1D frequencies. If another frequency + is requested, Catalyst must request the underlying data and resample. Notes ----- @@ -306,14 +309,14 @@ def get_frequency(freq, data_frequency=None, supported_freqs=['D', 'T']): data_frequency = 'minute' elif unit.lower() == 'h': + data_frequency = 'minute' + if 'H' in supported_freqs: unit = 'H' alias = '{}H'.format(candle_size) - else: candle_size = candle_size * 60 alias = '{}T'.format(candle_size) - data_frequency = 'minute' else: raise InvalidHistoryFrequencyAlias(freq=freq) diff --git a/catalyst/marketplace/utils/auth_utils.py b/catalyst/marketplace/utils/auth_utils.py index ab3c668d..f4d893a8 100644 --- a/catalyst/marketplace/utils/auth_utils.py +++ b/catalyst/marketplace/utils/auth_utils.py @@ -1,5 +1,6 @@ import hashlib import hmac +import webbrowser import requests import time @@ -45,10 +46,17 @@ def get_key_secret(pubAddr, wallet='mew'): nonce = '0x{}'.format(d['nonce']) if wallet == 'mew': + url = 'https://www.myetherwallet.com/signmsg.html' + print('\nObtaining a key/secret pair to streamline all future ' 'requests with the authentication server.\n' - 'Visit https://www.myetherwallet.com/signmsg.html and sign the ' - 'following message:\n{}'.format(nonce)) + 'Visit {url} and sign the ' + 'following message:\n{nonce}'.format( + url=url, + nonce=nonce)) + + webbrowser.open_new(url) + signature = input('Copy and Paste the "sig" field from ' 'the signature here (without the double quotes, ' 'only the HEX value):\n') diff --git a/catalyst/support/issue_227.py b/catalyst/support/issue_227.py new file mode 100644 index 00000000..09392f81 --- /dev/null +++ b/catalyst/support/issue_227.py @@ -0,0 +1,49 @@ +import pytz +from datetime import datetime +from catalyst.api import symbol +from catalyst.utils.run_algo import run_algorithm + +coin = 'btc' +base_currency = 'usd' +n_candles = 5 + + +def initialize(context): + context.symbol = symbol('%s_%s' % (coin, base_currency)) + + +def handle_data_polo_partial_candles(context, data): + history = data.history(symbol('btc_usdt'), ['volume'], + bar_count=10, + frequency='4H') + print('\nnow: %s\n%s' % (data.current_dt, history)) + if not hasattr(context, 'i'): + context.i = 0 + context.i += 1 + if context.i > 5: + raise Exception('stop') + + +live = False + +if live: + run_algorithm(initialize=lambda ctx: True, + handle_data=handle_data_polo_partial_candles, + exchange_name='poloniex', + base_currency='usdt', + algo_namespace='ns', + live=True, + data_frequency='minute', + capital_base=3000) +else: + run_algorithm(initialize=lambda ctx: True, + handle_data=handle_data_polo_partial_candles, + exchange_name='poloniex', + base_currency='usdt', + algo_namespace='ns', + live=False, + data_frequency='minute', + capital_base=3000, + start=datetime(2018, 2, 2, 0, 0, 0, 0, pytz.utc), + end=datetime(2018, 2, 20, 0, 0, 0, 0, pytz.utc) + ) diff --git a/catalyst/support/issue_274.py b/catalyst/support/issue_274.py new file mode 100644 index 00000000..74a497d9 --- /dev/null +++ b/catalyst/support/issue_274.py @@ -0,0 +1,35 @@ +import pytz +from datetime import datetime +from catalyst.api import symbol +from catalyst.utils.run_algo import run_algorithm + +coin = 'btc' +base_currency = 'usd' + + +def initialize(context): + context.symbol = symbol('%s_%s' % (coin, base_currency)) + + +def handle_data_polo_partial_candles(context, data): + history = data.history(symbol('btc_usdt'), ['volume'], + bar_count=10, + frequency='1D') + print('\nnow: %s\n%s' % (data.current_dt, history)) + if not hasattr(context, 'i'): + context.i = 0 + context.i += 1 + if context.i > 5: + raise Exception('stop') + + +run_algorithm(initialize=lambda ctx: True, + handle_data=handle_data_polo_partial_candles, + exchange_name='poloniex', + base_currency='usdt', + algo_namespace='ns', + live=False, + data_frequency='minute', + capital_base=3000, + start=datetime(2018, 2, 2, 0, 0, 0, 0, pytz.utc), + end=datetime(2018, 2, 20, 0, 0, 0, 0, pytz.utc)) diff --git a/docs/source/install.rst b/docs/source/install.rst index e4ae99dd..87f3c64c 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -143,7 +143,7 @@ with the following steps: .. code-block:: bash - conda create --name catalyst python=2.7 scipy zlib + conda create --name catalyst python=3.6 scipy zlib 3. Activate the environment: