diff --git a/catalyst/examples/simple_loop.py b/catalyst/examples/simple_loop.py index 52400485..9f02e5ac 100644 --- a/catalyst/examples/simple_loop.py +++ b/catalyst/examples/simple_loop.py @@ -1,13 +1,13 @@ import talib - import pandas as pd + from catalyst import run_algorithm from catalyst.api import symbol def initialize(context): print('initializing') - context.asset = symbol('burst_btc') + context.asset = symbol('eth_btc') def handle_data(context, data): @@ -16,22 +16,22 @@ def handle_data(context, data): price = data.current(context.asset, 'close') print('got price {price}'.format(price=price)) - prices = data.history( - context.asset, - fields='price', - bar_count=15, - frequency='1d' - ) - rsi = talib.RSI(prices.values, timeperiod=14)[-1] - print('got rsi: {}'.format(rsi)) + # prices = data.history( + # context.asset, + # fields='price', + # bar_count=20, + # frequency='1T' + # ) + # rsi = talib.RSI(prices.values, timeperiod=14)[-1] + # print('got rsi: {}'.format(rsi)) pass run_algorithm( capital_base=250, - start=pd.to_datetime('2017-08-01', utc=True), - end=pd.to_datetime('2017-9-30', utc=True), - data_frequency='minute', + start=pd.to_datetime('2017-1-1', utc=True), + end=pd.to_datetime('2017-10-22', utc=True), + data_frequency='daily', initialize=initialize, handle_data=handle_data, analyze=None, @@ -43,7 +43,7 @@ run_algorithm( # initialize=initialize, # handle_data=handle_data, # analyze=None, -# exchange_name='bitfinex', +# exchange_name='bittrex', # live=True, # algo_namespace='simple_loop', # base_currency='eth', diff --git a/catalyst/exchange/bitfinex/bitfinex.py b/catalyst/exchange/bitfinex/bitfinex.py index ea243a1f..4c878e04 100644 --- a/catalyst/exchange/bitfinex/bitfinex.py +++ b/catalyst/exchange/bitfinex/bitfinex.py @@ -240,7 +240,7 @@ class Bitfinex(Exchange): # TODO: fetch account data and keep in cache return None - def get_candles(self, data_frequency, assets, bar_count=None, + def get_candles(self, freq, assets, bar_count=None, start_dt=None, end_dt=None): """ Retrieve OHLVC candles from Bitfinex @@ -259,39 +259,36 @@ class Bitfinex(Exchange): 'retrieving {bars} {freq} candles on {exchange} from ' '{end_dt} for markets {symbols}, '.format( bars=bar_count, - freq=data_frequency, + freq=freq, exchange=self.name, end_dt=end_dt, symbols=get_symbols_string(assets) ) ) - freq_match = re.match(r'([0-9].*)(m|h|d)', data_frequency, re.M | re.I) + allowed_frequencies = ['1T', '5T', '15T', '30T', '60T', '180T', + '360T', '720T', '1D', '7D', '14D', '30D'] + if freq not in allowed_frequencies: + raise InvalidHistoryFrequencyError(frequency=freq) + + freq_match = re.match(r'([0-9].*)(T|H|D)', freq, re.M | re.I) if freq_match: number = int(freq_match.group(1)) unit = freq_match.group(2) - if unit == 'd': - converted_unit = 'D' + if unit == 'T': + if number in [60, 180, 360, 720]: + number = number / 60 + converted_unit = 'h' + else: + converted_unit = 'm' else: converted_unit = unit frequency = '{}{}'.format(number, converted_unit) - allowed_frequencies = ['1m', '5m', '15m', '30m', '1h', '3h', '6h', - '12h', '1D', '7D', '14D', '1M'] - if frequency not in allowed_frequencies: - raise InvalidHistoryFrequencyError( - frequency=data_frequency - ) - elif data_frequency == 'minute': - frequency = '1m' - elif data_frequency == 'daily': - frequency = '1D' else: - raise InvalidHistoryFrequencyError( - frequency=data_frequency - ) + raise InvalidHistoryFrequencyError(frequency=freq) # Making sure that assets are iterable asset_list = [assets] if isinstance(assets, TradingPair) else assets diff --git a/catalyst/exchange/bittrex/bittrex.py b/catalyst/exchange/bittrex/bittrex.py index 1bbfc68b..6c490a46 100644 --- a/catalyst/exchange/bittrex/bittrex.py +++ b/catalyst/exchange/bittrex/bittrex.py @@ -210,14 +210,14 @@ class Bittrex(Exchange): error=status['message'] ) - def get_candles(self, data_frequency, assets, bar_count=None, + def get_candles(self, freq, assets, bar_count=None, start_dt=None, end_dt=None): """ Supported Intervals ------------------- day, oneMin, fiveMin, thirtyMin, hour - :param data_frequency: + :param freq: :param assets: :param bar_count: :param start_dt @@ -233,28 +233,25 @@ class Bittrex(Exchange): 'retrieving {bars} {freq} candles on {exchange} from ' '{end_dt} for markets {symbols}, '.format( bars=bar_count, - freq=data_frequency, + freq=freq, exchange=self.name, end_dt=end_dt, symbols=get_symbols_string(assets) ) ) - data_frequency = data_frequency.lower() - if data_frequency == 'minute' or data_frequency == '1m': + if freq == '1T': frequency = 'oneMin' - elif data_frequency == '5m': + elif freq == '5T': frequency = 'fiveMin' - elif data_frequency == '30m': + elif freq == '30T': frequency = 'thirtyMin' - elif data_frequency == '1h': + elif freq == '60T': frequency = 'hour' - elif data_frequency == 'daily' or data_frequency == '1d': + elif freq == '1D': frequency = 'day' else: - raise InvalidHistoryFrequencyError( - frequency=data_frequency - ) + raise InvalidHistoryFrequencyError(frequency=freq) # Making sure that assets are iterable asset_list = [assets] if isinstance(assets, TradingPair) else assets @@ -297,6 +294,7 @@ class Bittrex(Exchange): if bar_count is None: ohlc_map[asset] = ohlc_from_candle(ordered_candles[0]) else: + # TODO: optimize ohlc_bars = [] for candle in ordered_candles[:bar_count]: ohlc = ohlc_from_candle(candle) diff --git a/catalyst/exchange/bundle_utils.py b/catalyst/exchange/bundle_utils.py index 9a0eb3c2..9d357e23 100644 --- a/catalyst/exchange/bundle_utils.py +++ b/catalyst/exchange/bundle_utils.py @@ -71,25 +71,18 @@ def get_delta(periods, data_frequency): if data_frequency == 'minute' else timedelta(days=periods) -def get_periods_range(start_dt, end_dt, data_frequency): - freq = 'T' if data_frequency == 'minute' else 'D' +def get_periods_range(start_dt, end_dt, freq): + if freq == 'minute': + freq = 'T' + + elif freq == 'daily': + freq = 'D' return pd.date_range(start_dt, end_dt, freq=freq) -def get_periods(start_dt, end_dt, data_frequency): - delta = end_dt - start_dt - - if data_frequency == 'minute': - delta_periods = delta.total_seconds() / 60 - - elif data_frequency == 'daily': - delta_periods = delta.total_seconds() / 60 / 60 / 24 - - else: - raise ValueError('frequency not supported') - - return int(delta_periods) +def get_periods(start_dt, end_dt, freq): + return len(get_periods_range(start_dt, end_dt, freq)) def get_start_dt(end_dt, bar_count, data_frequency): diff --git a/catalyst/exchange/exchange.py b/catalyst/exchange/exchange.py index 3640bbe3..91fc6733 100644 --- a/catalyst/exchange/exchange.py +++ b/catalyst/exchange/exchange.py @@ -12,11 +12,12 @@ from logbook import Logger from catalyst.constants import LOG_LEVEL from catalyst.data.data_portal import BASE_FIELDS from catalyst.exchange.bundle_utils import get_start_dt, \ - get_delta, get_periods + get_delta, get_periods, get_periods_range from catalyst.exchange.exchange_bundle import ExchangeBundle from catalyst.exchange.exchange_errors import MismatchingBaseCurrencies, \ InvalidOrderStyle, BaseCurrencyNotFoundError, SymbolNotFoundOnExchange, \ - InvalidHistoryFrequencyError, PricingDataNotLoadedError + InvalidHistoryFrequencyError, PricingDataNotLoadedError, \ + NoDataAvailableOnExchange from catalyst.exchange.exchange_execution import ExchangeStopLimitOrder, \ ExchangeLimitOrder, ExchangeStopOrder from catalyst.exchange.exchange_portfolio import ExchangePortfolio @@ -24,6 +25,7 @@ from catalyst.exchange.exchange_utils import get_exchange_symbols, \ get_frequency, resample_history_df from catalyst.finance.order import ORDER_STATUS from catalyst.finance.transaction import Transaction +from catalyst.utils.deprecate import deprecated log = Logger('Exchange', level=LOG_LEVEL) @@ -71,6 +73,15 @@ class Exchange: def time_skew(self): pass + def is_open(self, dt): + """ + Is the exchange open? + :param dt: + :return: + """ + # TODO: implement for each exchange. + return True + def ask_request(self): """ Asks permission to issue a request to the exchange. @@ -364,7 +375,8 @@ class Exchange: ) ) - ohlc = self.get_candles(data_frequency, asset) + freq = '1T' if data_frequency == 'minute' else '1D' + ohlc = self.get_candles(freq, asset) if field not in ohlc: raise KeyError('Invalid column: %s' % field) @@ -388,17 +400,84 @@ class Exchange: dates = [candle['last_traded'] for candle in candles] values = [candle[field] for candle in candles] - - periods = self.bundle.get_calendar_periods_range( - start_dt, end_dt, data_frequency - ) series = pd.Series(values, index=dates) + periods = get_periods_range( + start_dt, end_dt, data_frequency + ) # TODO: ensure that this working as expected, if not use fillna - series.reindex(periods, method='ffill', fill_value=previous_value) + series = series.reindex( + periods, + method='ffill', + fill_value=previous_value, + ) return series + @deprecated + def get_history_window_direct(self, + assets, + end_dt, + bar_count, + frequency, + field, + data_frequency=None, + ffill=True): + + """ + Public API method that returns a dataframe containing the requested + history window. Data is fully adjusted. + + Parameters + ---------- + assets : list of catalyst.data.Asset objects + The assets whose data is desired. + + end_dt: not applicable to cryptocurrencies + + bar_count: int + The number of bars desired. + + frequency: string + "1d" or "1m" + + field: string + The desired field of the asset. + + data_frequency: string + The frequency of the data to query; i.e. whether the data is + 'daily' or 'minute' bars. + + # TODO: fill how? + ffill: boolean + Forward-fill missing values. Only has effect if field + is 'price'. + + Returns + ------- + A dataframe containing the requested data. + """ + start_dt = get_start_dt(end_dt, bar_count, data_frequency) + + # The get_history method supports multiple asset + candles = self.get_candles( + data_frequency=frequency, + assets=assets, + bar_count=bar_count, + start_dt=start_dt, + end_dt=end_dt + ) + candle_series = self.get_series_from_candles( + candles=candles, + start_dt=start_dt, + end_dt=end_dt, + data_frequency=frequency, + field=field, + ) + + df = pd.DataFrame(candle_series) + return df + def get_history_window(self, assets, end_dt, @@ -442,7 +521,7 @@ class Exchange: A dataframe containing the requested data. """ - candle_size, unit, data_frequency = get_frequency( + freq, candle_size, unit, data_frequency = get_frequency( frequency, data_frequency ) adj_bar_count = candle_size * bar_count @@ -454,7 +533,7 @@ class Exchange: field=field, data_frequency=data_frequency ) - except PricingDataNotLoadedError: + except (PricingDataNotLoadedError, NoDataAvailableOnExchange): series = dict() for asset in assets: @@ -467,12 +546,14 @@ class Exchange: series[asset].index[-1] + get_delta(1, data_frequency) \ if asset in series else start_dt - trailing_bar_count = \ - get_periods(trailing_dt, end_dt, data_frequency) - # The get_history method supports multiple asset + # Use the original frequency to let each api optimize + # the size of result sets + trailing_bar_count = get_periods( + trailing_dt, end_dt, freq + ) candles = self.get_candles( - data_frequency=data_frequency, + freq=freq, assets=asset, bar_count=trailing_bar_count, start_dt=start_dt, @@ -482,6 +563,8 @@ class Exchange: last_value = series[asset].iloc(0) if asset in series \ else np.nan + # Create a series with the common data_frequency, ffill + # missing values candle_series = self.get_series_from_candles( candles=candles, start_dt=trailing_dt, @@ -497,7 +580,9 @@ class Exchange: else: series[asset] = candle_series - df = resample_history_df(pd.DataFrame(series), candle_size, field) + df = resample_history_df(pd.DataFrame(series), freq, field) + # TODO: consider this more carefully + df.dropna(inplace=True) return df @@ -708,13 +793,14 @@ class Exchange: pass @abstractmethod - def get_candles(self, data_frequency, assets, bar_count=None, + def get_candles(self, freq, assets, bar_count=None, start_dt=None, end_dt=None): """ Retrieve OHLCV candles for the given assets - :param data_frequency: - The candle frequency: minute or daily + :param freq: + The frequency alias per convention: + http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases :param assets: list[TradingPair] The targeted assets. :param bar_count: diff --git a/catalyst/exchange/exchange_data_portal.py b/catalyst/exchange/exchange_data_portal.py index 8d2cf997..f8d93288 100644 --- a/catalyst/exchange/exchange_data_portal.py +++ b/catalyst/exchange/exchange_data_portal.py @@ -303,7 +303,7 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase): """ bundle = self.exchange_bundles[exchange.name] # type: ExchangeBundle - candle_size, unit, data_frequency = get_frequency( + freq, candle_size, unit, data_frequency = get_frequency( frequency, data_frequency ) adj_bar_count = candle_size * bar_count @@ -317,7 +317,7 @@ class DataPortalExchangeBacktest(DataPortalExchangeBase): algo_end_dt=self._last_available_session, ) - df = resample_history_df(pd.DataFrame(series), candle_size, field) + df = resample_history_df(pd.DataFrame(series), freq, field) return df def get_exchange_spot_value(self, diff --git a/catalyst/exchange/exchange_errors.py b/catalyst/exchange/exchange_errors.py index 6cd55014..00e53395 100644 --- a/catalyst/exchange/exchange_errors.py +++ b/catalyst/exchange/exchange_errors.py @@ -86,6 +86,14 @@ class AlgoPickleNotFound(ZiplineError): ).strip() +class InvalidHistoryFrequencyAlias(ZiplineError): + msg = ( + 'Invalid frequency alias {freq}. Valid suffixes are M (minute) ' + 'and D (day). For example, these aliases would be valid ' + '1M, 5M, 1D.' + ).strip() + + class InvalidHistoryFrequencyError(ZiplineError): msg = ( 'Frequency {frequency} not supported by the exchange.' diff --git a/catalyst/exchange/exchange_utils.py b/catalyst/exchange/exchange_utils.py index 3bd35223..812c7776 100644 --- a/catalyst/exchange/exchange_utils.py +++ b/catalyst/exchange/exchange_utils.py @@ -10,7 +10,7 @@ from datetime import date, datetime import pandas as pd from catalyst.exchange.exchange_errors import ExchangeSymbolsNotFound, \ - InvalidHistoryFrequencyError + InvalidHistoryFrequencyError, InvalidHistoryFrequencyAlias from catalyst.utils.paths import data_root, ensure_directory, \ last_modified_time @@ -313,50 +313,61 @@ def get_common_assets(exchanges): def get_frequency(freq, data_frequency): - if freq == 'daily': - freq = '1d' - elif freq == 'minute': - freq = '1m' + if freq == 'minute': + unit = 'T' + candle_size = 1 - freq_match = re.match(r'([0-9].*)(m|M|d|D)', freq, re.M | re.I) - if freq_match: - candle_size = int(freq_match.group(1)) - unit = freq_match.group(2) + elif freq == 'daily': + unit = 'D' + candle_size = 1 else: - raise InvalidHistoryFrequencyError(freq) + freq_match = re.match(r'([0-9].*)?(m|M|d|D|h|H|T)', freq, re.M | re.I) + if freq_match: + candle_size = int(freq_match.group(1)) if freq_match.group(1) \ + else 1 + unit = freq_match.group(2) + + else: + raise InvalidHistoryFrequencyError(frequency=freq) if unit.lower() == 'd': + alias = '{}D'.format(candle_size) + if data_frequency == 'minute': data_frequency = 'daily' - elif unit.lower() == 'm': + elif unit.lower() == 'm' or unit == 'T': + alias = '{}T'.format(candle_size) + if data_frequency == 'daily': data_frequency = 'minute' - else: - raise InvalidHistoryFrequencyError(freq) - - return candle_size, unit, data_frequency - - -def resample_history_df(df, candle_size, field): - if candle_size > 1: - if field == 'open': - agg = 'first' - elif field == 'high': - agg = 'max' - elif field == 'low': - agg = 'min' - elif field == 'close': - agg = 'last' - elif field == 'volume': - agg = 'sum' - else: - raise ValueError('Invalid field.') - - # TODO: pad with nan? - return df.resample('{}T'.format(candle_size)).agg(agg) + # elif unit.lower() == 'h': + # candle_size = candle_size * 60 + # + # alias = '{}T'.format(candle_size) + # if data_frequency == 'daily': + # data_frequency = 'minute' else: - return df + raise InvalidHistoryFrequencyAlias(freq=freq) + + return alias, candle_size, unit, data_frequency + + +def resample_history_df(df, freq, field): + if field == 'open': + agg = 'first' + elif field == 'high': + agg = 'max' + elif field == 'low': + agg = 'min' + elif field == 'close': + agg = 'last' + elif field == 'volume': + agg = 'sum' + else: + raise ValueError('Invalid field.') + + return df.resample(freq).agg(agg) diff --git a/catalyst/exchange/poloniex/poloniex.py b/catalyst/exchange/poloniex/poloniex.py index 468463b0..65c397c7 100644 --- a/catalyst/exchange/poloniex/poloniex.py +++ b/catalyst/exchange/poloniex/poloniex.py @@ -1,3 +1,4 @@ +import calendar import json import json import time @@ -171,12 +172,12 @@ class Poloniex(Exchange): # TODO: fetch account data and keep in cache return None - def get_candles(self, data_frequency, assets, bar_count=None, + def get_candles(self, freq, assets, bar_count=None, start_dt=None, end_dt=None): """ Retrieve OHLVC candles from Poloniex - :param data_frequency: + :param freq: :param assets: :param bar_count: :return: @@ -193,31 +194,33 @@ class Poloniex(Exchange): 'retrieving {bars} {freq} candles on {exchange} from ' '{end_dt} for markets {symbols}, '.format( bars=bar_count, - freq=data_frequency, + freq=freq, exchange=self.name, end_dt=end_dt, symbols=get_symbols_string(assets) ) ) - if data_frequency == '5m': + if freq == '1T' and (bar_count == 1 or bar_count is None): + # TODO: use the order book instead + # We use the 5m to fetch the last bar frequency = 300 - elif data_frequency == '15m': + elif freq == '5T': + frequency = 300 + elif freq == '15T': frequency = 900 - elif data_frequency == '30m': + elif freq == '30T': frequency = 1800 - elif data_frequency == '2h': + elif freq == '120T': frequency = 7200 - elif data_frequency == '4h': + elif freq == '240T': frequency = 14400 - elif data_frequency == '1D' or data_frequency == 'daily': + elif freq == '1D': frequency = 86400 else: # Poloniex does not offer 1m data candles # It is likely to error out there frequently - raise InvalidHistoryFrequencyError( - frequency=data_frequency - ) + raise InvalidHistoryFrequencyError(frequency=freq) # Making sure that assets are iterable asset_list = [assets] if isinstance(assets, TradingPair) else assets @@ -225,15 +228,18 @@ class Poloniex(Exchange): for asset in asset_list: - end = int(time.mktime(end_dt.timetuple())) + # TODO: what's wrong with this? + # end = int(time.mktime(end_dt.timetuple())) + end = int(time.time()) if bar_count is None: start = end - 2 * frequency else: start = end - bar_count * frequency try: - response = self.api.returnchartdata(self.get_symbol(asset), - frequency, start, end) + response = self.api.returnchartdata( + self.get_symbol(asset), frequency, start, end + ) except Exception as e: raise ExchangeRequestError(error=e) diff --git a/catalyst/support/rodrigo_1.py b/catalyst/support/rodrigo_1.py new file mode 100644 index 00000000..ec32c617 --- /dev/null +++ b/catalyst/support/rodrigo_1.py @@ -0,0 +1,153 @@ +import pandas as pd +from logbook import Logger, DEBUG + +from catalyst import run_algorithm +from catalyst.api import (schedule_function, order_target_percent, symbol, + date_rules, get_open_orders, cancel_order, record, + set_commission, set_slippage) + +log = Logger('rodrigo_1', level=DEBUG) +""" +The initialize function sets any data or variables that +you'll use in your algorithm. +It's only called once at the beginning of your algorithm. +""" + + +def initialize(context): + # Select asset of interest + context.asset = symbol('BTC_USD') + + # set_commission(TradingPairFeeSchedule(maker_fee=0.5, taker_fee=0.5)) + # set_slippage(TradingPairFixedSlippage(spread=0.5)) + # Set up a rebalance method to run every day + schedule_function(rebalance, date_rule=date_rules.every_day()) + + +""" +Rebalance function scheduled to run once per day. +""" + + +def rebalance(context, data): + # To make market decisions, we're calculating the token's + # moving average for the last 5 days. + + # We get the price history for the last 5 days. + price_history = data.history(context.asset, fields='price', bar_count=5, + frequency='1d') + + # Then we take an average of those 5 days. + average_price = price_history.mean() + + # We also get the coin's current price. + price = data.current(context.asset, 'price') + + # Cancel any outstanding orders + orders = get_open_orders(context.asset) or [] + for order in orders: + cancel_order(order) + + # If our coin is currently listed on a major exchange + if data.can_trade(context.asset): + # If the current price is 1% above the 5-day average price, + # we open a long position. If the current price is below the + # average price, then we want to close our position to 0 shares. + if price > (1.01 * average_price): + # Place the buy order (positive means buy, negative means sell) + order_target_percent(context.asset, .99) + log.info("Buying %s" % (context.asset.symbol)) + elif price < average_price: + # Sell all of our shares by setting the target position to zero + order_target_percent(context.asset, 0) + log.info("Selling %s" % (context.asset.symbol)) + + # Use the record() method to track up to five custom signals. + # Record Apple's current price and the average price over the last + # five days. + cash = context.portfolio.cash + leverage = context.account.leverage + + record(price=price, average_price=average_price, cash=cash, + leverage=leverage) + + +def analyze(context=None, results=None): + import matplotlib.pyplot as plt + + # Plot the portfolio and asset data. + ax1 = plt.subplot(511) + results[['portfolio_value']].plot(ax=ax1) + ax1.set_ylabel('Portfolio Value (USD)') + + ax2 = plt.subplot(512, sharex=ax1) + ax2.set_ylabel('{asset} (USD)'.format(asset=context.asset)) + (results[[ + 'price', + ]]).plot(ax=ax2) + + trans = results.ix[[t != [] for t in results.transactions]] + buys = trans.ix[ + [t[0]['amount'] > 0 for t in trans.transactions] + ] + sells = trans.ix[ + [t[0]['amount'] < 0 for t in trans.transactions] + ] + + ax2.plot( + buys.index, + results.price[buys.index], + '^', + markersize=10, + color='g', + ) + ax2.plot( + sells.index, + results.price[sells.index], + 'v', + markersize=10, + color='r', + ) + + ax3 = plt.subplot(513, sharex=ax1) + results[['leverage']].plot(ax=ax3) + ax3.set_ylabel('Leverage ') + + ax4 = plt.subplot(514, sharex=ax1) + results[['cash']].plot(ax=ax4) + ax4.set_ylabel('Cash (USD)') + + results[[ + 'algorithm', + 'benchmark', + ]] = results[[ + 'algorithm_period_return', + 'benchmark_period_return', + ]] + + ax5 = plt.subplot(515, sharex=ax1) + results[[ + 'algorithm', + 'benchmark', + ]].plot(ax=ax5) + ax5.set_ylabel('Percent Change') + + plt.legend(loc=3) + + # Show the plot. + plt.gcf().set_size_inches(18, 8) + plt.show() + + +run_algorithm( + capital_base=100000, + start=pd.to_datetime('2017-1-1', utc=True), + end=pd.to_datetime('2017-10-22', utc=True), + data_frequency='minute', + initialize=initialize, + handle_data=None, + analyze=analyze, + exchange_name='bitfinex', + algo_namespace='rodrigo_1', + base_currency='usd' +) diff --git a/docs/source/releases.rst b/docs/source/releases.rst index 7e6270db..ee220190 100644 --- a/docs/source/releases.rst +++ b/docs/source/releases.rst @@ -12,6 +12,7 @@ Bug Fixes - Fixed issue with auto-ingestion of minute data - Fixed issue with sell orders in backtesting - Fixed data frequency issues with data.history() in backtesting +- Fixed an issue with can_trade() Build diff --git a/tests/exchange/test_bitfinex.py b/tests/exchange/test_bitfinex.py index 94968e9e..194422f5 100644 --- a/tests/exchange/test_bitfinex.py +++ b/tests/exchange/test_bitfinex.py @@ -8,7 +8,7 @@ from catalyst.finance.execution import (LimitOrder) log = Logger('test_bitfinex') -class TestBitfinexTestCase(BaseExchangeTestCase): +class TestBitfinex(BaseExchangeTestCase): @classmethod def setup(self): log.info('creating bitfinex object') @@ -48,7 +48,7 @@ class TestBitfinexTestCase(BaseExchangeTestCase): def test_get_candles(self): log.info('retrieving candles') ohlcv_neo = self.exchange.get_candles( - data_frequency='1m', + freq='1T', assets=self.exchange.get_asset('neo_btc') ) pass diff --git a/tests/exchange/test_bittrex.py b/tests/exchange/test_bittrex.py index 779c2a08..bf17970d 100644 --- a/tests/exchange/test_bittrex.py +++ b/tests/exchange/test_bittrex.py @@ -52,13 +52,13 @@ class TestBittrex(BaseExchangeTestCase): def test_get_candles(self): log.info('retrieving candles') ohlcv_neo = self.exchange.get_candles( - data_frequency='5m', + freq='5T', assets=self.exchange.get_asset('neo_btc'), bar_count=20, end_dt=pd.to_datetime('2017-10-20', utc=True) ) ohlcv_neo_ubq = self.exchange.get_candles( - data_frequency='1d', + freq='1D', assets=[ self.exchange.get_asset('neo_btc'), self.exchange.get_asset('ubq_btc') diff --git a/tests/exchange/test_bundle.py b/tests/exchange/test_bundle.py index 060592ec..2180dd03 100644 --- a/tests/exchange/test_bundle.py +++ b/tests/exchange/test_bundle.py @@ -126,9 +126,9 @@ class TestExchangeBundle: # data_frequency = 'daily' # include_symbols = 'neo_btc,bch_btc,eth_btc' - exchange_name = 'bittrex' + exchange_name = 'poloniex' data_frequency = 'daily' - include_symbols = 'wings_eth' + include_symbols = 'eth_btc' start = pd.to_datetime('2017-1-1', utc=True) end = pd.to_datetime('2017-10-16', utc=True) @@ -140,10 +140,10 @@ class TestExchangeBundle: log.info('ingesting exchange bundle {}'.format(exchange_name)) exchange_bundle.ingest( data_frequency=data_frequency, - include_symbols=None, + include_symbols=include_symbols, exclude_symbols=None, - start=None, - end=None, + start=start, + end=end, show_progress=True ) @@ -342,7 +342,7 @@ class TestExchangeBundle: assets=assets, end_dt=end_dt, bar_count=bar_count, - data_frequency='minute' + freq='1T' ) start_dt = get_start_dt(end_dt, bar_count, data_frequency) @@ -392,7 +392,7 @@ class TestExchangeBundle: start_dt=start_dt, end_dt=end_dt, bar_count=bar_count, - data_frequency=data_frequency + freq='1T' ) writer = bundle.get_writer(start_dt, end_dt, data_frequency) @@ -437,7 +437,7 @@ class TestExchangeBundle: exchange = get_exchange(exchange_name) bundle = ExchangeBundle(exchange) - asset = exchange.get_asset('xmr_btc') + asset = exchange.get_asset('eth_btc') path = get_bcolz_chunk( exchange_name=exchange.name, diff --git a/tests/exchange/test_poloniex.py b/tests/exchange/test_poloniex.py index 4a883701..b2ad56c3 100644 --- a/tests/exchange/test_poloniex.py +++ b/tests/exchange/test_poloniex.py @@ -8,7 +8,7 @@ from catalyst.exchange.exchange_utils import get_exchange_auth log = Logger('test_poloniex') -class TestPoloniexTestCase(BaseExchangeTestCase): +class TestPoloniex(BaseExchangeTestCase): @classmethod def setup(self): print ('creating poloniex object') @@ -52,11 +52,11 @@ class TestPoloniexTestCase(BaseExchangeTestCase): def test_get_candles(self): log.info('retrieving candles') ohlcv_neo = self.exchange.get_candles( - data_frequency='5m', - assets=self.exchange.get_asset('neos_btc') + freq='5T', + assets=self.exchange.get_asset('eth_btc') ) ohlcv_neo_ubq = self.exchange.get_candles( - data_frequency='5m', + freq='5T', assets=[ self.exchange.get_asset('neos_btc'), self.exchange.get_asset('via_btc')