Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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'])
Ejemplo n.º 3
0
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"]}'
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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))
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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('_', '-'))
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)))
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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))
Ejemplo n.º 12
0
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