From 4798fc75fb142edd3ef9065b31a7fcb5bf6de943 Mon Sep 17 00:00:00 2001 From: fredfortier Date: Mon, 25 Sep 2017 12:18:22 -0400 Subject: [PATCH] Housekeeping and documentation --- .../buy_low_sell_high_neo_with_interface.py | 4 +- catalyst/exchange/exchange.py | 67 ++++++++++++++----- catalyst/exchange/exchange_bundle.py | 37 +++------- catalyst/utils/run_algo.py | 22 +++--- 4 files changed, 72 insertions(+), 58 deletions(-) diff --git a/catalyst/examples/buy_low_sell_high_neo_with_interface.py b/catalyst/examples/buy_low_sell_high_neo_with_interface.py index 0e215aba..88f22766 100644 --- a/catalyst/examples/buy_low_sell_high_neo_with_interface.py +++ b/catalyst/examples/buy_low_sell_high_neo_with_interface.py @@ -154,8 +154,8 @@ def analyze(context, stats): # exchange_name='bittrex,bitfinex', # live=True, # algo_namespace=algo_namespace, -# base_currency='eth', -# live_graph=True +# base_currency='btc', +# live_graph=False # ) run_algorithm( capital_base=250, diff --git a/catalyst/exchange/exchange.py b/catalyst/exchange/exchange.py index 76319b04..ad4e89b9 100644 --- a/catalyst/exchange/exchange.py +++ b/catalyst/exchange/exchange.py @@ -437,6 +437,7 @@ class Exchange: data_frequency=frequency, assets=assets, bar_count=bar_count, + end_dt=end_dt ) series = dict() @@ -495,18 +496,6 @@ class Exchange: portfolio.portfolio_value = \ portfolio.positions_value + portfolio.cash - @abstractmethod - def get_balances(self): - """ - Retrieve wallet balances for the exchange - :return balances: A dict of currency => available balance - """ - pass - - @abstractmethod - def create_order(self, asset, amount, is_buy, style): - pass - def order(self, asset, amount, limit_price=None, stop_price=None, style=None): """Place an order. @@ -592,6 +581,34 @@ class Exchange: else: return None + # The methods below must be implemented for each exchange. + @abstractmethod + def get_balances(self): + """ + Retrieve wallet balances for the exchange + :return balances: A dict of currency => available balance + """ + pass + + @abstractmethod + def create_order(self, asset, amount, is_buy, style): + """ + Place an order on the exchange. + + :param asset : Asset + The asset that this order is for. + :param amount : int + The amount of shares to order. If ``amount`` is positive, this is + the number of shares to buy or cover. If ``amount`` is negative, + this is the number of shares to sell or short. + :param style : ExecutionStyle + The execution style for the order. + :param is_buy: boolean + Is it a buy order? + :return: + """ + pass + @abstractmethod def get_open_orders(self, asset): """Retrieve all of the current open orders. @@ -649,12 +666,28 @@ class Exchange: Retrieve OHLCV candles for the given assets :param data_frequency: - :param assets: - :param end_dt: + The candle frequency: minute, 5-minute or daily + :param assets: list[TradingPair] + The targeted assets. :param bar_count: - :param limit: - :param start_date: - :return: + The number of bar desired. (default 1) + :param end_dt: datetime, optional + The last bar date. + :param start_date: datetime, optional + The first bar date. + + :return dict[TradingPair, dict[str, Object]]: OHLCV data + A dictionary of OHLCV candles. Each TradingPair instance is + mapped to a list of dictionaries with this structure: + open: float + high: float + low: float + close: float + volume: float + last_traded: datetime + + See definition here: + http://www.investopedia.com/terms/o/ohlcchart.asp """ pass diff --git a/catalyst/exchange/exchange_bundle.py b/catalyst/exchange/exchange_bundle.py index a02363fd..9446a88a 100644 --- a/catalyst/exchange/exchange_bundle.py +++ b/catalyst/exchange/exchange_bundle.py @@ -32,33 +32,6 @@ def fetch_candles_chunk(exchange, assets, data_frequency, end_dt, bar_count): ) return candles - # series = dict() - # - # for asset in assets: - # asset_candles = candles[asset] - # - # candle_start_dt = None - # candle_end_dt = None - # for candle in asset_candles: - # last_traded = candle['last_traded'] - # - # if candle_start_dt is None or candle_start_dt > last_traded: - # candle_start_dt = last_traded - # - # if candle_end_dt is None or candle_end_dt < last_traded: - # candle_end_dt = last_traded - # - # - # asset_df = pd.DataFrame(asset_candles) - # if not asset_df.empty: - # asset_df.set_index('last_traded', inplace=True, drop=True) - # asset_df.sort_index(inplace=True) - # asset_df = asset_df.resample('1T').ffill() - # - # series[asset] = asset_df - # - # return series - def process_bar_data(exchange, assets, writer, data_frequency, show_progress, start, end): @@ -117,9 +90,15 @@ def process_bar_data(exchange, assets, writer, data_frequency, chunk_end = chunk['end'] chunk_start = chunk_end - timedelta(minutes=chunk['bar_count']) + chunk_assets = [] + for asset in assets: + if asset.start_date <= chunk_end: + chunk_assets.append(asset) + + # TODO: ensure correct behavior for assets starting in the chunk candles = fetch_candles_chunk( exchange=exchange, - assets=assets, + assets=chunk_assets, data_frequency=frequency, end_dt=chunk_end, bar_count=chunk['bar_count'] @@ -133,7 +112,7 @@ def process_bar_data(exchange, assets, writer, data_frequency, if not asset_candles: log.debug( 'no data: {symbols} on {exchange}, date {end}'.format( - symbols=assets, + symbols=chunk_assets, exchange=exchange.name, end=chunk_end ) diff --git a/catalyst/utils/run_algo.py b/catalyst/utils/run_algo.py index 401bd2e2..6a4e6f7c 100644 --- a/catalyst/utils/run_algo.py +++ b/catalyst/utils/run_algo.py @@ -143,7 +143,6 @@ def _run(handle_data, 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() @@ -170,6 +169,7 @@ def _run(handle_data, base_currency=base_currency, portfolio=portfolio ) + elif exchange_name == 'bittrex': exchanges[exchange_name] = Bittrex( key=exchange_auth['key'], @@ -177,17 +177,11 @@ def _run(handle_data, base_currency=base_currency, portfolio=portfolio ) + else: raise ExchangeNotFoundError(exchange_name=exchange_name) open_calendar = get_calendar('OPEN') - sim_params = create_simulation_parameters( - start=start, - end=end, - capital_base=capital_base, - data_frequency=data_frequency, - emission_rate=data_frequency, - ) env = TradingEnvironment( environ=environ, @@ -274,9 +268,17 @@ def _run(handle_data, data = DataPortalExchangeBacktest( exchanges=exchanges, - asset_finder=env.asset_finder, + asset_finder=None, trading_calendar=open_calendar, - first_trading_day=start, + first_trading_day=None, + ) + + sim_params = create_simulation_parameters( + start=start, + end=end, + capital_base=capital_base, + data_frequency=data_frequency, + emission_rate=data_frequency, ) algorithm_class = partial(