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"]}'
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 PlaceBuyOrder(self, market, quantity, rate): BittRexCo = Bittrex(self.apikey, self.apisecret) Data = BittRexCo.buy_limit(market, quantity, rate) if not Data['success']: print(Data['message']) return Data['success']
def bittrex_buy_limit(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.buy_limit(**params) print(result) return result except Exception as e: print(e)
from bittrex.bittrex import Bittrex bit = Bittrex(api_key='748fdc31633644849231b13a9f2cafdd', api_secret='25e3129bc6ed4cf3b3d7beaebfc4914e') # Only one instance is ok # Function get_markets #market_list = bit.get_markets() # Uncomment next line to print # print(market_list) # Ticker list example #firs_market = market_list['result'][0]['MarketName'] #ticker_for_the_first_market = bit.get_ticker('BTC-CRAVE') #print (ticker_for_the_first_market) # Buy limit example limit = bit.buy_limit('BTC-CRAVE', float(0.1) , float(2.1)) print(limit)
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 BittrexService(ServiceInterface): name = 'bit' def __init__(self, **kwargs): api_key = kwargs["api_key"] api_secret = kwargs["api_secret"] if not all([api_key, api_secret]): raise Exception( f"Both api_key and api_secret are required for {name} exchange") self.client = Bittrex(api_key, api_secret, API_V1_1) self.debug_mode = environ.get("DEBUG", False) def get_account(self): return self.client.get_account() def buy(self, coin_name, quantity=None, pair_base="BTC", amount=None, order_type="market"): try: symbol = f"{pair_base}-{coin_name}" price = self.get_price(symbol) quantity = self.calculate_buy_qty(price, amount) logger.info( f"buy order request:{symbol}>price:{price}>quantity:{quantity} > order_type: {order_type}") if order_type.lower() == "market": order = self.client.buy_market( market=symbol, quantity=quantity) elif order_type.lower() == "market": order = self.client.buy_limit( market=symbol, quantity=quantity, rate=price) logger.info( f"Bought order request:{symbol}>price:{price}>quantity:{quantity}> {order}") return order except Exception as ex: logger.error(ex, exc_info=True) raise UserAdviceException(ex) def sell(self, coin_name, quantity=None, pair_base="BTC", amount=None, order_type="market"): try: balance = self.get_balance(coin_name) if not balance: raise UserAdviceException( f"Balance not enough to execute action in {name} exchange") symbol = f"{pair_base}-{coin_name}" price = self.get_price(symbol) quantity = self.calculate_sell_qty(price, amount) logger.info( f"sell order request:{symbol}>price:{price}>quantity:{quantity} > order_type: {order_type}") if order_type.lower() == "market": order = self.client.sell_market( market=symbol, quantity=quantity) elif order_type.lower() == "market": order = self.client.sell_limit( market=symbol, quantity=quantity, rate=price) logger.info( f"Bought order request:{symbol}>price:{price}>quantity:{quantity}> {order}") return order except Exception as ex: logger.error(ex, exc_info=True) raise UserAdviceException(ex) def get_step_size(self, symbol): try: pass except Exception as ex: logger.error("Error retriving step size") return float(0.0) def get_price(self, symbol): try: price_info = self.client.get_ticker(market=symbol) logger.info(f"Price info: {price_info}") return float(price_info.get("price")) except Exception as ex: logger.error(ex, exc_info=True) raise Exception(ex) def calculate_sell_qty(self, price, amount, step_size=None): quantity = float(amount)/float(price) return float(quantity) def calculate_buy_qty(self, price, amount, step_size=None): quantity = float(amount)/float(price) return float(quantity) def get_balance(self, coin_name): pass try: balance_info = self.client.get_balance(coin_name) if not balance_info: raise UserAdviceException( f"Coin not found in account in {self.name} exchange") if not balance_info.get("success"): raise Exception(balance_info.get("message")) result = balance_info.get("result") return float(result.get("Available")) except Exception as ex: logger.error(ex, exc_info=True) raise Exception(ex) def track_coin(self, payload): pass def get_prices(self): pass def get_symbol_info(self, coin_name, pair_base="BTC"): try: market = f"{pair_base}-{coin_name}" info = self.client.get_market_summary(market=market) logger.info(f"Symbol info: {info}") return info except Exception as ex: logger.error(ex, exc_info=True) raise Exception(ex) def get_open_orders(self, coin_name, pair_base="BTC"): try: market = f"{pair_base}-{coin_name}" orders = self.client.get_open_orders(market=market) logger.info(f"orders: {orders}") return orders except Exception as ex: logger.error(ex, exc_info=True) raise Exception(ex) def get_all_orders(self, coin_name, limit=5, pair_base="BTC"): try: market = f"{pair_base}-{coin_name}" orders = self.client.get_order_history(market=market, limit=limit) logger.debug(f"orders: {orders}") return orders except Exception as ex: logger.error(ex, exc_info=True) raise Exception(ex)
# Initialize bittrex api api = Bittrex(API_KEY, API_SECRET, api_version=API_V1_1) # Open position logic: # 1. Get market last ask price r = api.get_ticker(market) if not r.get('success', False): raise Exception("Got an error while querying broker: %s" % r.get('message', 'nd')) ticker = r.get('result') # 2. Buy with args.total value _quantity = args.total / ticker.get('Ask', 0) _rate = ticker.get('Ask', 0) r = api.buy_limit(market, quantity=_quantity, rate=_rate) if not r.get('success', False): raise Exception("Could not open position on broker: %s" % r.get('message', 'nd')) open_order_id = r.get('result', {}).get('uuid', None) elif args.exchange == 'binance': market = "%s%s" % (args.market_currency, args.market_base) # Initialize binance api api = Binance(API_KEY, API_SECRET) # Is binance alive ? if api.get_system_status().get("status", -1) != 0: raise Exception("Exchange unavailable for trading")
class BittrexApiClient(BaseTradeApiClient): PAIR_NAME_TEMPLATE = '{quote}-{base}' def __init__(self): super(BittrexApiClient, self).__init__() self.related_nodes = ['api3'] self.api = self.get_api() def _get_api_currency_code(self, currency_code): return currency_code def _get_currency_by_api_code(self, api_currency_code): return Currency.objects.get(code=api_currency_code) def get_api_pairs_for_pair(self, pair): reverse_pair = pair.reverse_pair markets = self.get_all_active_pairs() for _pair in pair, reverse_pair: _name = self.get_api_pair_name(_pair) if _name in markets: return { _pair: { 'api_pair_name': _name, 'main_currency': self._get_currency_by_api_code(markets[_name]) } } base_btc = Pair.objects.get(base=pair.base, quote__code='BTC') quote_btc = Pair.objects.get(base=pair.quote, quote__code='BTC') res = {} for _pair in base_btc, quote_btc: _name = self.get_api_pair_name(_pair) if _name in markets: res.update({ _pair: { 'api_pair_name': _name, 'main_currency': self._get_currency_by_api_code(markets[_name]) } }) return res def get_api_pair_name(self, pair): return self.PAIR_NAME_TEMPLATE.format( base=self._get_api_currency_code(pair.base.code), quote=self._get_api_currency_code(pair.quote.code)) def get_all_active_pairs(self): markets = self.api.get_markets().get('result', []) return { m.get('MarketName'): m.get('MarketCurrency') for m in markets if m['IsActive'] } def get_api(self): if not self.api: self.api = Bittrex(settings.API3_KEY, settings.API3_SECRET) return self.api def get_balance(self, currency): raw_res = self.api.get_balance( self._get_api_currency_code(currency.code)) result = raw_res.get('result', {}) res = { key.lower(): Decimal(str(value if value else 0)) for key, value in result.items() if key in ['Pending', 'Balance', 'Available'] } return res def get_ticker(self, pair): market = self.PAIR_NAME_TEMPLATE.format( base=self._get_api_currency_code(pair.base.code), quote=self._get_api_currency_code(pair.quote.code)) res = self.api.get_ticker(market) return res def get_rate(self, pair, rate_type='Ask'): ticker = self.get_ticker(pair) rate = ticker.get('result', {}).get(rate_type, 0) return Decimal(str(rate)) def buy_limit(self, pair, amount, rate=None): market = self.PAIR_NAME_TEMPLATE.format( base=self._get_api_currency_code(pair.base.code), quote=self._get_api_currency_code(pair.quote.code)) if not rate: rate = self.get_rate(pair, rate_type='Ask') res = self.api.buy_limit(market, amount, rate) trade_id = res.get('result', {}).get('uuid') return trade_id, res def sell_limit(self, pair, amount, rate=None): market = self.PAIR_NAME_TEMPLATE.format( base=self._get_api_currency_code(pair.base.code), quote=self._get_api_currency_code(pair.quote.code)) if not rate: rate = self.get_rate(pair, rate_type='Bid') res = self.api.sell_limit(market, amount, rate) trade_id = res.get('result', {}).get('uuid') return trade_id, res def get_main_address(self, currency): raw_res = self.api.get_deposit_address( self._get_api_currency_code(currency.code)) result = raw_res.get('result', {}) address = result.get('Address', None) return address if address else None def release_coins(self, currency, address, amount): tx_id = None if isinstance(currency, Currency): currency = currency.code if isinstance(address, Address): address = address.address _currency = self._get_api_currency_code(currency) res = self.api.withdraw(_currency, amount, address) self.logger.info('Response from Bittrex withdraw: {}'.format(res)) success = res.get('success', False) if success: tx_id = res.get('result', {}).get('uuid') return tx_id, success
class BittrexBroker(BrokerBaseClass): """ Inherits from alchemist_lib.broker.broker.BrokerBaseClass. Website: https://bittrex.com/ Api documentation: https://bittrex.com/Home/Api Api wrapper: https://github.com/ericsomdahl/python-bittrex Attributes: session (sqlalchemy.orm.session.Session): Database connection. bittrex (bittrex.bittrex.Bittrex): Communication object. """ def __init__(self, api_key=None, secret_key=None): """ Costructor method. Args: api_key (str): The api key provided by Bittrex. secret_key (str): The secret key provided by Bittrex. Note: https://bittrex.com/Manage#sectionApi https://cryptocatbot.com/api-key-activation-exchanges/ """ BrokerBaseClass.__init__(self) self.bittrex = Bittrex(api_key=api_key, api_secret=secret_key, api_version=API_V1_1) def get_best_rate(self, asset, amount, field): """ Bittrex doesn't allow to place market orders submitted via API so we need to get the best bid/ask price for every order. Args: asset (alchemist_lib.database.asset.Asset): The asset we want to exchange for BTC or vice versa. amount (decimal.Decimal): The amount we want to exchange. field (str): Must be "ask" or "bid". Return: price (decimal.Decimal): The best bid/ask, executing an order at this price is like submit a market order. If the book is too thin the return value is 0. """ amount = abs(amount) pair = "BTC-{}".format(asset.ticker) if field == "ask": book = self.bittrex.get_orderbook(market=pair, depth_type=SELL_ORDERBOOK) if book["success"] == False or book["result"] == None: logging.debug( "Bittrex api result is None or success is False. get_best_rate() method. Asset: {}" .format(asset.ticker)) return Decimal(0) else: book = self.bittrex.get_orderbook(market=pair, depth_type=BUY_ORDERBOOK) if book["success"] == False or book["result"] == None: logging.debug( "Bittrex api result is None or success is False. get_best_rate() method. Asset: {}" .format(asset.ticker)) return Decimal(0) values = book["result"] orders_sum = Decimal(0) for book_item in values: orders_sum += Decimal(book_item["Quantity"]) if orders_sum > amount: return Decimal(book_item["Rate"]) return Decimal(0) def place_order(self, asset, amount, order_type): """ Places an order for a specific asset on Bittrex. Args: asset (alchemist_lib.database.asset.Asset): The asset we want exchange for BTC. amount (decimal.Decimal): The amount we want to exchange. order_type (str): Type of order. Return: order_id (str, int): Order identifier, if some errors occur it returns int(-1). """ pair = "BTC-{}".format(asset.ticker) min_order_size = BittrexExchange().get_min_order_size(asset=asset) logging.debug("Min order size for {} is {}".format( asset, min_order_size)) if amount > min_order_size: field = "ask" operation = "buy" elif amount < (min_order_size * (-1)): field = "bid" operation = "sell" else: return -1 if order_type == "MKT": rate = self.get_best_rate(asset=asset, amount=abs(amount), field=field) else: logging.critical("Unknown order type. NotImplemented raised.") raise NotImplemented("Unknown order type. NotImplemented raised.") logging.debug("Order: Pair: {}. Amount: {}. Operation: {}".format( pair, amount, operation)) if operation == "buy": order_return_dict = self.bittrex.buy_limit(market=pair, rate=rate, quantity=amount) else: order_return_dict = self.bittrex.sell_limit(market=pair, rate=rate, quantity=abs(amount)) if order_return_dict["result"] == None: logging.warning( "Bittrex api result is None or success is False. place_order() method. Order id will be -1. Asset: {}" .format(asset.ticker)) return -1 order_id = str(order_return_dict["result"]["uuid"]) logging.info( "{} order placed for {}. Amount: {}. Order id: {}.".format( operation.upper(), asset.ticker, amount, order_id)) print("{} order placed for {}. Amount: {}. Order id: {}.".format( operation.upper(), asset.ticker, amount, order_id)) order = ExecutedOrder(order_id=order_id, order_datetime=dt.datetime.utcnow(), ticker=asset.ticker, instrument_id=asset.instrument_id, amount=amount, operation=operation, order_type=order_type, broker_name="bittrex", exchange_name="bittrex") self.session.add(order) self.session.commit() return order_id
amount_alis = islem_ucreti / bs # alinacak coin miktari amount_satis = amount_alis * 0.9975 # satilacak coin miktari cuzdan_kontrol = 1 except: cuzdan_kontrol = 0 continue if cuzdan_kontrol == 1: if btrxavantaj > zorluk and btrx_wallet > islem_ucreti and polo_wallet_c * pa > islem_ucreti: try: pa = pa * (1 - (kayip + (btrxavantaj - zorluk)) / 1000) bs = bs * (1 + (kayip + (btrxavantaj - zorluk)) / 1000) polo.sell(poloniex_currency, pa, amount_satis) order_s = my_bittrex.buy_limit(bittrex_currency, amount_alis, bs) print btrxavantaj, "\tBITTREX ALIS\t", bs, "\n\t\tPOLO SATIS\t", pa print datetime.now().strftime('%Y-%m-%d %H:%M:%S') # emir kontrolu. islem sonra devam edecek (bittrex) while True: try: kontrol = my_bittrex.get_order( order_s['result']['uuid']) if kontrol['result']['IsOpen'] == False: print "bittrex alim emri gerceklesti" break except: print "bittrex alim emir kontrol hatasi"
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
bitfinex_instance.place_order(amount=trade_size, price=None, side="buy", ord_type="market", symbol=pairname) if exchange == "BITTREX": print("Acquiring " + str(trade_size) + " " + currency + " on " + exchange) if not test: pairname = transfer_currency + "-" + currency ## market orders are disabled for bittrex, we will use a limit order to cross the spread buy_price = float( bittrex_instance.get_ticker( market=pairname)['result']['Ask']) bittrex_instance.buy_limit(market=pairname, quantity=trade_size, rate=buy_price) # make market order at trade_size, base transfer_currency # save the orders to csv #As the transfer & one investment coin is the same, we do not buy 10% ETH, we buy 60% ETH and than send it as above described to Bitfinex and Bittrex. #As soon as the ETH arrives there the buy actions above will be made. ## the script will account for the optimal/actual balances each time it is run, triggering will have to come from elsewhere #Time of every transaction including it's fees and prices must be stored into the database. The price should be stored in both the base currency and the actual used coin (note - e.g. IOTA must be bought from EUR->ETH->IOTA) so I need the price EUR/IOTA & ETH/IOTA. ## we have no way to track transactions since they have to be cleared on the exchange before we can get any info about them ## so the prices/stats that you want will have to be collected and attributed after-the-fact since they are not returned at the time of orders ## for now we are using market orders, but would recommend switching to limit orders for safety asap #Please also provide a ready to use installation how to get this installed on a local docker.