class Transaction(object): def __init__(self, market, quantity=0, rate=0): self.client = Bittrex(API_KEY, API_SECRET) self.market = market self.quantity = quantity self.rate = rate def createBuyOrder(self): orderData = self.client.buy_limit(self.market, self.quantity, self.rate) self.uuid = self.orderData.get('result').get('uuid') def createSellOrder(self): orderData = self.client.sell_limit(self.market, self.quantity, self.rate) self.uuid = self.orderData.get('result').get('uuid') def cancelBuyOrder(self): self.client.cancel(self.uuid) def cancelSellOrder(self): self.client.cancel(self.uuid) def verifyOrderCompletion(self): if self.client.get_order( self.uuid).get('result').get('IsOpen') == False: return True else: return False
def CancelOutDatedOrder(self, seconds): BittRexCo = Bittrex(self.apikey, self.apisecret) Data = BittRexCo.get_open_orders() if Data['success']: for item in Data['result']: dt = dateutil.parser.parse(item['Opened']) timestamp = int(time.mktime(dt.timetuple())) if time.time() - timestamp > seconds: print("Cancelling Order : " + item['OrderUuid']) BittRexCo.cancel(item['OrderUuid']) else: print(Data['message'])
class BittrexUtils: def __init__(self): self.my_bittrex = Bittrex(BITTREX_KEY, BITTREX_SECRET) def get_available_balance(self, symbol): return self.my_bittrex.get_balance(symbol)["result"]["Available"] def get_ask(self, symbol): """Return current ask price for symbol""" pair = f'BTC-{symbol}' return self.my_bittrex.get_marketsummary(pair)["result"][0]["Ask"] def get_bid(self, symbol): """Return current bid price for symbol""" pair = f'BTC-{symbol}' return self.my_bittrex.get_marketsummary(pair)["result"][0]["Bid"] def get_last(self, symbol): """Return current last price for symbol""" pair = f'BTC-{symbol}' return self.my_bittrex.get_marketsummary(pair)["result"][0]["Last"] def prepare_btc_buy(self, symbol, amount): """Prepare get pair, quantity and price for create_buy_order""" pair = f'BTC-{symbol}' price = self.get_ask(symbol) * 1.02 # Buy 2% higher quantity = round(amount / price, 8) return pair, quantity, price def create_buy_order(self, pair, quantity, price): """Create buy order on Bittrex, return order uuid""" response = self.my_bittrex.buy_limit(pair, quantity, price) if response["success"]: return response["result"]["uuid"] else: raise Exception(response["message"]) def create_sell_order(self, pair, quantity, price): """Create sell order on Bittrex, return order uuid""" response = self.my_bittrex.sell_limit(pair, quantity, price) if response["success"]: return response["result"]["uuid"] else: raise Exception(response["message"]) def get_open_orders(self): orders = self.my_bittrex.get_open_orders()["result"] result = [] for order in orders: message = f'Order {order["OrderUuid"]}\n\n{order["Exchange"]}\nType: {order["OrderType"]}\nQuantity: {order["Quantity"]}\nPrice: {order["Limit"]}\nBTC total: {order["Limit"]*order["Quantity"]}\n\nOpen: {order["Closed"] == None}' result.append(message) return result def cancel_order(self, uuid): return self.my_bittrex.cancel(uuid)["success"] def get_order_status(self, uuid): """Returns string of order status""" order = self.my_bittrex.get_order(uuid)["result"] return f'Order {order["OrderUuid"]}\n\n{order["Exchange"]}\nType: {order["Type"]}\nQuantity: {order["Quantity"]}\nPrice: {order["Limit"]}\nBTC total: {order["Reserved"]}\n\nOpen: {order["IsOpen"]}'
def bittrex_cancel(chat_id, **params): full_api = getbittrexapi(chat_id)['bittrex_api'] api_key = full_api.split(':')[0].strip() api_secret = full_api.split(':')[1].strip() client = Bittrex(api_key, api_secret, api_version=API_V1_1) try: result = client.cancel(**params) print(result) return result except Exception as e: print(e)
btc_bal = bittrex_obj_api2.get_balance('BTC') my_holding_btc = '{:10.8f}'.format(btc_bal['result']['Balance']) last_updated_my_holding = btc_bal['result']['Updated'] print('You have %s BTC, last updated at %s' % (my_holding_btc, last_updated_my_holding)) if btc_bal['result']['Balance'] > 0: print('You have some funds to trade') if set_coin_call_val >= coin_ticker_last_val: print('Finally, its right time to purchase as per your set value') invest_btc = PERCENT_BUY * btc_bal['result']['Balance'] print(set_coin_call, invest_btc, coin_ticker_last_val) trade_buy_obj = bittrex_obj_api2.trade_buy( set_coin_call, order_type='LIMIT', quantity=invest_btc, rate=coin_ticker_last_val, time_in_effect='GOOD_TIL_CANCELLED') print(trade_buy_obj) open_order_obj = bittrex_obj_api2.get_open_orders(set_coin_call) print(open_order_obj) if len(open_order_obj['result']) > 0: open_order_uuid = open_order_obj['result'][0]['OrderUuid'] cancel_order = bittrex_obj_api2.cancel(open_order_uuid) print(cancel_order) else: print('No Open orders') else: print('Sorry, deposit some BTC') #print(json.dumps(btc_price, sort_keys=True, indent=4))
class BittrexClient(Base): """ Bittrex interface """ arg_parser = configargparse.get_argument_parser() arg_parser.add('--bittrex_api_key', help='Bittrex API key') arg_parser.add("--bittrex_secret", help='Bittrex secret key') arg_parser.add("--bittrex_txn_fee", help='Bittrex txn. fee') open_orders = [] def __init__(self): args = self.arg_parser.parse_known_args()[0] super(BittrexClient, self).__init__() api_key = args.bittrex_api_key secret = args.bittrex_secret self.transaction_fee = float(args.bittrex_txn_fee) self.bittrex = Bittrex(api_key, secret) self.pair_delimiter = '-' self.verbosity = args.verbosity def get_pairs(self): """ Returns ticker pairs for all currencies """ markets = self.bittrex.get_market_summaries() if markets is None: print(colored('\n! Got empty markets', 'red')) return None res = markets['result'] pairs = [] for market in res: pair = market['MarketName'] # pair = pair.replace('-', '_') pairs.append(pair) return pairs def get_candles_df(self, currency_pair, epoch_start, epoch_end, interval_in_sec=300): """ Returns candlestick chart data in pandas dataframe """ dict_data = self.get_candles(currency_pair, epoch_start, epoch_end, interval_in_sec) df = pd.DataFrame(dict_data) df['pair'] = currency_pair return df def get_candles(self, currency_pair, epoch_start, epoch_end, interval_in_sec=300): """ Returns candlestick chart data """ currency_pair = currency_pair.replace('_', self.pair_delimiter) try: # tickInterval must be in [“oneMin”, “fiveMin”, “thirtyMin”, “hour”, “day”]. res = self.bittrex.get_ticks(currency_pair, '“fiveMin”') # era “fiveMin” except gaierror as e: print( colored( '\n! Got gaierror exception from Bittrex client. Details: ' + e, 'red')) return dict() except Exception as e: print( colored('\n! Got exception from Bittrex client. Details: ' + e, 'red')) return dict() if res is None: print( colored('\n! Got empty result for pair: ' + currency_pair, 'red')) return dict() tickers = res['result'] got_min_epoch_ticker = False raw_tickers = [] if tickers is None: print( colored('\n! Got empty tickers for pair: ' + currency_pair, 'red')) return dict() # Parse tickers for ticker in tickers: naive_dt = parse(ticker['T']) utc_dt = naive_dt.replace(tzinfo=tzutc()) epoch = int(utc_dt.timestamp()) if epoch <= epoch_start: got_min_epoch_ticker = True # Skip/remove older than wanted tickers (adding extra hours to be sure that we have the data) if epoch < (epoch_start - 6 * 3600): continue raw_ticker = dict() raw_ticker['high'] = ticker['H'] raw_ticker['low'] = ticker['L'] raw_ticker['open'] = ticker['O'] raw_ticker['close'] = ticker['C'] raw_ticker['volume'] = ticker['V'] raw_ticker['quoteVolume'] = ticker['BV'] raw_ticker['date'] = epoch raw_ticker['weightedAverage'] = 0.0 raw_tickers.append(raw_ticker) if not got_min_epoch_ticker: print( colored( 'Not able to get all data (data not available) for pair: ' + currency_pair, 'red')) # Create/interpolate raw tickers to fit our interval ticker out_tickers = [] for ticker_epoch in range(epoch_start, epoch_end, interval_in_sec): items = [ element for element in raw_tickers if element['date'] <= ticker_epoch ] if len(items) <= 0: print( colored( 'Could not found a ticker for:' + currency_pair + ', epoch:' + str(ticker_epoch), 'red')) continue # Get the last item (should be closest to search epoch) item = items[-1].copy() item['date'] = ticker_epoch out_tickers.append(item) return out_tickers.copy() # return self.bittrex.returnChartData(currency_pair, period, start, end) def get_balances(self): """ Return available account balances (function returns ONLY currencies > 0) """ resp = self.bittrex.get_balances() balances = resp['result'] pairs = dict() for item in balances: currency = item['Currency'] pairs[currency] = item['Available'] return pairs @staticmethod def get_volume_from_history(history, candle_size): """ Returns volume for given candle_size :param history: history data :param candle_size: in minutes :return: Calculated volume for given candle_size """ volume = 0.0 epoch_now = int(time.time()) epoch_candle_start = epoch_now - candle_size * 60 pattern = '%Y-%m-%dT%H:%M:%S' for item in history: time_string = item['TimeStamp'].split('.', 1)[0] dt = datetime.datetime.strptime(time_string, pattern) item_epoch = dt.replace(tzinfo=timezone.utc).timestamp() if item_epoch >= epoch_candle_start: quantity = item['Quantity'] volume += quantity return volume def get_symbol_ticker(self, symbol, candle_size=5): """ Returns real-time ticker Data-Frame :candle_size: size in minutes to calculate the interval """ market = symbol.replace('_', self.pair_delimiter) ticker = self.bittrex.get_ticker(market) history = self.bittrex.get_market_history(market, 100)['result'] volume = self.get_volume_from_history(history, candle_size) df = pd.DataFrame.from_dict(ticker['result'], orient="index") df = df.T # We will use 'last' price as closing one df = df.rename(columns={ 'Last': 'close', 'Ask': 'lowestAsk', 'Bid': 'highestBid' }) df['volume'] = volume df['pair'] = symbol df['date'] = int(datetime.datetime.utcnow().timestamp()) return df def get_market_history(self, start, end, currency_pair='all'): """ Returns market trade history """ logger = logging.getLogger(__name__) logger.warning('Not implemented!') pass def trade(self, actions, wallet, trade_mode): """ Places actual buy/sell orders """ if trade_mode == TradeMode.backtest: return Base.trade(actions, wallet, trade_mode) else: actions = self.life_trade(actions) return actions def life_trade(self, actions): """ Places orders and returns order number """ for action in actions: market = action.pair.replace('_', self.pair_delimiter) # Handle buy/sell mode wallet = self.get_balances() if action.buy_sell_mode == BuySellMode.all: action.amount = self.get_buy_sell_all_amount(wallet, action) elif action.buy_sell_mode == BuySellMode.fixed: action.amount = self.get_fixed_trade_amount(wallet, action) if self.verbosity: print( 'Processing live-action: ' + str(action.action) + ', amount:', str(action.amount) + ', pair:', market + ', rate:', str(action.rate) + ', buy_sell_mode:', action.buy_sell_mode) if action.action == TradeState.none: actions.remove(action) continue # If we don't have enough assets, just skip/remove the action if action.amount == 0.0: print( colored( 'No assets to buy/sell, ...skipping: ' + str(action.amount) + ' ' + market, 'green')) actions.remove(action) continue # ** Buy Action ** if action.action == TradeState.buy: print( colored( 'setting buy order: ' + str(action.amount) + '' + market, 'green')) ret = self.bittrex.buy_limit(market, action.amount, action.rate) if not ret['success']: print( colored( 'Error: ' + ret['message'] + '. Txn: buy-' + market, 'red')) continue else: uuid = ret['result']['uuid'] self.open_orders.append(uuid) print(colored('Buy order placed (uuid): ' + uuid, 'green')) print(ret) # ** Sell Action ** elif action.action == TradeState.sell: print( colored( 'setting sell order: ' + str(action.amount) + '' + market, 'yellow')) ret = self.bittrex.sell_limit(market, action.amount, action.rate) if not ret['success']: print( colored( 'Error: ' + ret['message'] + '. Txn: sell-' + market, 'red')) continue else: uuid = ret['result']['uuid'] self.open_orders.append(uuid) print(colored('Sell order placed (uuid): ' + uuid, 'green')) print(ret) return actions def cancel_order(self, order_number): """ Cancels order for given order number """ return self.bittrex.cancel(order_number) def get_open_orders(self, currency_pair=''): """ Returns open orders """ return self.bittrex.get_open_orders(currency_pair) def get_trade_history(self, date_from, date_to, currency_pair='all'): """ Returns trade history """ # TODO pass
class ApiWrapper(object): """ Wrapper for exchanges. Currently implemented: * Bittrex * Poloniex (partly) """ def __init__(self, config): """ Initializes the ApiWrapper with the given config, it does not validate those values. :param config: dict """ self.dry_run = config['dry_run'] if self.dry_run: logger.info('Instance is running with dry_run enabled') use_poloniex = config.get('poloniex', {}).get('enabled', False) use_bittrex = config.get('bittrex', {}).get('enabled', False) if use_poloniex: self.exchange = Exchange.POLONIEX self.api = Poloniex(key=config['poloniex']['key'], secret=config['poloniex']['secret']) elif use_bittrex: self.exchange = Exchange.BITTREX self.api = Bittrex(api_key=config['bittrex']['key'], api_secret=config['bittrex']['secret']) else: self.api = None def buy(self, pair, rate, amount): """ Places a limit buy order. :param pair: Pair as str, format: BTC_ETH :param rate: Rate limit for order :param amount: The amount to purchase :return: None """ if self.dry_run: pass elif self.exchange == Exchange.POLONIEX: self.api.buy(pair, rate, amount) # TODO: return order id elif self.exchange == Exchange.BITTREX: data = self.api.buy_limit(pair.replace('_', '-'), amount, rate) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) return data['result']['uuid'] def sell(self, pair, rate, amount): """ Places a limit sell order. :param pair: Pair as str, format: BTC_ETH :param rate: Rate limit for order :param amount: The amount to sell :return: None """ if self.dry_run: pass elif self.exchange == Exchange.POLONIEX: self.api.sell(pair, rate, amount) # TODO: return order id elif self.exchange == Exchange.BITTREX: data = self.api.sell_limit(pair.replace('_', '-'), amount, rate) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) return data['result']['uuid'] def get_balance(self, currency): """ Get account balance. :param currency: currency as str, format: BTC :return: float """ if self.dry_run: return 999.9 elif self.exchange == Exchange.POLONIEX: data = self.api.returnBalances() return float(data[currency]) elif self.exchange == Exchange.BITTREX: data = self.api.get_balance(currency) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) return float(data['result']['Balance'] or 0.0) def get_ticker(self, pair): """ Get Ticker for given pair. :param pair: Pair as str, format: BTC_ETC :return: dict """ if self.exchange == Exchange.POLONIEX: data = self.api.returnTicker() return { 'bid': float(data[pair]['highestBid']), 'ask': float(data[pair]['lowestAsk']), 'last': float(data[pair]['last']) } elif self.exchange == Exchange.BITTREX: data = self.api.get_ticker(pair.replace('_', '-')) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) return { 'bid': float(data['result']['Bid']), 'ask': float(data['result']['Ask']), 'last': float(data['result']['Last']), } def cancel_order(self, order_id): """ Cancel order for given order_id :param order_id: id as str :return: None """ if self.dry_run: pass elif self.exchange == Exchange.POLONIEX: raise NotImplemented('Not implemented') elif self.exchange == Exchange.BITTREX: data = self.api.cancel(order_id) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) def get_open_orders(self, pair): """ Get all open orders for given pair. :param pair: Pair as str, format: BTC_ETC :return: list of dicts """ if self.dry_run: return [] elif self.exchange == Exchange.POLONIEX: raise NotImplemented('Not implemented') elif self.exchange == Exchange.BITTREX: data = self.api.get_open_orders(pair.replace('_', '-')) if not data['success']: raise RuntimeError('BITTREX: {}'.format(data['message'])) return [{ 'id': entry['OrderUuid'], 'type': entry['OrderType'], 'opened': entry['Opened'], 'rate': entry['PricePerUnit'], 'amount': entry['Quantity'], 'remaining': entry['QuantityRemaining'], } for entry in data['result']] def get_pair_detail_url(self, pair): """ Returns the market detail url for the given pair :param pair: pair as str, format: BTC_ANT :return: url as str """ if self.exchange == Exchange.POLONIEX: raise NotImplemented('Not implemented') elif self.exchange == Exchange.BITTREX: return 'https://bittrex.com/Market/Index?MarketName={}'.format( pair.replace('_', '-'))
class BittrexExchange(Exchange): def __init__(self, auth=False): if auth: with open('bittrex.key') as kfile: api_key = kfile.readline().strip() api_secret = kfile.readline().strip() else: api_key = None api_secret = None self.conn = Bittrex(api_key, api_secret, api_version=API_V2_0) def sell_limit(self, pair, quantity, value): req = self.conn.trade_sell(pair, 'LIMIT', quantity, value, 'GOOD_TIL_CANCELLED') if not self._validate_req(req): print('Unable to pass limit order: %s' % req['message']) data = req['result'] return BittrexOrder(data, id=data['OrderId']) def sell_market(self, pair, quantity): pass def sell_stop(self, pair, quantity, value): req = self.conn.trade_sell(pair, 'LIMIT', quantity, value, 'GOOD_TIL_CANCELLED', 'LESS_THAN', value) if not self._validate_req(req): print('Unable to pass stop order: %s' % req['message']) return None data = req['result'] return BittrexOrder(data, id=data['OrderId']) def buy_limit(self, pair, quantity, value): req = self.conn.trade_buy(pair, 'LIMIT', quantity, value, 'GOOD_TIL_CANCELLED') if not self._validate_req(req): print('Unable to pass buy limit order: %s' % req['message']) data = req['result'] return BittrexOrder(data, id=data['OrderId']) def buy_limit_range(self, pair, quantity, min_val, max_val): req = self.conn.trade_buy(pair, 'LIMIT', quantity, max_val, 'GOOD_TIL_CANCELLED', 'GREATER_THAN', min_val) if not self._validate_req(req): print('Unable to pass buy range order: %s' % req['message']) data = req['result'] return BittrexOrder(data, id=data['OrderId']) def get_tick(self, pair): req = self.conn.get_latest_candle(pair, 'oneMin') if not self._validate_req(req): print('Unable to get tick: %s' % req['message']) return None return req['result'][0] def get_open_orders(self, pair): req = self.conn.get_open_orders(pair) if self._validate_req(req): return [ BittrexOrder(data, id=data['OrderUuid']) for data in req['result'] ] else: return [] def cancel_order(self, order): req = self.conn.cancel(order.id) if not self._validate_req(req): print('Unable to cancel order: %s' % req['message']) return False return True def get_position(self, pair): req = self.conn.get_balance(pair) if not self._validate_req(req): print('Unable to get position: %s' % req['message']) return None return req['result'] @staticmethod def _validate_req(req): return ('success' in req and req['success'] is True)
from bittrex.bittrex import Bittrex, SELL_ORDERBOOK import json import logging import pprint order_id = '78124cb3-dc10-44b7-8734-41a845e42bc7' with open("secrets.json") as secrets_file: secrets = json.load(secrets_file) exchange = Bittrex(secrets['key'], secrets['secret']) openorders = exchange.get_open_orders() for order in openorders['result']: print order result = exchange.cancel(order_id) print("\tResult of clearing profit: {}".format(pprint.pformat(result)))
class BittrexExchange(Exchange): def __init__(self, auth=False): if auth: with open('bittrex.key') as kfile: api_key = kfile.readline().strip() api_secret = kfile.readline().strip() else: api_key = None api_secret = None self.conn = Bittrex(api_key, api_secret, api_version=API_V2_0) @bittrex_retry() def sell_limit(self, pair, quantity, value): req = self.conn.trade_sell( pair, 'LIMIT', quantity, value, 'GOOD_TIL_CANCELLED') self._validate_req(req, 'Unable to pass limit order') data = req['result'] return BittrexOrder(data, id=data['OrderId']) @bittrex_retry() def sell_market(self, pair, quantity): pass @bittrex_retry() def sell_stop(self, pair, quantity, value): req = self.conn.trade_sell( pair, 'LIMIT', quantity, value / 2, 'GOOD_TIL_CANCELLED', 'LESS_THAN', value) self._validate_req(req, 'Unable to pass stop order') data = req['result'] return BittrexOrder(data, id=data['OrderId']) @bittrex_retry() def buy_limit(self, pair, quantity, value): req = self.conn.trade_buy( pair, 'LIMIT', quantity, value, 'GOOD_TIL_CANCELLED') self._validate_req(req, 'Unable to pass buy limit order') data = req['result'] return BittrexOrder(data, id=data['OrderId']) @bittrex_retry() def buy_limit_range(self, pair, quantity, min_val, max_val): req = self.conn.trade_buy( pair, 'LIMIT', quantity, max_val, 'GOOD_TIL_CANCELLED', 'GREATER_THAN', min_val) self._validate_req(req, 'Unable to pass buy range order') data = req['result'] return BittrexOrder(data, id=data['OrderId']) @bittrex_retry() def get_tick(self, pair): req = self.conn.get_latest_candle(pair, 'oneMin') self._validate_req(req, 'Unable to get tick') return req['result'][0] @bittrex_retry() def get_candles(self, pair, duration): req = self.conn.get_candles(pair, duration) self._validate_req(req, 'Unable to get candles') return req['result'] @bittrex_retry() def get_open_orders(self, pair): req = self.conn.get_open_orders(pair) self._validate_req(req, 'Unable to get open orders') return [BittrexOrder(data, id=data['OrderUuid']) for data in req['result']] @bittrex_retry() def get_order_history(self, pair=None): req = self.conn.get_order_history(pair) self._validate_req(req, 'Unable to get order history') return [BittrexOrder(data, id=data['OrderUuid']) for data in req['result']] @bittrex_retry() def cancel_order(self, order): req = self.conn.cancel(order.id) try: self._validate_req(req, 'Unable to cancel order') except BittrexError as error: if error.args[0] == 'ORDER_NOT_OPEN': return True else: raise error while True: req = self.conn.get_order(order.id) self._validate_req(req, 'Unable to get status of the canceled order') if (('status' in req and req['status'] is None) or ('result' in req and 'IsOpen' in req['result'] and req['result']['IsOpen'] is False)): break return True @bittrex_retry() def get_balances(self): req = self.conn.get_balances() self._validate_req(req, 'Unable to get balances') return req['result'] @bittrex_retry() def get_position(self, pair): req = self.conn.get_balance(pair) self._validate_req(req, 'Unable to get position') return req['result'] @bittrex_retry() def update_order(self, order): req = self.conn.get_order(order.id) self._validate_req(req, 'Unable to get order') order.update(req['result']) return order @staticmethod def _validate_req(req, msg=None, do_raise=True): if 'success' in req and req['success'] is True: return True else: if msg: print('%s: %s' % (msg, req.get('message', '<no message>'))) if do_raise: if req.get('message', None) in ('NO_API_RESPONSE', 'APIKEY_INVALID'): raise BittrexRetryableError(req['message']) else: raise BittrexError(req.get('message', '<no message>')) else: return False
class BittrexExchange: def __init__(self): self.disabled = False api_key = bot_cfg("BTREX_KEY") api_secret = bot_cfg("BTREX_SECRET") if api_key is None or api_secret is None: self.disabled = True log.info( "Disable BITTREX because either api_key or api_secret not available" ) else: self.bittrex_v1 = Bittrex(api_key, api_secret, api_version=API_V1_1) self.bittrex_v2 = Bittrex(api_key, api_secret, api_version=API_V2_0) self.cache = ExpiringDict(max_len=200, max_age_seconds=60) def is_disabled(self): return self.disabled def name(self): return self.__class__.__name__ def get_open_orders(self): log.info("{}: Getting open orders".format(self.name())) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) if self.cache.get("open_orders"): return self.cache.get("open_orders") open_orders_response = self.bittrex_v1.get_open_orders() open_orders = self.result(open_orders_response) self.cache["open_orders"] = open_orders return open_orders def get_orders_history(self): log.info("{}: Getting order history".format(self.name())) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) if self.cache.get("order_history"): return self.cache.get("order_history") order_history_response = self.bittrex_v1.get_order_history() order_history = self.result(order_history_response) self.cache["order_history"] = order_history return order_history def get_price(self, symbol): log.info("{}: Getting ticker data for {}".format(self.name(), symbol)) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) if self.cache.get(symbol): return self.cache.get(symbol) ticker_info_response = self.bittrex_v1.get_ticker(symbol) ticker_info = self.result(ticker_info_response) self.cache[symbol] = ticker_info return ticker_info def trade_commission(self, quantity, price): trade_value = float(quantity) * float(price) exchange_commission = trade_value * 0.0025 return trade_value, exchange_commission, trade_value + exchange_commission def get_market_summaries(self): log.info("{}: Getting market summaries from exchange".format( self.name())) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) if self.cache.get("market_summaries_api"): return self.cache.get("market_summaries_api") market_summaries_api_response = self.bittrex_v1.get_market_summaries() market_summaries_api = self.result(market_summaries_api_response) self.cache["market_summaries_api"] = market_summaries_api return market_summaries_api def sell_order(self, quantity_to_sell, trade_symbol, sell_price): log.info( "{}: Selling {} (quantity) of {} (symbol) for {:06.8f} (price)". format(self.name(), quantity_to_sell, trade_symbol, sell_price)) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) sell_limit_response = self.bittrex_v2.trade_sell( market=trade_symbol, order_type="LIMIT", quantity=quantity_to_sell, rate=sell_price, time_in_effect="GOOD_TIL_CANCELLED", condition_type="LESS_THAN", target=sell_price, ) sell_limit = self.result(sell_limit_response) order_id = sell_limit.get("OrderId") return order_id def buy_order(self, quantity_to_buy, trade_symbol, buy_price): log.info( "{}: Buying {} (quantity) of {} (symbol) for {:06.8f} (price)". format(self.name(), quantity_to_buy, trade_symbol, buy_price)) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) buy_limit_response = self.bittrex_v2.trade_buy( market=trade_symbol, order_type="LIMIT", quantity=quantity_to_buy, rate=buy_price, time_in_effect="GOOD_TIL_CANCELLED", condition_type="GREATER_THAN", target=buy_price, ) buy_limit = self.result(buy_limit_response) order_id = buy_limit.get("OrderId") return order_id def get_balances(self): log.info("{}: Printing balance in exchange".format(self.name())) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) if self.cache.get("balances"): return self.cache.get("balances") get_balances_response = self.bittrex_v1.get_balances() balances = [{ "exchange": "BITTREX", "currency": b.get("Currency"), "available": b.get("Balance"), } for b in self.result(get_balances_response) if b.get("Balance") > 0] self.cache["balances"] = balances return balances def track_order(self, order_id): log.info("{}: Tracking order: {}".format(self.name(), order_id)) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) get_order_response = self.bittrex_v2.get_order(order_id) order = self.result(get_order_response) quantity = order.get("Quantity") quantity_remaining = order.get("QuantityRemaining") settled = not order.get("IsOpen") status = "closed" if settled else "open" side = "sell" if order.get("Type") == "LIMIT_SELL" else "buy" price = float(order.get("Price")) limit = float(order.get("Limit")) commission_paid = float(order.get("CommissionPaid")) executed_value = price + commission_paid return { "id": order.get("OrderUuid"), "settled": settled, "side": side, "done_reason": "canceled" if quantity_remaining and settled else "done", "status": status, "price": price, "limit": "{:06.8f}".format(limit), "fill_fees": "{:06.8f}".format(commission_paid), "filled_size": quantity - quantity_remaining, "executed_value": "{:06.8f}".format(executed_value), "done_at": order.get("Closed"), } def cancel_order(self, order_id, reason=None): log.info("{}: Cancelling order: {}, Reason: {}".format( self.name(), order_id, reason)) if self.is_disabled(): raise EnvironmentError("{} is disabled".format(self.name())) cancelled_order_response = self.bittrex_v2.cancel(order_id) return self.result(cancelled_order_response) @staticmethod def result(api_response): if api_response.get("success"): return api_response.get("result") raise ConnectionError("API Failed: {}".format(api_response))
def main(): with open('./BittrexAPI.txt') as apifile: lines = apifile.readlines() my_api_key = lines[2] my_api_secret = lines[4] try: my_bittrex = Bittrex(my_api_key, my_api_secret, api_version='v1.1') print('API Logged In.') except: print('Login Error.') try: quantity = float(input('Set quantity as:')) aim = str(input('Set aim coin as:')) except: aim = None print('Input Error.') balance = my_bittrex.get_balance('BTC') if aim != None: buy_market = 'BTC-' + aim sell_market = aim + '-BTC' else: sys.exit() buy_rate = my_bittrex.get_ticker(buy_market)['result']['Bid'] if quantity <= balance: start = time.time() buy_result = my_bittrex.buy_limit(buy_market, quantity, buy_rate) buy_uuid = buy_result['result']['uuid'] if buy_result['success'] == True: end = time.time() print('Buying Has Done. Time: %s' % str(end - start)) else: print('Buying Timeout.') my_bittrex.cancel(buy_uuid) sys.exit() sell_trig = str(input('Start Selling? (Y/N)')) if sell_trig != 'N': start = time.time() base_remain = my_bittrex.get_balance('BTC') aim_all = my_bittrex.get_balance(aim) sell_rate = my_bittrex.get_ticker(sell_market)['result']['Bid'] if base_remain == balance - quantity: sell_result = my_bittrex.sell_limit(sell_market, aim_all, sell_rate) if sell_result['success'] == True: end = time.time() print('Selling Has Done. Time: %s' % str(end - start)) else: print('Selling timeout.') sys.exit() else: print('Buying delayed. Canceling Order.') my_bittrex.cancel(buy_uuid) sys.exit() else: print('Not Enough Funds.') sys.exit()
class BittrexService(Exchange): def __init__(self, name, public_key, private_key): Exchange.__init__(self, name) self.ob_ws = OrderBookSocket(self) self.ex_ws = ExecutionsSocket(self) self.ex_ws.authenticate(public_key, private_key) self.markets_following = {} self.open_orders = [] self.rest_client = Bittrex(public_key, private_key, api_version=API_V1_1) def get_order_book(self, base, quote): resp = self.rest_client.get_orderbook( BittrexService._to_market(base, quote)) print('rest book:' + str(resp['result'])) if resp['success'] is True: book = resp['result'] internal_book = {'bids': [], 'asks': []} for bid in book['buy']: internal_book['bids'].append( [str(bid['Rate']), str(bid['Quantity'])]) for ask in book['sell']: internal_book['asks'].append( [str(ask['Rate']), str(ask['Quantity'])]) internal_book['base'] = base internal_book['quote'] = quote internal_book['exchange'] = self.name self.notify_callbacks('order_book', data=internal_book) return internal_book def get_our_orders_by_decimal_price(self): our_orders_by_price = {'bids': {}, 'asks': {}} open_orders_copy = self.open_orders.copy() for order in open_orders_copy: order['price'] = Decimal(str(order['price'])) order['quantity'] = Decimal(str(order['quantity'])) order['cum_quantity_filled'] = Decimal( str(order['cum_quantity_filled'])) if order['side'] == 'buy': if str(order['price']) not in our_orders_by_price['bids']: our_orders_by_price['bids'][order['price']] = order[ 'quantity'] - order['cum_quantity_filled'] else: our_orders_by_price['bids'][order['price']] += order[ 'quantity'] - order['cum_quantity_filled'] elif order['side'] == 'sell': if str(order['price']) not in our_orders_by_price['bids']: our_orders_by_price['asks'][order['price']] = order[ 'quantity'] - order['cum_quantity_filled'] else: our_orders_by_price['asks'][order['price']] += order[ 'quantity'] - order['cum_quantity_filled'] return our_orders_by_price def follow_market(self, base, quote): self.ob_ws.add_subscription(BittrexService._to_market( base, quote)) # bittrex has it backwards self.ex_ws.add_subscription(BittrexService._to_market( base, quote)) # bittrex has it backwards self.markets_following[self._to_market(base, quote)] = { 'base': base, 'quote': quote } def unfollow_market(self, base, quote): self.ob_ws.remove_subscription(BittrexService._to_market(base, quote)) self.ex_ws.remove_subscription(BittrexService._to_market(base, quote)) self.markets_following.pop(self._to_market(base, quote), None) @staticmethod def _to_market(base, quote): return quote + '-' + base def unfollow_all(self): markets = self.ob_ws.books_following.keys() for market in markets: self.ob_ws.remove_subscription(market) def get_balances(self): response = self.rest_client.get_balances() if response['success'] is True: internal_balances = [] entries = response['result'] for entry in entries: asset = entry['Currency'] balance = Decimal(str(entry['Balance'])) free = Decimal(str(entry['Available'])) if balance > Decimal(0): internal_balances.append({ 'asset': asset, 'free': free, 'locked': balance - free }) self.notify_callbacks('account', account_type='balance', data=internal_balances) return internal_balances else: self.notify_callbacks('account', account_type='balances_failed', data={}) return [] def create_order(self, base, quote, price, quantity, side, order_type, internal_order_id, request_id=None, requester_id=None, **kwargs): if side == 'buy': response = self.rest_client.buy_limit( BittrexService._to_market(base, quote), quantity, price) elif side == 'sell': response = self.rest_client.sell_limit( BittrexService._to_market(base, quote), quantity, price) else: raise NotImplementedError('Side of {} is unknown for {}', side, self.name) quantity = str(quantity) price = str(price) if response is None: internal_response = { 'action': 'CREATE_FAILED', 'reason': 'UNKNOWN', 'exchange': self.name, 'base': base, 'quote': quote, 'internal_order_id': internal_order_id, 'side': side, 'quantity': quantity, 'price': price, 'cum_quantity_filled': 0, 'received_ms': time() * 1000 } elif 'success' in response and response['success'] is False: reason = 'UNKNOWN' if response['message'] == 'INSUFFICIENT_FUNDS': reason = response['message'] internal_response = { 'action': 'CREATE_FAILED', 'reason': reason, 'exchange': self.name, 'base': base, 'quote': quote, 'internal_order_id': internal_order_id, 'side': side, 'quantity': quantity, 'price': price, 'cum_quantity_filled': 0, 'received_ms': time() * 1000 } else: exchange_id = response['result']['uuid'] internal_response = { 'action': 'CREATED', 'exchange': self.name, 'base': base, 'quote': quote, 'exchange_order_id': exchange_id, 'internal_order_id': internal_order_id, 'side': side, 'quantity': quantity, 'price': price, 'cum_quantity_filled': 0, 'order_status': 'OPEN', 'server_ms': time() * 1000, 'received_ms': time() * 1000 } open_order = internal_response.copy() open_order['price'] = Decimal(open_order['price']) open_order['quantity'] = Decimal(open_order['quantity']) self.open_orders.append(internal_response) self.notify_callbacks('trade_lifecycle', data=internal_response) return internal_response def cancel_order(self, base, quote, internal_order_id, request_id, requester_id=None, exchange_order_id=None): index_to_pop = None if exchange_order_id is None: i = 0 for open_order in self.open_orders: if open_order['internal_order_id'] == internal_order_id: exchange_order_id = open_order['exchange_order_id'] index_to_pop = i break i += 1 response = self.rest_client.cancel(exchange_order_id) if response['success'] is True: i = 0 if index_to_pop is None: for order in self.open_orders: if order['exchange_order_id'] == exchange_order_id: index_to_pop = i break i += 1 if index_to_pop is not None: self.open_orders.pop(index_to_pop) self.notify_callbacks('trade_lifecycle', data={ 'action': 'CANCELED', 'base': base, 'quote': quote, 'exchange': self.name, 'exchange_order_id': exchange_order_id, 'internal_order_id': internal_order_id, 'order_status': 'CANCELED', 'server_ms': int(round(time() * 1000)), 'received_ms': int(round(time() * 1000)) }) else: reason = response['message'] if response['message'] == 'INVALID_ORDER' or\ response['message'] == 'ORDER_NOT_OPEN' or\ response['message'] == 'UUID_INVALID': reason = 'order_not_found' self.notify_callbacks('trade_lifecycle', data={ 'action': 'CANCEL_FAILED', 'base': base, 'quote': quote, 'reason': reason, 'exchange': self.name, 'exchange_order_id': exchange_order_id, 'internal_order_id': internal_order_id, 'order_status': 'UNKNOWN', 'server_ms': int(round(time() * 1000)), 'received_ms': int(round(time() * 1000)) }) def cancel_all(self, base, quote): open_orders_resp = self.rest_client.get_open_orders( BittrexService._to_market(base, quote)) open_orders = open_orders_resp['result'] for open_order in open_orders: exchange_order_id = open_order['OrderUuid'] internal_order_id = None for order in self.open_orders: if order['exchange_order_id'] == exchange_order_id: internal_order_id = order['internal_order_id'] break self.cancel_order(base, quote, internal_order_id, 'a_request_id', exchange_order_id=exchange_order_id) def can_withdraw(self, currency): return True def withdraw(self, currency, amount, address, tag=None, cb=None, **kwargs): # TODO - Internal format and cb self.rest_client.withdraw(currency, address, amount) def can_deposit(self, currency): return True def get_deposit_address(self, currency): response = self.rest_client.get_deposit_address(currency) return response['result']['Address'] def get_deposits(self, currency=None): # TODO - Internal format return self.rest_client.get_deposit_history(currency) def get_withdrawals(self, currency): # TODO - Internal format return self.rest_client.get_withdrawal_history(currency) def get_order_by_exchange_id(self, exchange_id): for open_order in self.open_orders.copy(): if open_order['exchange_order_id'] == exchange_id: return open_order return None def get_public_trades(self, base, quote, start_s, end_s): pass def get_our_trades(self, base, quote, start_s, end_s): pass