def __convert_order_params_for_blotter(limit_price, stop_price, style): """ Helper method for converting deprecated limit_price and stop_price arguments into ExecutionStyle instances. This function assumes that either style == None or (limit_price, stop_price) == (None, None). """ if stop_price: raise OrderTypeNotSupported(order_type='stop') if style: if limit_price is not None: raise ValueError( 'An order style and a limit price was included in the ' 'order. Please pick one to avoid any possible conflict.' ) # Currently limiting order types or limit and market to # be in-line with CXXT and many exchanges. We'll consider # adding more order types in the future. if not isinstance(style, ExchangeLimitOrder) or \ not isinstance(style, MarketOrder): raise OrderTypeNotSupported( order_type=style.__class__.__name__ ) return style if limit_price: return ExchangeLimitOrder(limit_price) else: return MarketOrder()
def test_orders(self): population = 3 quote_currency = 'eth' order_amount = 0.1 exchanges = select_random_exchanges( population=population, features=['fetchOrder'], is_authenticated=True, base_currency=quote_currency, ) # Type: list[Exchange] log_catcher = TestHandler() with log_catcher: for exchange in exchanges: exchange.init() assets = exchange.get_assets(quote_currency=quote_currency) asset = select_random_assets(assets, 1)[0] self.assertIsInstance(asset, TradingPair) tickers = exchange.tickers([asset]) price = tickers[asset]['last_price'] amount = order_amount / price limit_price = price * 0.8 style = ExchangeLimitOrder(limit_price=limit_price) order = exchange.order( asset=asset, amount=amount, style=style, ) sleep(1) open_order, _ = exchange.get_order(order.id, asset) self.assertEqual(0, open_order.status) exchange.cancel_order(open_order, asset) sleep(1) canceled_order, _ = exchange.get_order(open_order.id, asset) warnings = [ record for record in log_catcher.records if record.level == WARNING ] self.assertEqual(0, len(warnings)) self.assertEqual(2, canceled_order.status) print('tested {exchange} / {symbol}, order: {order}'.format( exchange=exchange.name, symbol=asset.symbol, order=order.id, )) pass
def test_order(self): log.info('creating order') asset = self.exchange.get_asset('eth_usdt') order_id = self.exchange.order( asset=asset, style=ExchangeLimitOrder(limit_price=1000), amount=1.01, ) log.info('order created {}'.format(order_id)) assert order_id is not None pass
def __convert_order_params_for_blotter(limit_price, stop_price, style): """ Helper method for converting deprecated limit_price and stop_price arguments into ExecutionStyle instances. This function assumes that either style == None or (limit_price, stop_price) == (None, None). """ if style: assert (limit_price, stop_price) == (None, None) return style if limit_price and stop_price: return ExchangeStopLimitOrder(limit_price, stop_price) if limit_price: return ExchangeLimitOrder(limit_price) if stop_price: return ExchangeStopOrder(stop_price) else: return MarketOrder()
def test_orders(self): population = 3 quote_currency = 'eth' order_amount = 0.1 exchanges = select_random_exchanges( population=population, features=['fetchOrder'], is_authenticated=True, base_currency=quote_currency, ) # Type: list[Exchange] for exchange in exchanges: exchange.init() assets = exchange.get_assets(quote_currency=quote_currency) asset = select_random_assets(assets, 1)[0] assert asset tickers = exchange.tickers([asset]) price = tickers[asset]['last_price'] amount = order_amount / price limit_price = price * 0.8 style = ExchangeLimitOrder(limit_price=limit_price) order = exchange.order( asset=asset, amount=amount, style=style, ) sleep(1) open_order, _ = exchange.get_order(order.id, asset) assert open_order.status == 0 exchange.cancel_order(open_order, asset) sleep(1) canceled_order, _ = exchange.get_order(open_order.id, asset) assert canceled_order.status == 2 pass
def order(self, asset, amount, limit_price=None, stop_price=None, style=None): """Place an order. Parameters ---------- asset : Asset The asset that this order is for. 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. limit_price : float, optional The limit price for the order. stop_price : float, optional The stop price for the order. style : ExecutionStyle, optional The execution style for the order. Returns ------- order_id : str or None The unique identifier for this order, or None if no order was placed. Notes ----- The ``limit_price`` and ``stop_price`` arguments provide shorthands for passing common execution styles. Passing ``limit_price=N`` is equivalent to ``style=LimitOrder(N)``. Similarly, passing ``stop_price=M`` is equivalent to ``style=StopOrder(M)``, and passing ``limit_price=N`` and ``stop_price=M`` is equivalent to ``style=StopLimitOrder(N, M)``. It is an error to pass both a ``style`` and ``limit_price`` or ``stop_price``. See Also -------- :class:`catalyst.finance.execution.ExecutionStyle` :func:`catalyst.api.order_value` :func:`catalyst.api.order_percent` """ if amount == 0: log.warn('skipping order amount of 0') return None if asset.base_currency != self.base_currency.lower(): raise MismatchingBaseCurrencies(base_currency=asset.base_currency, algo_currency=self.base_currency) is_buy = (amount > 0) if limit_price is not None and stop_price is not None: style = ExchangeStopLimitOrder(limit_price, stop_price, exchange=self.name) elif limit_price is not None: style = ExchangeLimitOrder(limit_price, exchange=self.name) elif stop_price is not None: style = ExchangeStopOrder(stop_price, exchange=self.name) elif style is not None: raise InvalidOrderStyle(exchange=self.name.title(), style=style.__class__.__name__) else: raise ValueError('Incomplete order data.') display_price = limit_price if limit_price is not None else stop_price log.debug( 'issuing {side} order of {amount} {symbol} for {type}: {price}'. format(side='buy' if is_buy else 'sell', amount=amount, symbol=asset.symbol, type=style.__class__.__name__, price='{}{}'.format(display_price, asset.base_currency))) order = self.create_order(asset, amount, is_buy, style) if order: self._portfolio.create_order(order) return order.id else: return None