def fetch_ticker(self, symbol): ohlcv = self._ohlcvs.get(symbol) if ohlcv is None: raise BadSymbol('ExchangeBackend: no prices for {}'.format(symbol)) current_date = self._timeframe.date().floor('1T') row = ohlcv.loc[current_date] timestamp = int(current_date.value / 10**6) return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': Exchange.iso8601(timestamp), 'high': row['high'], 'low': row['low'], 'bid': None, 'bidVolume': None, 'ask': None, 'askVolume': None, 'vwap': None, 'open': row['open'], 'close': row['close'], 'last': None, 'previousClose': None, 'change': None, 'percentage': None, 'average': None, 'baseVolume': None, 'quoteVolume': None, 'info': {}, }
def iso8601(value): return ccxtExchange.iso8601(value)
def create_order(self, market, type, price, side, amount): self._update_orders() type_market = False type_limit = False if type == 'market': if price is not None: raise InvalidOrder( 'ExchangeAccount: market order has no price') type_market = True elif type == 'limit': price = _convert_float_or_raise(price, 'ExchangeAccount: price') type_limit = True if price <= 0: raise BadRequest('ExchangeAccount: price needs to be positive') else: raise InvalidOrder( 'ExchangeAccount: only market and limit order supported') if market is None: raise InvalidOrder('ExchangeAccount: market is None') symbol = market.get('symbol') ohlcv = self._ohlcvs.get(symbol) if ohlcv is None: raise InvalidOrder('ExchangeAccount: no prices available for {}' .format(symbol)) if side not in ['buy', 'sell']: raise InvalidOrder('ExchangeAccount: side {} not supported' .format(side)) buy = side == 'buy' amount = _convert_float_or_raise(amount, 'ExchangeAccount: amount') if amount <= 0: raise BadRequest('ExchangeAccount: amount needs to be positive') base = market.get('base') quote = market.get('quote') if base is None: raise BadRequest('ExchangeAccount: market has no base') if quote is None: raise BadRequest('ExchangeAccount: market has no quote') self._last_order_id += 1 order_id = str(self._last_order_id) date = self._timeframe.date() timestamp = int(date.value / 10e5) order = { 'info': {}, 'id': order_id, 'timestamp': timestamp, 'datetime': Exchange.iso8601(timestamp), 'lastTradeTimestamp': None, 'symbol': symbol, 'type': type, 'side': side, 'price': None, 'amount': amount, 'cost': None, 'average': None, 'filled': 0, 'remaining': amount, 'status': 'open', 'fee': {'currency': base if buy else quote, 'cost': None, 'rate': None}, 'trades': None, } if type_market: # Determinie the price of the market order # We could use the next low/high to fill the order, but then we # need to wait for the next date to fill the order, otherwise we # would introduce a possibility to see the future price # (Look-Ahead Bias) # If we wait for the next date, we would return a market order that # is pending, but this should never happen in reality # Maybe the factor should depend on the volume factor = Decimal('0.0015') if buy: price = (1 + factor) * _convert_float(ohlcv['high'][date]) else: price = (1 - factor) * _convert_float(ohlcv['low'][date]) fee_percentage = market.get('taker', 0) fee_percentage = _convert_float_or_raise(fee_percentage, 'ExchangeAccount: fee') self._update_balance(price, amount, base, quote, buy, fee_percentage) self._fill_order(order, buy, price, timestamp, fee_percentage) self._closed_orders[order_id] = order if type_limit: # TODO Probably use taker fee, if the order can be filled now fee_percentage = market.get('maker', 0) fee_percentage = _convert_float_or_raise(fee_percentage, 'ExchangeAccount: fee') if buy: self._balances[quote].change_used(price * amount) else: self._balances[base].change_used(amount) self._open_orders[order_id] = order self._private_order_info[order_id] = { 'id': order_id, 'base': base, 'quote': quote, 'price': price, 'buy': buy, 'fee_percentage': fee_percentage, 'fillable_date': self._limit_order_fillable_date( symbol, buy, price), } self._update_next_private_order_to_update() return {'id': order_id, 'info': {}}