示例#1
0
class order_api(object):

	def __init__(self):
		self.client = Client("KCl8UvtnFcrlEgpqiwJlA0dr2SM3DuhKHHxiRtHA8oe7yl0JZYqas8oN2XNK0Lfz", "2wj46v8IAKpXoeigAmzfPg1VEjYi3oItNTeeNcEkDrK1HIev4nZHJr1Cd8tiJ5L0", {"verify": True, "timeout": 20})

	def get_all_orders(self,symbol='VENETH',limit=10):
		return self.get_all_orders(symbol,limit)

	# def create_order(self, symbol='VENETH', side='BUY', type=ORDER_TYPE_LIMIT, timeInForce=TIME_IN_FORCE_GTC, quantity=100, price='0.00001'):
		# self.client.create_order(symbol,side,type,timeInForce,quantity,price)

	# def create_sell_limit_order(self):
		# self.order = client.order_limit_buy(symbol,quantity,price)

	# def create_market_order(self):
		# pass

	def create_test_order(self,symbol,quantity,price):
		return self.client.create_test_order(symbol=symbol,quantity=quantity,price=price,side='BUY',type='LIMIT',timeInForce='GTC')

	def get_all_orders(self,symbol='VENETH'):
		return self.client.get_all_orders(symbol=symbol)

	def get_open_orders(self,symbol='VENETH'):
		return self.client.get_open_orders(symbol=symbol)

	def cancel_order(self,symbol='VENETH',orderId=0):
		return self.client.cancel_order(symbol=symbol,orderId=orderId)

	def order_status(self,symbol='VENETH',orderId=0):
		return self.client.get_order(symbol=symbol,orderId=orderId)
示例#2
0
def CANCEL_OPEN_ORDERS(LOG,univ,out_file):

	LOG.write(TimeStamp() + "CANCEL_OPEN_ORDERS\n")

	try:
		client = Client(api_key, api_secret)

	except BinanceAPIException as e:
		print(e.status_code)
		print(e.message)

	F = open(out_file,'w')
	F.write(TimeStamp() + "\n")
	for u in univ:
		if (u == "BTC"):
			continue
		try:
			sym = u + "BTC"
			#print(sym)
			data = client.get_open_orders(symbol=sym)
			if data is None:
				continue
			for T in data:
				TS = TimeStampUnixDateTime(T['time'])
				S = 'Order:\n'
				F.write(S)
				S = '\tSymbol:   \t%s\t%s\n' % (u,sym)
				F.write(S)
				S = '\tQty:      \t%s\n' % (T['origQty'])
				F.write(S)
				S = '\tPrice:    \t%s\n' % (T['price'])
				F.write(S)
				S = '\tOrder Id: \t%s\n\n' % (T['orderId'])
				F.write(S)

				try:
					RV = client.cancel_order(symbol=sym,orderId=T['orderId'])
					if (RV):
						S = 'Return Value:\n'
						F.write(S)
						S = '\tSymbol:              \t%s\n' % (RV['symbol'])
						F.write(S)
						S = '\torigClientOrderId:	\t%s\n' % (RV['origClientOrderId'])
						F.write(S)
						S = '\torderId:	            \t%s\n' % (RV['orderId'])
						F.write(S)
						S = '\tclientOrderId:	    \t%s\n\n\n' % (RV['clientOrderId'])
						F.write(S)
				
				except BinanceAPIException as e:
					print(e.status_code)
					print(e.message)
					LOG.write(e.message + "\n")

		except BinanceAPIException as e:
			print(e.status_code)
			print(e.message)
			LOG.write(e.message + "\n")

	F.close()
示例#3
0
class _Binance(Exchange):
    def __init__(self, key="", secret=""):
        super(_Binance, self).__init__("binance", key, secret, "")
        self.client = Client(key, secret)

    def __transfer_symbol(self, s):
        return s.replace("_", "").upper()

    def fetch_depth(self, symbol):
        symbol = self.__transfer_symbol(symbol)
        return self.client.get_order_book(symbol=symbol)

    def account(self):
        data = self.client.get_account()
        return self._parse_account(data)

    def _parse_account(self, data):
        acc = Account(self)
        for x in data['balances']:
            coin = x['asset'].lower()
            freeze = float(x['locked'])
            avail = float(x['free'])
            if freeze > 0 or avail > 0:
                acc.set_avail(coin, avail).set_freeze(coin, freeze)
        return acc

    def order(self, symbol, side, type="limit", amount=None, price=None):
        assert type == 'limit'  # 暂时支持limit
        assert side in self.TRADE_SIDE

        symbol = self.__transfer_symbol(symbol)
        if side == 'buy':
            return self.client.order_limit_buy(symbol=symbol, quantity=amount, price=price)['orderId']
        else:
            return self.client.order_limit_sell(symbol=symbol, quantity=amount, price=price)['orderId']

    def order_info(self, symbol, order_id):
        data = self.client.get_order(symbol=self.__transfer_symbol(symbol), orderId=order_id)
        return self._parse_order(data)

    def _parse_order(self, data):
        return data

    def cancel_order(self, symbol, order_id):
        self.client.cancel_order(symbol=self.__transfer_symbol(symbol), orderId=order_id)
        return True
示例#4
0
def execute_trades(api_object, trade_df):
    '''
    :param api_object: binance api object
    param trade_df: pandas DataFrame with index ticker, columns Market (string), price(float, in BTC),
        Curr_Dist(float, [0,1]), Target_Dist(float,[0,1]),Trade_Perc(float,[-1,1]), Trade_Amt (in BTC,float),
        Trade_Amt_Coin (float, in the target currency)
    '''
    for coin, row in trade_df.iterrows():
        try:
            #close any open orders
            open_orders = api_object.get_open_orders(symbol=row.market)
            market = row.market
            #Binance only allows certain order sizes by coin
            trade_amt = round(row.Trade_Amt_Coin, 6)
            buy = bool(trade_amt > 0)
            sell = bool(trade_amt < 0)
            trade_amt = abs(trade_amt)
            #filter to make sure in tick size increments above min trade size
            market_lot_size_info = api_object.get_symbol_info(
                market)['filters'][1]
            trade_amt -= (trade_amt - float(market_lot_size_info['minQty'])
                          ) % float(market_lot_size_info['stepSize'])
            if trade_amt <= 0:
                continue
            if open_orders:
                print('Cancelling open orders for {}.'.format(coin))
                for order in open_orders:
                    api_object.cancel_order(symbol=market,
                                            orderId=order['orderId'])
            if buy:
                print('Buying {} of {}'.format(trade_amt, coin))
                print(
                    api_object.order_market_buy(symbol=market,
                                                quantity=trade_amt))
            elif sell:
                print('Selling {} of {}'.format(trade_amt, coin))
                print(
                    api_object.order_market_sell(symbol=market,
                                                 quantity=trade_amt))
        except Exception as e:
            print(e)
示例#5
0
def binance_cancel_order(chat_id, **params):
    full_api = getbinanceapi(chat_id)['binance_api']
    api_key = full_api.split(':')[0].strip()
    api_secret = full_api.split(':')[1].strip()
    client = Client(api_key, api_secret)
    binance_timesync(client)
    try:
        js_info = client.cancel_order(**params)
        print(js_info)
        return js_info
    except Exception as e:
        print(e)
示例#6
0
def cancel_order(request):
    if request.method == 'POST':
        symbol = request.POST.get("symbol")
        order_id = request.POST.get("order_id")

        api_key = request.user.apikey
        api_secret = request.user.Secret
        client = Client(api_key, api_secret)

        cancel_order = Order.objects.get(orderId=order_id)
        try:
            ifo = client.cancel_order(symbol=symbol, orderId=order_id)
            if ifo["orderId"]:
                cancel_order.status = 'CANCELED'
                response = {'orderId': ifo["orderId"]}

        except BinanceAPIException:
            ifo = client.get_order(symbol=symbol, orderId=order_id)
            cancel_order.status = ifo['status']
            response = {'aa': "失败!", "status": ifo['status']}

        cancel_order.save()
        return JsonResponse(response)
示例#7
0
class TradingPortfolio():
    """Connect Binance account.

    The core class to connect Binance  with API, in order to connect account info,
    register strategt.

    Attributes:
        binance_key: A str of is binance authorization key.
        binance_secret: A str of is binance authorization secret.

    """
    def __init__(self, binance_key, binance_secret, execute_before_candle_complete=False):
        self._client = Client(api_key=binance_key, api_secret=binance_secret)
        self._trading_methods = []
        self._margins = {}
        self.ticker_info = TickerInfo(self._client)
        self.default_stable_coin = 'USDT'
        self.execute_before_candle_complete = execute_before_candle_complete

    def set_default_stable_coin(self, token):
        self.default_stable_coin = token

    def register(self, trading_method):
        """Rigister TradingMethod object.
        Args:
          trading_method: A object of TradingMethod().
        """

        if trading_method.execution_price == 'open' and self.execute_before_candle_complete:
            raise Exception("Detect execute_before_candle_complete=True and trading_method.execution_price is open"
                    + "Please set trading_method.execute_before_candle_complete to False"
                    + " and execute live trading right after candles are complete.")

        self._trading_methods.append(trading_method)

    def register_margin(self, asset, weight_btc):
        """Rigister weight_btc as operation amount.
        Args:
          asset: A str of asset name (ex: 'USDT')
          weight_btc: A float of btc for each commodity operation (ex: 0.2)
        """
        self._margins[asset] = weight_btc

    def get_all_symbol_lookback(self):
        """Get all symbol lookback.
        Use in get_ohlcvs(self) function.
        Returns:
            A dict of OHLCV lookback.

        """
        symbol_lookbacks = {}
        addition = {}

        weight_units = set()
        max_lookback = 0

        for method in self._trading_methods:
            weight_units.add((method.weight_unit, method.freq))
            max_lookback = max(max_lookback, method.lookback)
            for a in method.symbols:

                quote_asset = self.ticker_info.get_quote_asset(a)
                base_asset = self.ticker_info.get_base_asset(a)
                if (a, method.freq) not in symbol_lookbacks or method.lookback > symbol_lookbacks[(a, method.freq)]:
                    symbol_lookbacks[(a, method.freq)] = method.lookback

                if base_asset != method.weight_unit:
                    new_symbol = base_asset + method.weight_unit
                    if (new_symbol, method.freq) not in addition or method.lookback > addition[(new_symbol, method.freq)]:
                        addition[(new_symbol, method.freq)] = method.lookback

        for w, f in weight_units:
            if w != 'BTC':
                addition[('BTC' + w, f)] = max_lookback

        # add quote asset historical data
        # for (symbol, freq), lookback in symbol_lookbacks.items():
        #     base_asset = self.ticker_info.get_base_asset(symbol)
        #     if base_asset != self.quote_asset:
        #         new_symbol = base_asset + self.quote_asset
        #         addition[(new_symbol, freq)] = lookback

        return {**symbol_lookbacks, **addition}

    def get_ohlcvs(self):
        """Getting histrical price data through binance api.

        Returns:
            A DataFrame of OHLCV data , the number of data length is lookback.

        """
        symbol_lookbacks = self.get_all_symbol_lookback()

        ohlcvs = {}
        for (symbol, freq), lookback in symbol_lookbacks.items():
            ohlcvs[(symbol, freq)] = get_nbars_binance(symbol, freq, lookback, self._client)

        return ohlcvs

    def get_full_ohlcvs(self):
        """Getting all histrical price data through binance api.

        Returns:
            A DataFrame of OHLCV data for all.

        """
        symbol_lookbacks = self.get_all_symbol_lookback()
        ohlcvs = {}

        for (symbol, freq), lookback in symbol_lookbacks.items():
            ohlcvs[(symbol, freq)] = get_all_binance(symbol, freq)
            time.sleep(3)
        return ohlcvs

    def get_latest_signals(self, ohlcvs, html=False):
        """Get latest signals dataframe.

        Choose which strategy to implement on widgets GUI.

        Args:
          ohlcvs: A dataframe of symbel.
          html: A bool of controlling html generation.

        Returns:
          A dataframe of latest_signals data,
          The last_signals column is bool value of whether to execute the transaction.
          The value_in_btc column is present value of assets.
        """
        ret = []
        for method in self._trading_methods:
            for symbol in method.symbols:
                ohlcv = ohlcvs[(symbol, method.freq)].copy()

                # remove incomplete candle
                if self.execute_before_candle_complete == False and method.execution_price == 'close':
                    t = datetime.datetime.utcnow().replace(tzinfo=timezone.utc)
                    delta_t = ohlcv.index[-1] - ohlcv.index[-2]
                    ohlcv = ohlcv.loc[:t-delta_t]

                htmlname = f'{symbol}-{method.freq}-{method.name}.html' if html else None
                result = method.strategy.backtest(ohlcv,
                                                  method.variables, filters=method.filters, plot=html,
                                                  html=htmlname,
                                                  freq=method.freq, fees=0., slippage=0., execution_price=method.execution_price)

                signal = result.cash().iloc[-1] == 0
                return_ = 0

                # find weight if it is in the nested dictionary
                weight = method.weight
                if isinstance(weight, dict):
                    weight = (weight[symbol]
                        if symbol in weight else weight['default'])

                entry_price = 0
                entry_time = 0
                value_in_btc = 0
                trade_price_type = method.execution_price
                if signal:
                    txn = result.positions().records
                    rds = result.orders().records
                    return_ = ohlcv[trade_price_type].iloc[-1] / rds['price'].iloc[-1] - 1
                    entry_price = rds['price'].iloc[-1]
                    entry_time = ohlcv.index[int(rds.iloc[-1]['idx'])]

                    base_asset = self.ticker_info.get_base_asset(symbol)
                    quote_asset = self.ticker_info.get_quote_asset(symbol)

                    if base_asset != method.weight_unit:
                        quote_symbol = base_asset + method.weight_unit
                        quote_history = ohlcvs[(quote_symbol, method.freq)]
                        quote_asset_price_previous = quote_history[trade_price_type].loc[entry_time]
                        quote_asset_price_now = quote_history[trade_price_type].iloc[-1]
                    else:
                        quote_asset_price_previous = 1
                        quote_asset_price_now = 1

                    if method.weight_unit != 'BTC':
                        btc_quote_price_previous = ohlcvs[('BTC' + method.weight_unit, method.freq)][trade_price_type].loc[entry_time]
                        btc_quote_price_now = ohlcvs[('BTC' + method.weight_unit, method.freq)][trade_price_type].iloc[-1]
                    else:
                        btc_quote_price_previous = 1
                        btc_quote_price_now = 1

                    previous_weight_btc = (weight / btc_quote_price_previous)
                    value_in_btc = previous_weight_btc / quote_asset_price_previous * quote_asset_price_now / (btc_quote_price_now / btc_quote_price_previous)
                    weight_btc = previous_weight_btc
                    previous_price_btc = quote_asset_price_previous  / btc_quote_price_previous
                    present_price_btc = quote_asset_price_now  / btc_quote_price_now
                    amount = previous_weight_btc / previous_price_btc
                    present_amount = value_in_btc / present_price_btc
                    assert 0.9999 < amount / present_amount < 1.0001

                else:
                    if method.weight_unit != 'BTC':
                        btc_quote_price_now = ohlcvs[('BTC' + method.weight_unit, method.freq)][trade_price_type].iloc[-1]
                    else:
                        btc_quote_price_now = 1

                    weight_btc = weight / btc_quote_price_now
                    amount = 0

                ret.append({
                    'symbol': symbol,
                    'method name': method.name,
                    'latest_signal': signal,
                    'weight_btc': weight_btc,
                    'freq': method.freq,
                    'return': return_,
                    'amount': amount,
                    'value_in_btc': value_in_btc * signal,
                    'latest_price': ohlcv[trade_price_type].iloc[-1],
                    'entry_price': entry_price,
                    'entry_time': entry_time,
                    'html': htmlname,
                })

        ret = pd.DataFrame(ret)
        return ret

    def calculate_position_size(self, signals, rebalance_threshold=0.03, excluded_assets=list()):
        """Calculate the proportion of asset orders.

        Calculate data is based on latest signals dataframe.

        Args:
          signals: A dataframe of signals.
          rebalance_threshold: A float of rebalance_threshold.
          excluded_assets: A list of asset name which are excluded calculation.

        Returns:
          diff_value: A dataframe of how many assets to deposit for each cryptocurrency.
          diff_value_btc: A dataframe of converting cryptocurrency to BTC.
          transaction: A dataframe of transaction(new order) data.
        """
        if self.default_stable_coin not in excluded_assets:
            excluded_assets.append(self.default_stable_coin)

        signals['base_asset'] = signals.symbol.map(self.ticker_info.get_base_asset)
        signals['quote_asset'] = signals.symbol.map(self.ticker_info.get_quote_asset)
        signals['base_value_btc'] = signals.latest_signal * signals.value_in_btc
        signals['quote_value_btc'] = -(signals.latest_signal.astype(int) * signals.weight_btc)

        quote_asset_list = list(set(signals.quote_asset))

        # calculate base and quote assets (in btc term)
        base_asset_value = pd.Series(signals.base_value_btc.values, index=signals.base_asset)
        quote_asset_value = pd.Series(signals.quote_value_btc.values, index=signals.quote_asset)
        base_asset_value = base_asset_value.groupby(level=0).sum()
        quote_asset_value = quote_asset_value.groupby(level=0).sum()

        # get position
        position = pd.Series({i['asset']: i['free'] for i in self.ticker_info.info['balances']
                              if float(i['free']) != 0}).astype(float)
        position = position[position.index.str[:2] != 'LD']

        # refine asset index
        all_assets = base_asset_value.index | quote_asset_value.index | position.index

        base_asset_value = base_asset_value.reindex(all_assets).fillna(0)
        quote_asset_value = quote_asset_value.reindex(all_assets).fillna(0)
        position = position.reindex(all_assets).fillna(0)

        # calculate algo value
        algo_value_in_btc = base_asset_value + quote_asset_value
        asset_price_in_btc = position.index.map(self.ticker_info.get_asset_price_in_btc)
        algo_value = algo_value_in_btc / asset_price_in_btc

        # calculate diffierence
        margin_position = pd.Series(self._margins).reindex(all_assets).fillna(0)

        diff_value_btc = pd.DataFrame({
            'algo_p': algo_value_in_btc,
            'margin_p': margin_position * asset_price_in_btc,
            'estimate_p': algo_value_in_btc + margin_position * asset_price_in_btc,
            'present_p': position * asset_price_in_btc,
            'difference': (algo_value_in_btc + margin_position * asset_price_in_btc).clip(0,None) - position * asset_price_in_btc,
            'rebalance_threshold': (algo_value_in_btc + margin_position * asset_price_in_btc).abs() * rebalance_threshold,
        })
        diff_value_btc['rebalance'] = diff_value_btc['difference'].abs() > diff_value_btc['rebalance_threshold']
        diff_value_btc.loc[quote_asset_list, 'rebalance'] = True

        # excluding checking of asset positions

        excluded = pd.Series(True, diff_value_btc.index)
        excluded[diff_value_btc.index.isin(signals.quote_asset) | diff_value_btc.index.isin(signals.base_asset)] = False
        excluded[diff_value_btc.index.isin(excluded_assets)] = True

        diff_value_btc['excluded'] = excluded

        diff_value = diff_value_btc.copy()
        diff_value = diff_value.div(asset_price_in_btc, axis=0)
        diff_value.rebalance = diff_value.rebalance != 0
        diff_value.excluded = diff_value.excluded != 0

        # calculate transactions

        rebalance_value_btc = diff_value_btc.rebalance * diff_value_btc.difference * (~diff_value_btc.excluded)
        increase_asset_amount = rebalance_value_btc[rebalance_value_btc > 0]
        decrease_asset_amount = rebalance_value_btc[rebalance_value_btc < 0]

        diff_value_btc['rebalance'] = diff_value_btc['difference'].abs() > diff_value_btc['rebalance_threshold']
        diff_value['rebalance'] = diff_value_btc.rebalance

        txn_btc = {}

        for nai, ai in increase_asset_amount.items():
            for nad, ad in decrease_asset_amount.items():

                symbol = nad + nai
                amount = min(-ad, ai)

                is_valid = self.ticker_info._list_select(self.ticker_info.tickers, 'symbol',
                                                         symbol) is not None and nai in quote_asset_list

                if is_valid:
                    increase_asset_amount.loc[nai] -= amount
                    decrease_asset_amount.loc[nad] += amount
                    txn_btc[symbol] = -amount
                    continue

                symbol = nai + nad
                is_valid = self.ticker_info._list_select(self.ticker_info.tickers, 'symbol',
                                                         symbol) is not None and nad in quote_asset_list

                if is_valid:
                    increase_asset_amount.loc[nai] -= amount
                    decrease_asset_amount.loc[nad] += amount
                    txn_btc[symbol] = amount
                    continue

        # assumption: self.default_stable_coin can be the quote asset for all alt-coins
        transaction_btc = increase_asset_amount.append(decrease_asset_amount)
        transaction_btc.index = transaction_btc.index + self.default_stable_coin

        if self.default_stable_coin in transaction_btc.index:
            transaction_btc.pop(self.default_stable_coin+self.default_stable_coin)

        transaction_btc = transaction_btc.append(pd.Series(txn_btc))

        transaction = transaction_btc.to_frame(name='value_in_btc')

        transaction['base_asset'] = transaction.index.map(self.ticker_info.get_base_asset)
        transaction['quote_asset'] = transaction.index.map(self.ticker_info.get_quote_asset)
        transaction['value'] = transaction['value_in_btc'] / transaction.base_asset.map(
            self.ticker_info.get_asset_price_in_btc)
        transaction['price'] = transaction.index.map(
            lambda s: self.ticker_info._list_select(self.ticker_info.tickers, 'symbol', s)['price'])
        transaction = transaction.groupby(level=0).agg(
            dict(value_in_btc='sum', value='sum', base_asset='first', quote_asset='first', price='first'))
        transaction = transaction[transaction.value != 0]

        # check difference after transaction
        def asset_distributed(v):
            asset_increase = v.value_in_btc.groupby(v.base_asset).sum()
            asset_decrease = v.value_in_btc.groupby(v.quote_asset).sum()
            return asset_increase.reindex(all_assets).fillna(0) - asset_decrease.reindex(all_assets).fillna(0)

        verify_assets = asset_distributed(transaction)
        verify_assets = verify_assets[verify_assets != 0]
        verify = (verify_assets / diff_value_btc.difference.reindex(verify_assets.index) - 1).abs() < 0.001

        try:
            assert verify[verify.index != self.default_stable_coin].all()
        except:
            print(diff_value_btc)
            print(transaction)
            print(verify_assets)
            print(verify)
            raise Exception("validation fail")

        # filter out orders where base asset is in quote asset list (ex: btcusdt)
        # assumption: base asset should only be paired by one quote asset
        transaction = transaction[~(transaction.base_asset.isin(quote_asset_list) & (
                    transaction.value_in_btc.abs() < diff_value_btc.loc[
                transaction['base_asset']].rebalance_threshold.values))]

        # verify diff_value
        def get_filters(exinfo, symbol):
            filters = self.ticker_info._list_select(self.ticker_info.exinfo['symbols'], 'symbol', symbol)['filters']
            min_lot_size = self.ticker_info._list_select(filters, 'filterType', 'LOT_SIZE')['minQty']
            step_size = self.ticker_info._list_select(filters, 'filterType', 'LOT_SIZE')['stepSize']
            min_notional = self.ticker_info._list_select(filters, 'filterType', 'MIN_NOTIONAL')['minNotional']
            return {
                'min_lot_size': min_lot_size,
                'step_size': step_size,
                'min_notional': min_notional,
            }

        filters = pd.DataFrame(
            {s: get_filters(self.ticker_info.exinfo, s) for s in transaction.index}).transpose().astype(float)

        if len(transaction) != 0:
            min_notional = filters.min_notional
            minimum_lot_size = filters.min_lot_size
            step_size = filters.step_size

            # rebalance filter:
            diff = transaction['value']

            # step size filter
            diff = round((diff / step_size).astype(int) * step_size, 9)

            # minimum lot filter
            diff[diff.abs() < minimum_lot_size] = 0

            # minimum notional filter
            diff[diff.abs() * transaction.price.astype(float) < min_notional] = 0

            transaction['final_value'] = diff
            transaction['final_value_in_btc'] = diff * transaction.base_asset.map(
                self.ticker_info.get_asset_price_in_btc)
        else:
            transaction = pd.DataFrame(None, columns=['final_value'])

        transaction = transaction[transaction['final_value'] != 0]

        return diff_value, diff_value_btc, transaction

    def execute_orders(self, transactions, mode='TEST'):
        """Execute orders to Binance.

        Execute orders by program order.

        Args:
          transactions: A dataframe which is generated by transaction in calculate_position_size() function result.
          mode: A str of transactions mode, we have 3 method.
              'TEST' is simulation.
              'MARKET' is market order which is transaction at the current latest price.
              'LIMIT' is The transaction is done at the specified price. If the specified price is not touched,
                      the transaction has not been completed.

        Returns:
            A dataframe of trades.
        """
        def cancel_orders(symbol):
            orders = self._client.get_open_orders(symbol=symbol)
            for o in orders:
                self._client.cancel_order(symbol=symbol, orderId=o['orderId'])

        order_func = self._client.create_order if mode == 'MARKET' or mode == 'LIMIT' else self._client.create_test_order

        print('|---------EXECUTION LOG----------|')
        print('| time: ', datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))

        trades = {}
        for s, lot in transactions.final_value.items():

            cancel_orders(s)

            if lot == 0:
                continue

            side = SIDE_BUY if lot > 0 else SIDE_SELL
            try:
                args = dict(
                    side=side,
                    type=ORDER_TYPE_MARKET,
                    symbol=s,
                    quantity=abs(lot))

                if mode == 'LIMIT':
                    args['price'] = transactions.price.loc[s]
                    args['type'] = ORDER_TYPE_LIMIT
                    args['timeInForce'] = 'GTC'

                order_func(**args)
                order_result = 'success'
                print('|', mode, s, side, abs(lot), order_result)
            except Exception as e:
                print('| FAIL', s, s, side, abs(lot), str(e))
                order_result = 'FAIL: ' + str(e)

            trades[s] = {
                **args,
                'result': order_result,
            }

        return pd.DataFrame(trades).transpose()

    def status(self, ohlcvs):
        """Strategy list widgets.

        Choose which strategy to implement on widgets GUI.

        Args:
          ohlcvs: A dataframe of symbol.

        Returns:
            widget GUI
        """
        import ipywidgets as widgets

        ret = pd.DataFrame()
        full_results = []
        for method in self._trading_methods:
            for symbol in method.symbols:
                ohlcv = ohlcvs[(symbol, method.freq)]
                result = method.strategy.backtest(ohlcv,
                                                  method.variables, filters=method.filters, freq=method.freq)
                ret[method.name + '-' + symbol + '-' + method.freq] = result.cumulative_returns

                weight_btc = method.weight_btc
                if isinstance(weight_btc, dict):
                    weight_btc = (weight_btc[symbol]
                        if symbol in weight_btc else weight_btc['default'])

                full_results.append({
                    'name': method.name,
                    'symbol': symbol,
                    'freq': method.freq,
                    'weight': weight_btc,
                    'portfolio': result,
                    'trading_method': method,
                    'signal': result.cash().iloc[-1] == 0,
                })

        method_dropdown = widgets.Dropdown(options=[m.name + '-' + str(i) for i, m in enumerate(self._trading_methods)])
        symbol_dropdown = widgets.Dropdown(options=[symbol + '-' + freq for symbol, freq in ohlcvs.keys()])
        backtest_btn = widgets.Button(description='status')

        backtest_panel = widgets.Output()
        option_panel = widgets.Output()

        def plotly_df(df):
            """Display plot.
            """
            # Plot
            fig = px.line()
            for sname, s in df.items():
                fig.add_scatter(x=s.index, y=s.values, name=sname)  # Not what is desired - need a line
            # fig.show()

        @backtest_panel.capture(clear_output=True)
        def backtest(_):
            """Display single strategy backtest result.
            """
            method_id = int(method_dropdown.value.split('-')[-1])
            history_id = tuple(symbol_dropdown.value.split('-'))
            ohlcv = ohlcvs[history_id]
            strategy = self._trading_methods[method_id].strategy
            svars = self._trading_methods[method_id].variables
            filters = self._trading_methods[method_id].filters
            strategy.backtest(ohlcv, variables=svars, filters=filters, freq=history_id[-1], plot=True)

        backtest_btn.on_click(backtest)
        dropdowns = widgets.HBox([method_dropdown, symbol_dropdown, backtest_btn])
        with option_panel:
            plotly_df(ret)
            display(pd.DataFrame(full_results))

        return widgets.VBox([option_panel, dropdowns, backtest_panel])

    def portfolio_backtest(self, ohlcvs, min_freq, quote_assets=['BTC', 'USDT', 'BUSD', 'USDC'], fee=0.002, delay=0):
        """Display portfolio backtest result.

        Calculate overall account asset changes.
        Unit is USD

        Args:
          ohlcvs: A dataframe of symbel.
          min_freq: A str of calculation frequency ex('4h').
          quote_assets: A list of assets name ex(['BTC', 'USDT', 'BUSD', 'ETH']).
          fee: A float of trading fee.
          delay: A int of delayed entry and exit setting.
        Returns:
            widget GUI
        """
        # backtest_results
        results = []
        for method in self._trading_methods:
            for symbol in method.symbols:
                ohlcv = ohlcvs[(symbol, method.freq)]
                result = method.strategy.backtest(ohlcv,
                                                  method.variables, filters=method.filters, freq=method.freq)
                # find weight_btc if it is in the nested dictionary
                weight_btc = method.weight
                if isinstance(weight_btc, dict):
                    weight_btc = (weight_btc[symbol]
                        if symbol in weight else weight_btc['default'])

                weight_btc *= self.ticker_info.get_asset_price_in_btc(method.weight_unit)

                results.append({
                    'name': method.name,
                    'symbol': symbol,
                    'freq': method.freq,
                    'weight': weight_btc,
                    'portfolio': result,
                    'trading_method': method,
                    'signal': result.cash().iloc[-1] == 0,
                })

        results = pd.DataFrame(results)

        import matplotlib.pyplot as plt
        position = {}
        quote_substract = {}
        for index, value in results.transpose().items():
            position[value.loc['name'] + '|' + value.symbol + '|' + value.freq] = (value.portfolio.cash() == 0).shift(
                delay).ffill() * value.weight
        position = pd.DataFrame(position).resample(min_freq).last().ffill()
        position.columns = position.columns.str.split('|').str[1]
        position = position.ffill().fillna(0)
        position = position.groupby(position.columns, axis=1).sum()

        # find quote assets
        quote_asset_col = []
        for symbol in position.columns:
            for q in quote_assets:
                if symbol[-len(q):] == q:
                    quote_asset_col.append(q)
                    break

        quote_position = position.copy()
        quote_position.columns = quote_asset_col
        quote_position = -quote_position.groupby(quote_position.columns, axis=1).sum()

        # calculate return in usdt
        assets = position.columns.str.split('|').str[0].to_list()

        for i, a in enumerate(assets):
            for q in quote_assets:
                if len(a) > 5 and a[-len(q):] == q:
                    assets[i] = a[:-len(q)]

        position.columns = assets
        position = position.groupby(position.columns, axis=1).sum()
        quote_position = quote_position.groupby(quote_position.columns, axis=1).sum()

        all_symbols = list(set(quote_position.columns) | set(position.columns) | set(self._margins.keys()))
        if 'USDT' not in all_symbols:
            all_symbols.append('USDT')

        position = position.reindex(all_symbols, axis=1).fillna(0) + quote_position.reindex(all_symbols, axis=1).fillna(
            0)

        ohlcv_usdt = {a: get_all_binance(a + 'USDT', min_freq) for a in position.columns if a != 'USDT'}

        initial_margin_sum_btc = 0
        for a, w in self._margins.items():
            position[a] += self.ticker_info.get_asset_price_in_btc(a) * w
            initial_margin_sum_btc += self.ticker_info.get_asset_price_in_btc(a) * w

        # remove negative position
        negative_position = ((position < 0) * position).drop('USDT', axis=1, errors='ignore').sum(axis=1)
        pusdt = position['USDT'].copy()
        position = position.clip(0, None)
        position.USDT = pusdt + negative_position

        addition_usdt = -min(position.USDT.min(), 0) / self.ticker_info.get_asset_price_in_btc('USDT')

        if addition_usdt > 0:
            print('WARRN**: additional usdt is required: ', addition_usdt, ' USD')

        p = position.loc[position.index[(position != position.shift()).abs().sum(axis=1) != 0] | position.index[-1:]]
        p.index = p.index.tz_localize(None)

        ohlcv_usdt_close = pd.DataFrame({name: s.close for name, s in ohlcv_usdt.items()})
        ohlcv_usdt_close.index = ohlcv_usdt_close.index.tz_localize(None)

        rebalance_time = (p.index & ohlcv_usdt_close.index)

        ohlcv_usdt_close = ohlcv_usdt_close.loc[rebalance_time]
        p = p.loc[rebalance_time].fillna(0)

        asset_return = ((ohlcv_usdt_close.pct_change().shift(-1).fillna(0)) * p) - fee * (p - p.shift()).abs()
        asset_return.fillna(0, inplace=True)

        (asset_return.cumsum() / self.ticker_info.get_asset_price_in_btc('USDT')).plot()
        plt.show()

        s = (asset_return.sum(axis=1).cumsum() + initial_margin_sum_btc) / self.ticker_info.get_asset_price_in_btc(
            'USDT')
        s.plot()

        plt.show()

        (s / s.cummax()).plot()
        plt.show()

        return results
示例#8
0
class BinanceClient(AbstractClient):
    def __init__(self, listener):
        self.exchange = 'binance'
        self.trade_fee = Decimal(0.0005)
        self.client = Client(api_keys.binance[0], api_keys.binance[1])
        super(BinanceClient, self).__init__(listener)
        self._get_exchange_info()
        self.get_all_balances()

    def _buy(self, symbol, price, amount):
        result = self.client.create_order(symbol=symbol,
                                          quantity=amount,
                                          price=price,
                                          side=SIDE_BUY,
                                          type=ORDER_TYPE_LIMIT,
                                          timeInForce=TIME_IN_FORCE_GTC)
        self.open_orders[symbol] = result['orderId']

    def _sell(self, symbol, price, amount):
        result = self.client.create_order(symbol=symbol,
                                          quantity=amount,
                                          price=price,
                                          side=SIDE_SELL,
                                          type=ORDER_TYPE_LIMIT,
                                          timeInForce=TIME_IN_FORCE_GTC)
        self.open_orders[symbol] = result['orderId']

    def _cancel(self, symbol):
        orderId = self.open_orders.pop(symbol)
        try:
            self.client.cancel_order(symbol=symbol, orderId=orderId)
        # Binance throws API exception if the order is not open so we'll have to check if it's fulfilled here.
        except BinanceAPIException as e:
            time.sleep(1)
            if not self.is_order_fulfilled(symbol, orderId):
                # Order was not fulfilled, re-throw exception
                raise e
        except BinanceRequestException as e:
            self.errors += 1
            raise e

    def is_order_fulfilled(self, symbol, orderId):
        try:
            for data in self.client.get_my_trades(symbol=symbol):
                if data['orderId'] == int(orderId):
                    return True

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] is order fulfilled error", e
            self.errors += 1

        return False

    def get_all_balances(self):
        try:
            result = self.client.get_account()

            for balance in result['balances']:
                self.coin_balances[str(balance['asset'])] = Decimal(
                    str(balance['free']))  # + Decimal(balance['locked'])

            return self.coin_balances

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] get all balances error:", str(
                e).replace('\r\n', '')
            self.errors += 1

    def _market_poll(self):
        result = {'success': False}
        result['client'] = self
        result['timestamp'] = int(time.time() * 1000)
        result['coinpairs'] = {}

        try:
            coins = self.client.get_orderbook_tickers()

            for coin in coins:
                symbol = str(coin['symbol'])
                if symbol in self.exchange_symbols:
                    result['coinpairs'][self._get_arbitrager_coinpair(
                        symbol)] = {
                            'buy': Decimal(str(coin['bidPrice'])),
                            'buyAmount': Decimal(str(coin['bidQty'])),
                            'sell': Decimal(str(coin['askPrice'])),
                            'sellAmount': Decimal(str(coin['askQty']))
                        }

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] market poll error", str(
                e).replace('\r\n', '')
            self.errors += 1

        if len(result['coinpairs']) > 0:
            result['success'] = True

        return result

    def _get_exchange_info(self):
        result = self.client.get_exchange_info()
        for symbol in result['symbols']:
            sym = str(symbol['symbol'])
            self.trade_rules[sym] = {}
            trade_rule = self.trade_rules[sym]
            for filter in symbol['filters']:
                if filter['filterType'] == 'PRICE_FILTER':
                    trade_rule['minPrice'] = Decimal(filter['minPrice'])
                    trade_rule['maxPrice'] = Decimal(filter['maxPrice'])
                    trade_rule['stepPrice'] = Decimal(filter['tickSize'])
                elif filter['filterType'] == 'LOT_SIZE':
                    if sym == 'NEOETH':
                        trade_rule['minAmount'] = Decimal(0.1)
                    elif sym == 'LTCETH':
                        trade_rule['minAmount'] = Decimal(0.05)
                    else:
                        trade_rule['minAmount'] = Decimal(filter['minQty'])
                    trade_rule['maxAmount'] = Decimal(filter['maxQty'])
                    trade_rule['stepAmount'] = Decimal(filter['stepSize'])
                elif filter['filterType'] == 'MIN_NOTIONAL':
                    trade_rule['minNotional'] = Decimal(filter['minNotional'])
示例#9
0
class ApiCalls:
    """Collection of api related methods."""
    def __init__(self, mw, tp):
        self.mw = mw

        self.client = Client(mw.cfg_manager.api_key, mw.cfg_manager.api_secret,
                             {
                                 "verify": True,
                                 "timeout": 10
                             })

        app.client = self.client

        self.threadpool = tp

    def initialize(self):

        # print("setting client: " + str(self.client))

        try:
            val["coins"] = self.availablePairs()

            val["accHoldings"] = self.getHoldings()

            val["tickers"] = self.getTickers()

            val["apiCalls"] += 3
            # userMsg = dict()
            # accHoldings = dict()

            self.set_pair_values()
            self.mw.is_connected = True
        except (BinanceAPIException, NameError) as e:
            print("API ERROR")
            print(str(e))
            if "code=-1003" in str(e):
                print("ja ein api error :)")
            elif "code=-2014":
                print("API KEY INVALID")

    # def get_tether(client):
    #     tether_info = client.get_ticker(symbol="BTCUSDT")
    #     return tether_info

    def set_pair_values(self):
        """Set various values based on the chosen pair."""
        pair = self.mw.cfg_manager.pair
        val["decimals"] = len(str(val["coins"][pair]["tickSize"])) - 2

        if int(val["coins"][pair]["minTrade"]) == 1:
            val["assetDecimals"] = 0
        else:
            val["assetDecimals"] = len(str(val["coins"][pair]["minTrade"])) - 2

    def availablePairs(self):
        """
        Create a dictonary containing all BTC tradepairs excluding USDT.

        Keys are:
        {'symbol': 'ETHBTC', 'tradedMoney': 3024.89552855, 'baseAssetUnit': 'Ξ', 'active': True, 'minTrade': '0.00100000', 'baseAsset': 'ETH', 'activeSell': 66254.102, 'withdrawFee': '0', 'tickSize': '0.000001', 'prevClose': 0.044214, 'activeBuy': 0, 'volume': '66254.102000', 'high': '0.047998', 'lastAggTradeId': 2809764, 'decimalPlaces': 8, 'low': '0.043997', 'quoteAssetUnit': '฿', 'matchingUnitType': 'STANDARD', 'close': '0.047656', 'quoteAsset': 'BTC', 'open': '0.044214', 'status': 'TRADING', 'minQty': '1E-8'}
        """
        # create a local dictionary
        coins = dict()

        # API Call
        products = self.client.get_products()

        # For every entry in API answer:
        for i, pair in enumerate(products["data"]):

            # Check if pair contains BTC, does not contain USDT and if volume is >0
            if "BTC" in pair["symbol"] and "USDT" not in pair[
                    "symbol"] and float(products["data"][i]["volume"]) > 0.0:
                # Create a temporary dictionary to store keys and values
                tempdict = dict()

                # Add every key-value pair to the temp dictionary
                for key, value in pair.items():
                    tempdict[key] = value
                # Add every temp dictionary to the coin dictionary
                coins[tempdict["symbol"]] = tempdict

        return coins

    def getHoldings(self):
        """Make an inital API call to get BTC and coin holdings."""
        # API Call:
        order = self.client.get_account()
        accHoldings = dict()
        for i in range(len(order["balances"])):
            accHoldings[order["balances"][i]["asset"]] = {
                "free": order["balances"][i]["free"],
                "locked": order["balances"][i]["locked"]
            }

        return accHoldings

    def getTickers(self):
        """Make an initial API call to get ticker data."""
        ticker = self.client.get_ticker()
        # print(str(ticker))
        all_tickers = dict()
        for _, ticker_data in enumerate(ticker):
            if "BTC" in ticker_data["symbol"]:
                # print(str(ticker_data))
                all_tickers[ticker_data["symbol"]] = ticker_data

        return all_tickers

    def getTradehistory(self, pair):
        """Make an initial API call to get the trade history of a given pair. This is used until updated by websocket data."""
        # API call
        globalList = list()
        trades = self.client.get_aggregate_trades(symbol=pair, limit=50)
        for _, trade in enumerate(reversed(trades)):
            globalList.insert(
                0, {
                    "price": str(trade["p"]),
                    "quantity": str(trade["q"]),
                    "maker": bool(trade["m"]),
                    "time": str(trade["T"])
                })

        return list(reversed(globalList))

    def getDepth(self, symbol):
        """Make an initial API call to get market depth (bids and asks)."""
        # API Call
        depth = self.client.get_order_book(symbol=symbol, limit=20)

        asks = depth["asks"]
        bids = depth["bids"]
        return {"bids": bids, "asks": asks}

    def api_create_order(self, side, pair, price, amount, progress_callback):
        print("create order: " + str(price) + " " + str(amount))
        try:
            if side == "Buy":
                order = self.client.order_limit_buy(symbol=pair,
                                                    quantity=str(amount),
                                                    price=str(price))

            elif side == "Sell":
                order = self.client.order_limit_sell(symbol=pair,
                                                     quantity=str(amount),
                                                     price=str(price))

            print("order status: " + str(order))
            return order
        except BinanceAPIException as e:
            print("create order failed: " + str(e))
            print(str(order))

    def api_cancel_order(self, client, order_id, symbol, progress_callback):
        print("cancel order " + str(symbol) + " " + str(order_id))
        try:
            self.client.cancel_order(symbol=symbol, orderId=order_id)
        except BinanceAPIException as e:
            print("cancel failed " + str(e))
            print(str(self.client))
            print(str(symbol))
            print(str(order_id))

    def api_order_history(self, pair, progress_callback):
        orders = self.client.get_all_orders(symbol=pair)
        progress_callback.emit(orders)
        val["apiCalls"] += 1

    def api_history(self, progress_callback):
        trade_history = self.getTradehistory(self.mw.cfg_manager.pair)
        progress_callback.emit({"history": reversed(trade_history)})
        val["apiCalls"] += 1

    def api_depth(self, progress_callback):
        depth = self.getDepth(self.mw.cfg_manager.pair)
        val["asks"] = depth["asks"]
        progress_callback.emit({"asks": val["asks"]})
        val["bids"] = depth["bids"]
        progress_callback.emit({"bids": val["bids"]})
        val["apiCalls"] += 1

    def api_all_orders(self, progress_callback):
        print("CLEINT;" + str(self.client))
        orders = self.client.get_open_orders()
        progress_callback.emit(orders)
        numberPairs = sum(val["pairs"].values())
        print("number pairs: " + str(numberPairs))

    def api_calls(self):
        """Inital and coin specific api calls"""
        worker = Worker(self.api_history)
        worker.signals.progress.connect(self.mw.live_data.batch_history)
        self.mw.threadpool.start(worker)

        worker = Worker(self.api_depth)
        worker.signals.progress.connect(self.mw.live_data.batch_orderbook)
        worker.signals.finished.connect(self.mw.limit_pane.t_complete)
        self.mw.threadpool.start(worker)

        self.get_trade_history(self.mw.cfg_manager.pair)

    def get_trade_history(self, pair):
        worker = Worker(partial(self.api_order_history, pair))
        worker.signals.progress.connect(self.mw.history_table.orders_received)
        self.mw.threadpool.start(worker)

    def get_kline(self, pair, progress_callback):
        """Make an API call to get historical data of a coin pair."""
        interval = "1m"

        try:  # try since this is used heavily
            klines = self.client.get_klines(symbol=pair, interval=interval)
        except (ConnectionError, BinanceAPIException) as e:
            print(str(e))

        progress_callback.emit([klines, pair, interval])

        val["apiCalls"] += 1

    def cancel_order_byId(self, order_id, symbol):
        """Cancel an order by id from within a separate thread."""
        worker = Worker(
            partial(self.mw.api_manager.api_cancel_order, app.client, order_id,
                    symbol))
        # worker.signals.progress.connect(self.cancel_callback)
        self.threadpool.start(worker)
class BinanceAPIManager:
    def __init__(self, config: Config, db: Database, logger: Logger):
        self.binance_client = Client(
            config.BINANCE_API_KEY,
            config.BINANCE_API_SECRET_KEY,
            tld=config.BINANCE_TLD,
        )
        self.db = db
        self.logger = logger
        self.config = config

    @cached(cache=TTLCache(maxsize=1, ttl=43200))
    def get_trade_fees(self) -> Dict[str, float]:
        return {ticker["symbol"]: ticker["taker"] for ticker in self.binance_client.get_trade_fee()["tradeFee"]}

    @cached(cache=TTLCache(maxsize=1, ttl=60))
    def get_using_bnb_for_fees(self):
        return self.binance_client.get_bnb_burn_spot_margin()["spotBNBBurn"]

    def get_fee(self, origin_coin: Coin, target_coin: Coin, selling: bool):
        base_fee = self.get_trade_fees()[origin_coin + target_coin]
        if not self.get_using_bnb_for_fees():
            return base_fee
        # The discount is only applied if we have enough BNB to cover the fee
        amount_trading = (
            self._sell_quantity(origin_coin.symbol, target_coin.symbol)
            if selling
            else self._buy_quantity(origin_coin.symbol, target_coin.symbol)
        )
        fee_amount = amount_trading * base_fee * 0.75
        if origin_coin.symbol == "BNB":
            fee_amount_bnb = fee_amount
        else:
            origin_price = self.get_market_ticker_price(origin_coin + Coin("BNB"))
            if origin_price is None:
                return base_fee
            fee_amount_bnb = fee_amount * origin_price
        bnb_balance = self.get_currency_balance("BNB")
        if bnb_balance >= fee_amount_bnb:
            return base_fee * 0.75
        return base_fee

    def get_all_market_tickers(self) -> AllTickers:
        """
        Get ticker price of all coins
        """
        return AllTickers(self.binance_client.get_all_tickers())
#seco 27-04-21
    def get_coinlist(self) -> Get_Coinlist
        
        return Get_Coinlist(self.binance.client.exchangeinfo(“quotename”))

    def get_market_ticker_price(self, ticker_symbol: str):
        """
        Get ticker price of a specific coin
        """
        for ticker in self.binance_client.get_symbol_ticker():
            if ticker["symbol"] == ticker_symbol:
                return float(ticker["price"])
        return None

    def get_currency_balance(self, currency_symbol: str):
        """
        Get balance of a specific coin
        """
        for currency_balance in self.binance_client.get_account()["balances"]:
            if currency_balance["asset"] == currency_symbol:
                return float(currency_balance["free"])
        return None

    def retry(self, func, *args, **kwargs):
        time.sleep(1)
        attempts = 0
        while attempts < 20:
            try:
                return func(*args, **kwargs)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info("Failed to Buy/Sell. Trying Again.")
                if attempts == 0:
                    self.logger.info(e)
                attempts += 1
        return None

    def get_symbol_filter(self, origin_symbol: str, target_symbol: str, filter_type: str):
        return next(
            _filter
            for _filter in self.binance_client.get_symbol_info(origin_symbol + target_symbol)["filters"]
            if _filter["filterType"] == filter_type
        )

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_alt_tick(self, origin_symbol: str, target_symbol: str):
        step_size = self.get_symbol_filter(origin_symbol, target_symbol, "LOT_SIZE")["stepSize"]
        if step_size.find("1") == 0:
            return 1 - step_size.find(".")
        return step_size.find("1") - 1

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_min_notional(self, origin_symbol: str, target_symbol: str):
        return float(self.get_symbol_filter(origin_symbol, target_symbol, "MIN_NOTIONAL")["minNotional"])

    def wait_for_order(self, origin_symbol, target_symbol, order_id):
        while True:
            try:
                order_status = self.binance_client.get_order(symbol=origin_symbol + target_symbol, orderId=order_id)
                break
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info(f"Unexpected Error: {e}")
                time.sleep(1)

        self.logger.info(order_status)

        while order_status["status"] != "FILLED":
            try:
                order_status = self.binance_client.get_order(symbol=origin_symbol + target_symbol, orderId=order_id)

                if self._should_cancel_order(order_status):
                    cancel_order = None
                    while cancel_order is None:
                        cancel_order = self.binance_client.cancel_order(
                            symbol=origin_symbol + target_symbol, orderId=order_id
                        )
                    self.logger.info("Order timeout, canceled...")

                    # sell partially
                    if order_status["status"] == "PARTIALLY_FILLED" and order_status["side"] == "BUY":
                        self.logger.info("Sell partially filled amount")

                        order_quantity = self._sell_quantity(origin_symbol, target_symbol)
                        partially_order = None
                        while partially_order is None:
                            partially_order = self.binance_client.order_market_sell(
                                symbol=origin_symbol + target_symbol, quantity=order_quantity
                            )

                    self.logger.info("Going back to scouting mode...")
                    return None

                if order_status["status"] == "CANCELED":
                    self.logger.info("Order is canceled, going back to scouting mode...")
                    return None

                time.sleep(1)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info(f"Unexpected Error: {e}")
                time.sleep(1)

        return order_status

    def _should_cancel_order(self, order_status):
        minutes = (time.time() - order_status["time"] / 1000) / 60
        timeout = 0

        if order_status["side"] == "SELL":
            timeout = float(self.config.SELL_TIMEOUT)
        else:
            timeout = float(self.config.BUY_TIMEOUT)

        if timeout and minutes > timeout and order_status["status"] == "NEW":
            return True

        if timeout and minutes > timeout and order_status["status"] == "PARTIALLY_FILLED":
            if order_status["side"] == "SELL":
                return True

            if order_status["side"] == "BUY":
                current_price = self.get_market_ticker_price(order_status["symbol"])
                if float(current_price) * (1 - 0.001) > float(order_status["price"]):
                    return True

        return False

    def buy_alt(self, origin_coin: Coin, target_coin: Coin, all_tickers: AllTickers):
        return self.retry(self._buy_alt, origin_coin, target_coin, all_tickers)

    def _buy_quantity(
        self, origin_symbol: str, target_symbol: str, target_balance: float = None, from_coin_price: float = None
    ):
        target_balance = target_balance or self.get_currency_balance(target_symbol)
        from_coin_price = from_coin_price or self.get_all_market_tickers().get_price(origin_symbol + target_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(target_balance * 10 ** origin_tick / from_coin_price) / float(10 ** origin_tick)

    def _buy_alt(self, origin_coin: Coin, target_coin: Coin, all_tickers):
        """
        Buy altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, False)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = all_tickers.get_price(origin_symbol + target_symbol)

        order_quantity = self._buy_quantity(origin_symbol, target_symbol, target_balance, from_coin_price)
        self.logger.info(f"BUY QTY {order_quantity}")

        # Try to buy until successful
        order = None
        while order is None:
            try:
                order = self.binance_client.order_limit_buy(
                    symbol=origin_symbol + target_symbol,
                    quantity=order_quantity,
                    price=from_coin_price,
                )
                self.logger.info(order)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info(f"Unexpected Error: {e}")

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        stat = self.wait_for_order(origin_symbol, target_symbol, order["orderId"])

        if stat is None:
            return None

        self.logger.info(f"Bought {origin_symbol}")
        trade_log.set_complete(stat["cummulativeQuoteQty"])

        return order

    def sell_alt(self, origin_coin: Coin, target_coin: Coin, all_tickers: AllTickers):
        return self.retry(self._sell_alt, origin_coin, target_coin, all_tickers)

    def _sell_quantity(self, origin_symbol: str, target_symbol: str, origin_balance: float = None):
        origin_balance = origin_balance or self.get_currency_balance(origin_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(origin_balance * 10 ** origin_tick) / float(10 ** origin_tick)

    def _sell_alt(self, origin_coin: Coin, target_coin: Coin, all_tickers: AllTickers):
        """
        Sell altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, True)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = all_tickers.get_price(origin_symbol + target_symbol)

        order_quantity = self._sell_quantity(origin_symbol, target_symbol, origin_balance)
        self.logger.info(f"Selling {order_quantity} of {origin_symbol}")

        self.logger.info(f"Balance is {origin_balance}")
        order = None
        while order is None:
            # Should sell at calculated price to avoid lost coin
            order = self.binance_client.order_limit_sell(
                symbol=origin_symbol + target_symbol, quantity=(order_quantity), price=from_coin_price
            )

        self.logger.info("order")
        self.logger.info(order)

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        # Binance server can take some time to save the order
        self.logger.info("Waiting for Binance")

        stat = self.wait_for_order(origin_symbol, target_symbol, order["orderId"])

        if stat is None:
            return None

        new_balance = self.get_currency_balance(origin_symbol)
        while new_balance >= origin_balance:
            new_balance = self.get_currency_balance(origin_symbol)

        self.logger.info(f"Sold {origin_symbol}")

        trade_log.set_complete(stat["cummulativeQuoteQty"])

        return order
示例#11
0
class BinanceWrapper(BaseExchangeWrapper):
    INTERVAL_MAP = {
        CandleTicks.one_minute : Client.KLINE_INTERVAL_1MINUTE,
        CandleTicks.five_minutes : Client.KLINE_INTERVAL_5MINUTE,
        CandleTicks.thirty_minutes : Client.KLINE_INTERVAL_30MINUTE,
        CandleTicks.one_hour : Client.KLINE_INTERVAL_1HOUR,
        CandleTicks.one_day : Client.KLINE_INTERVAL_1DAY,
    }

    def __init__(self, api_key, api_secret):
        BaseExchangeWrapper.__init__(self, exposes_confirmations=False)
        self._handle = Client(api_key, api_secret)
        self._filters = {}
        self._load_markets()

    def _perform_request(self, request_lambda):
        try:
            output = request_lambda()
            if type(output) is dict and output.get('success', True) == False:
                if output['msg'] is dict:
                    if output['msg']['code'] == -1021:
                        raise ExchangeAPIException('Request timed out')
                    raise ExchangeAPIException(output['msg']['msg'])
                else:
                    raise ExchangeAPIException('Failed to fetch data: {0}'.format(output['msg']))
            return output
        except Exception as ex:
            raise ExchangeAPIException(ex.message)

    def _load_names(self):
        try:
            result = requests.get('https://api.coinmarketcap.com/v1/ticker/')
            data = json.loads(result.text)
        except Exception as ex:
            print 'Failed to parse coinmarketcap data: {0}'.format(ex)
            return {}
        names = {}
        for item in data:
            names[item['symbol']] = item['name']
        return names

    def _load_withdraw_info(self):
        try:
            result = requests.get('https://www.binance.com/assetWithdraw/getAllAsset.html')
            data = json.loads(result.text)
        except Exception as ex:
            print 'Failed to parse withdraw fees data: {0}'.format(ex)
            return {}
        fees = {}
        for item in data:
            fees[item['assetCode']] = {
                'fee' : item['transactionFee'],
                'min' : float(item['minProductWithdraw'])
            }
        return fees

    def _make_exchange_name(self, base_currency_code, market_currency_code):
        if base_currency_code not in self._markets or \
           market_currency_code not in self._markets[base_currency_code]:
           raise UnknownMarketException(base_currency_code, market_currency_code)
        return '{0}{1}'.format(market_currency_code, base_currency_code)

    def _split_sumbol(self, symbol):
        for base_code, markets in self._markets.items():
            for market_code in markets:
                if market_code + base_code == symbol:
                    return (base_code, market_code)
        raise ExchangeAPIException('Failed to decode symbol {0}'.format(symbol))

    def _add_filter(self, exchange, filters):
        min_price = None
        max_price = None
        price_tick = None
        min_amount = None
        max_amount = None
        amount_step = None
        min_notional = None
        for f in filters:
            if f['filterType'] == 'PRICE_FILTER':
                min_price = float(f['minPrice'])
                max_price = float(f['maxPrice'])
                price_tick = float(f['tickSize'])
            elif f['filterType'] == 'LOT_SIZE':
                min_amount = float(f['minQty'])
                max_amount = float(f['maxQty'])
                amount_step = float(f['stepSize'])
            elif f['filterType'] == 'MIN_NOTIONAL':
                min_notional = float(f['minNotional'])
        self._filters[exchange] = OrderFilter(
            min_price,
            max_price,
            price_tick,
            min_amount,
            max_amount,
            amount_step,
            min_notional
        )

    def _load_markets(self):
        names = self._load_names()
        self.withdraw_info = self._load_withdraw_info()
        result = self._perform_request(lambda: self._handle.get_exchange_info())
        for symbol in result['symbols']:
            base_currency = symbol['quoteAsset']
            market_currency = symbol['baseAsset']
            self.add_currency(Currency(
                base_currency,
                names.get(base_currency, base_currency),
                0,
                self.withdraw_info.get(base_currency, {}).get('fee', None)
            ))
            self.add_currency(Currency(
                market_currency,
                names.get(market_currency, market_currency),
                0,
                self.withdraw_info.get(market_currency, {}).get('fee', None)
            ))
            self.add_market(base_currency, market_currency)
            self._add_filter(symbol['symbol'], symbol['filters'])

    def get_open_orders(self):
        result = self._perform_request(lambda: self._handle.get_open_orders())
        output = []
        for item in result:
            base_code, market_code = self._split_sumbol(item['symbol'])
            amount = float(item['origQty'])
            output.append(TradeOrder(
                item["orderId"],
                self._currencies[base_code],
                self._currencies[market_code],
                dateparser.parse(str(item["time"])),
                None,
                amount,
                amount - float(item["executedQty"]),
                float(item["price"]),
                float(item["price"]),
                OrderType.limit_buy if item["side"] == "BUY" else OrderType.limit_sell
            ))
        return output

    # Order history in Binance requires a symbol... This doesn't really work
    def get_order_history(self, base_currency_code=None, market_currency_code=None):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.get_my_trades(symbol=exchange_name))
        output = []
        for item in result:
            amount = float(item['qty'])
            output.append(TradeOrder(
                item["orderId"],
                self._currencies[base_currency_code],
                self._currencies[market_currency_code],
                None,
                dateparser.parse(str(item["time"])),
                amount,
                0, # Amount remaining
                float(item["price"]),
                float(item["price"]),
                OrderType.limit_buy if item["isBuyer"] else OrderType.limit_sell
            ))
        return output

    def get_withdrawal_history(self, currency_code=None):
        result = self._perform_request(lambda: self._handle.get_withdraw_history())
        output = []
        for item in result.get("withdrawList", []):
            output.append(Transfer(
                self._currencies[item['asset']],
                item['amount'],
                item['txId'],
                None, # Confirmation
                None, # Tx cost
                item['status'] == 1, # Cancelled
                utils.datetime_from_utc_time(str(item['applyTime']))
            ))
        return output

    def cancel_order(self, base_currency_code, market_currency_code, order_id):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.cancel_order(symbol=exchange_name,
                                                                         orderId=order_id))

    def get_market_state(self, base_currency_code, market_currency_code):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.get_all_tickers())
        price = None
        for entry in result:
            if entry['symbol'] == exchange_name:
                price = entry['price']
        if price is not None:
            result = self._handle.get_orderbook_tickers()
            for entry in result:
                if entry['symbol'] == exchange_name:
                    return MarketState(
                        float(entry['askPrice']),
                        float(entry['bidPrice']),
                        float(price)
                    )
        raise ExchangeAPIException('Failed to fetch information for given market')

    def get_orderbook(self, base_currency_code, market_currency_code):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.get_order_book(symbol=exchange_name))
        buy_orderbook = Orderbook()
        sell_orderbook = Orderbook()
        for item in result['bids']:
            buy_orderbook.add_order(Order(float(item[0]), float(item[1])))
        for item in result['asks']:
            sell_orderbook.add_order(Order(float(item[0]), float(item[1])))
        return (buy_orderbook, sell_orderbook)

    def get_wallets(self):
        result = self._perform_request(lambda: self._handle.get_account())
        output = []
        for data in result['balances']:
            currency = data['asset']
            # Shouldn't happen. TODO: log this
            if currency not in self._currencies:
                continue
            free = float(data['free'])
            locked = float(data['locked'])
            wallet = Wallet(
                self._currencies[currency],
                free + locked,
                free,
                locked
            )
            output.append(wallet)
        return output

    def get_wallet(self, currency_code):
        self.check_valid_currency(currency_code)
        result = self._perform_request(lambda: self._handle.get_asset_balance(currency_code))
        free = float(result['free'])
        locked = float(result['locked'])
        return Wallet(
            self._currencies[currency_code],
            free + locked,
            free,
            locked
        )

    def get_deposit_history(self, currency_code=None):
        result = self._perform_request(lambda: self._handle.get_deposit_history())
        output = []
        for i in result['depositList']:
            # TODO: somehow log this
            if i["asset"] not in self._currencies:
                continue
            output.append(
                Transfer(
                    self._currencies[i["asset"]],
                    float(i["amount"]),
                    i["txId"],
                    i["status"], # Status == 1 means success
                    0,
                    False,
                    dateparser.parse(str(i["insertTime"])),
                )
            )
        return output

    def buy(self, base_currency_code, market_currency_code, amount, rate):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.order_limit_buy(symbol=exchange_name,
                                                                            quantity=amount,
                                                                            price=rate))
        return result['orderId']

    def sell(self, base_currency_code, market_currency_code, amount, rate):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda: self._handle.order_limit_sell(symbol=exchange_name,
                                                                             quantity=amount,
                                                                             price=rate))
        return result['orderId']

    def withdraw(self, currency_code, amount, address, address_tag):
        params = {
            'asset' : currency_code,
            'amount' : amount,
            'address' : address,
        }
        if address_tag is not None:
            params['addressTag'] = address_tag
        result = self._perform_request(lambda:self._handle.withdraw(**params))
        return result['id']

    def get_deposit_address(self, currency_code):
        self.check_valid_currency(currency_code)
        result = self._perform_request(lambda: self._handle.get_deposit_address(asset=currency_code))
        if not result['success']:
            raise ExchangeAPIException('Failed to fetch address for {0} wallet'.format(currency_code))
        return CryptoAddress(
            currency_code,
            result['address'],
            result.get('addresTag', None)
        )

    def get_candles(self, base_currency_code, market_currency_code, interval, limit):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        result = self._perform_request(lambda:
            self._handle.get_klines(
                symbol=exchange_name,
                interval=BinanceWrapper.INTERVAL_MAP[interval],
                limit=limit
            )
        )
        output = []
        for i in result:
            output.append(Candle(
                float(i[3]), # Low
                float(i[2]), # High
                float(i[1]), # Open
                float(i[4]), # Close
                dateparser.parse(str(i[0]))
            ))
        return output

    def is_order_rate_valid(self, base_currency_code, market_currency_code, rate):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        if exchange_name not in self._filters:
            return True
        order_filter = self._filters[exchange_name]
        if rate < order_filter.min_price:
            return OrderInvalidity(OrderInvalidity.Comparison.greater_eq, order_filter.min_price)
        elif rate > order_filter.max_price:
            return OrderInvalidity(OrderInvalidity.Comparison.lower_eq, order_filter.max_price)
        else:
            return True

    def is_order_amount_valid(self, base_currency_code, market_currency_code, amount):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        if exchange_name not in self._filters:
            return True
        order_filter = self._filters[exchange_name]
        if amount < order_filter.min_amount:
            return OrderInvalidity(OrderInvalidity.Comparison.greater_eq, order_filter.min_amount)
        elif amount > order_filter.max_amount:
            return OrderInvalidity(OrderInvalidity.Comparison.lower_eq, order_filter.max_amount)
        else:
            return True

    def is_order_notional_value_valid(self, base_currency_code, market_currency_code, rate, amount):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        if exchange_name not in self._filters:
            return True
        order_filter = self._filters[exchange_name]
        notional_value = rate * amount
        if notional_value < order_filter.min_notional:
            return OrderInvalidity(OrderInvalidity.Comparison.greater_eq, order_filter.min_notional)
        else:
            return True

    def minimum_withdraw_limit(self, currency_code):
        if currency_code in self.withdraw_info:
            return self.withdraw_info[currency_code]['min']
        return None

    def adjust_order_rate(self, base_currency_code, market_currency_code, rate):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        if exchange_name not in self._filters:
            return amount
        order_filter = self._filters[exchange_name]
        return utils.round_order_value(order_filter.price_tick, rate)

    def adjust_order_amount(self, base_currency_code, market_currency_code, amount):
        exchange_name = self._make_exchange_name(base_currency_code, market_currency_code)
        if exchange_name not in self._filters:
            return amount
        order_filter = self._filters[exchange_name]
        return utils.round_order_value(order_filter.amount_step, amount)

    def order_history_needs_asset(self):
        return True
class BinanceExchange(Exchange):
    exchange_name = "Binance"
    isMargin = False

    def __init__(self, apiKey, apiSecret, pairs, name):
        super().__init__(apiKey, apiSecret, pairs, name)

        self.connection = Client(self.api['key'], self.api['secret'])

        symbol_info_arr = self.connection.get_exchange_info()
        dict_symbols_info = {
            item['symbol']: item
            for item in symbol_info_arr["symbols"]
        }
        actual_symbols_info = {
            symbol: dict_symbols_info[symbol]
            for symbol in self.pairs
        }
        self.symbols_info = actual_symbols_info

        self.update_balance()
        self.socket = BinanceSocketManager(self.connection)
        self.socket.start_user_socket(self.on_balance_update)
        self.socket.start()
        self.is_last_order_event_completed = True
        self.step_sizes = {}
        self.balance_updated = True

        for symbol_info in symbol_info_arr['symbols']:
            if symbol_info['symbol'] in self.pairs:
                self.step_sizes[symbol_info['symbol']] = \
                    [f['stepSize'] for f in symbol_info['filters'] if f['filterType'] == 'LOT_SIZE'][0]

    def start(self, caller_callback):
        self.socket.start_user_socket(caller_callback)

    def update_balance(self):
        account_information = self.connection.get_account()
        self.set_balance(account_information['balances'])

    def get_trading_symbols(self):
        symbols = set()
        if not self.symbols_info:
            raise RuntimeError("Cant get exchange info")
        for key, value in self.symbols_info.items():
            symbols.add(value["quoteAsset"])
            symbols.add(value["baseAsset"])
        return symbols

    def set_balance(self, balances):
        symbols = self.get_trading_symbols()
        dict_balances = {item['asset']: item for item in balances}
        actual_balance = {symbol: dict_balances[symbol] for symbol in symbols}
        self.balance = actual_balance

    def on_balance_update(self, upd_balance_ev):
        if upd_balance_ev['e'] == 'outboundAccountPosition':
            balance = []
            for ev in upd_balance_ev['B']:
                balance.append({
                    'asset': ev['a'],
                    'free': ev['f'],
                    'locked': ev['l']
                })
            self.balance.update({item['asset']: item for item in balance})

    def get_open_orders(self):
        orders = self.connection.get_open_orders()
        general_orders = []
        for o in orders:
            quantityPart = self.get_part(o['symbol'], o["origQty"], o['price'],
                                         o['side'])
            general_orders.append(
                Order(o['price'], o["origQty"], quantityPart, o['orderId'],
                      o['symbol'], o['side'], o['type'], self.exchange_name))
        return general_orders

    def _cancel_order(self, order_id, symbol):
        self.connection.cancel_order(symbol=symbol, orderId=order_id)
        self.logger.info(f'{self.name}: Order canceled')

    async def on_cancel_handler(self, event: Actions.ActionCancel):
        try:
            slave_order_id = self._cancel_order_detector(event.price)
            self._cancel_order(slave_order_id, event.symbol)
        except BinanceAPIException as error:
            self.logger.error(f'{self.name}: error {error.message}')
        except:
            self.logger.error(
                f"{self.name}: error in action: {event.name} in slave {self.name}"
            )

    def stop(self):
        self.socket.close()

    def _cancel_order_detector(self, price):
        # detect order id which need to be canceled
        slave_open_orders = self.connection.get_open_orders()
        for ordr_open in slave_open_orders:
            if float(ordr_open['price']) == float(price):
                return ordr_open['orderId']

    def process_event(self, event):
        # return event in generic type from websocket

        # if this event in general type it was send from start function and need call firs_copy
        if 'exchange' in event:
            return event

        if event['e'] == 'outboundAccountPosition':
            self.on_balance_update(event)

        elif event['e'] == 'executionReport':
            if event['X'] == 'FILLED':
                return
            elif event['x'] == 'CANCELED':
                return Actions.ActionCancel(event['s'], event['p'], event['i'],
                                            self.exchange_name, event)
            elif event['X'] == 'NEW':
                order_event = event

                if order_event['s'] not in self.pairs:
                    return

                if order_event[
                        'o'] == 'MARKET':  # if market order, we haven't price and cant calculate quantity
                    order_event['p'] = self.connection.get_ticker(
                        symbol=order_event['s'])['lastPrice']

                # part = self.get_part(order_event['s'], order_event['q'], order_event['p'], order_event['S'])

                # shortcut mean https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#order-update
                order = Order(
                    order_event['p'], order_event['q'],
                    self.get_part(order_event['s'], order_event['q'],
                                  order_event['p'], order_event['S']),
                    order_event['i'], order_event['s'], order_event['S'],
                    order_event['o'], self.exchange_name, order_event['P'])
                return Actions.ActionNewOrder(order, self.exchange_name, event)
            return

    async def on_order_handler(self, event: Actions.ActionNewOrder):
        self.create_order(event.order)

    def create_order(self, order):
        """
        :param order:
        """
        quantity = self.calc_quantity_from_part(order.symbol,
                                                order.quantityPart,
                                                order.price, order.side)
        self.logger.info('Slave ' + self.name + ' ' +
                         str(self._get_quote_balance(order.symbol)) + ' ' +
                         str(self._get_base_balance(order.symbol)) +
                         ', Create Order:' + ' amount: ' + str(quantity) +
                         ', price: ' + str(order.price))
        try:
            if order.type == 'STOP_LOSS_LIMIT' or order.type == "TAKE_PROFIT_LIMIT":
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             price=order.price,
                                             quantity=quantity,
                                             timeInForce='GTC',
                                             stopPrice=order.stop)
            if order.type == 'MARKET':
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             quantity=quantity)
            else:
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             quantity=quantity,
                                             price=order.price,
                                             timeInForce='GTC')
            self.logger.info(f"{self.name}: order created")
        except Exception as e:
            self.logger.error(str(e))

    def _get_quote_balance(self, symbol):
        return self.balance[self.symbols_info[symbol]['quoteAsset']]

    def _get_base_balance(self, symbol):
        return self.balance[self.symbols_info[symbol]['baseAsset']]

    def get_part(self, symbol: str, quantity: float, price: float, side: str):
        # get part of the total balance of this coin

        # if order[side] == sell: need obtain coin balance
        if side == 'BUY':
            get_context_balance = self._get_quote_balance
            market_value = float(quantity) * float(price)
        else:
            get_context_balance = self._get_base_balance
            market_value = float(quantity)

        balance = float(get_context_balance(symbol)['free'])

        # if first_copy the balance was update before
        if self.balance_updated:
            balance += float(get_context_balance(symbol)['locked'])
        # else:
        #     balance += market_value

        part = market_value / balance
        part = part * 0.99  # decrease part for 1% for avoid rounding errors in calculation
        return part

    def calc_quantity_from_part(self, symbol, quantityPart, price, side):
        # calculate quantity from quantityPart

        # if order[side] == sell: need obtain coin balance

        if side == 'BUY':
            get_context_balance = self._get_quote_balance
            buy_koef = float(price)
        else:
            get_context_balance = self._get_base_balance
            buy_koef = 1

        cur_bal = float(get_context_balance(symbol)['free'])

        if self.balance_updated:
            cur_bal += float(get_context_balance(symbol)['locked'])

        quantity = quantityPart * cur_bal / buy_koef

        stepSize = float(self.step_sizes[symbol])
        precision = int(round(-math.log(stepSize, 10), 0))
        quantity = round(quantity, precision)
        return quantity
class BinanceAPIManager:
    def __init__(self, config: Config, db: Database, logger: Logger):
        # initializing the client class calls `ping` API endpoint, verifying the connection
        self.binance_client = Client(
            config.BINANCE_API_KEY,
            config.BINANCE_API_SECRET_KEY,
            tld=config.BINANCE_TLD,
        )
        self.db = db
        self.logger = logger
        self.config = config

        self.cache = BinanceCache()
        self.stream_manager: Optional[BinanceStreamManager] = None
        self.setup_websockets()

    def setup_websockets(self):
        self.stream_manager = BinanceStreamManager(
            self.cache,
            self.config,
            self.binance_client,
            self.logger,
        )

    @cached(cache=TTLCache(maxsize=1, ttl=43200))
    def get_trade_fees(self) -> Dict[str, float]:
        return {
            ticker["symbol"]: float(ticker["takerCommission"])
            for ticker in self.binance_client.get_trade_fee()
        }

    @cached(cache=TTLCache(maxsize=1, ttl=60))
    def get_using_bnb_for_fees(self):
        return self.binance_client.get_bnb_burn_spot_margin()["spotBNBBurn"]

    def get_fee(self, origin_coin: Coin, target_coin: Coin, selling: bool):
        base_fee = self.get_trade_fees()[origin_coin + target_coin]
        if not self.get_using_bnb_for_fees():
            return base_fee

        # The discount is only applied if we have enough BNB to cover the fee
        amount_trading = (self._sell_quantity(origin_coin.symbol,
                                              target_coin.symbol)
                          if selling else self._buy_quantity(
                              origin_coin.symbol, target_coin.symbol))

        fee_amount = amount_trading * base_fee * 0.75
        if origin_coin.symbol == "BNB":
            fee_amount_bnb = fee_amount
        else:
            origin_price = self.get_ticker_price(origin_coin + Coin("BNB"))
            if origin_price is None:
                return base_fee
            fee_amount_bnb = fee_amount * origin_price

        bnb_balance = self.get_currency_balance("BNB")

        if bnb_balance >= fee_amount_bnb:
            return base_fee * 0.75
        return base_fee

    def get_account(self):
        """
        Get account information
        """
        return self.binance_client.get_account()

    def get_ticker_price(self, ticker_symbol: str):
        """
        Get ticker price of a specific coin
        """
        price = self.cache.ticker_values.get(ticker_symbol, None)
        if price is None and ticker_symbol not in self.cache.non_existent_tickers:
            self.cache.ticker_values = {
                ticker["symbol"]: float(ticker["price"])
                for ticker in self.binance_client.get_symbol_ticker()
            }
            self.logger.debug(
                f"Fetched all ticker prices: {self.cache.ticker_values}")
            price = self.cache.ticker_values.get(ticker_symbol, None)
            if price is None:
                self.logger.info(
                    f"Ticker does not exist: {ticker_symbol} - will not be fetched from now on"
                )
                self.cache.non_existent_tickers.add(ticker_symbol)

        return price

    def get_currency_balance(self, currency_symbol: str, force=False) -> float:
        """
        Get balance of a specific coin
        """
        with self.cache.open_balances() as cache_balances:
            balance = cache_balances.get(currency_symbol, None)
            if force or balance is None:
                cache_balances.clear()
                cache_balances.update({
                    currency_balance["asset"]: float(currency_balance["free"])
                    for currency_balance in self.binance_client.get_account()
                    ["balances"]
                })
                self.logger.debug(f"Fetched all balances: {cache_balances}")
                if currency_symbol not in cache_balances:
                    cache_balances[currency_symbol] = 0.0
                    return 0.0
                return cache_balances.get(currency_symbol, 0.0)

            return balance

    def retry(self, func, *args, **kwargs):
        time.sleep(1)
        attempts = 0
        while attempts < 20:
            try:
                return func(*args, **kwargs)
            except Exception:  # pylint: disable=broad-except
                self.logger.warning(
                    f"Failed to Buy/Sell. Trying Again (attempt {attempts}/20)"
                )
                if attempts == 0:
                    self.logger.warning(traceback.format_exc())
                attempts += 1
        return None

    def get_symbol_filter(self, origin_symbol: str, target_symbol: str,
                          filter_type: str):
        return next(_filter for _filter in self.binance_client.get_symbol_info(
            origin_symbol + target_symbol)["filters"]
                    if _filter["filterType"] == filter_type)

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_alt_tick(self, origin_symbol: str, target_symbol: str):
        step_size = self.get_symbol_filter(origin_symbol, target_symbol,
                                           "LOT_SIZE")["stepSize"]
        if step_size.find("1") == 0:
            return 1 - step_size.find(".")
        return step_size.find("1") - 1

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_min_notional(self, origin_symbol: str, target_symbol: str):
        return float(
            self.get_symbol_filter(origin_symbol, target_symbol,
                                   "MIN_NOTIONAL")["minNotional"])

    def _wait_for_order(
        self, order_id, origin_symbol: str, target_symbol: str
    ) -> Optional[BinanceOrder]:  # pylint: disable=unsubscriptable-object
        while True:
            order_status: BinanceOrder = self.cache.orders.get(order_id, None)
            if order_status is not None:
                break
            self.logger.debug(f"Waiting for order {order_id} to be created")
            time.sleep(1)

        self.logger.debug(f"Order created: {order_status}")

        while order_status.status != "FILLED":
            try:
                order_status = self.cache.orders.get(order_id, None)

                self.logger.debug(f"Waiting for order {order_id} to be filled")

                if self._should_cancel_order(order_status):
                    cancel_order = None
                    while cancel_order is None:
                        cancel_order = self.binance_client.cancel_order(
                            symbol=origin_symbol + target_symbol,
                            orderId=order_id)
                    self.logger.info("Order timeout, canceled...")

                    # sell partially
                    if order_status.status == "PARTIALLY_FILLED" and order_status.side == "BUY":
                        self.logger.info("Sell partially filled amount")

                        order_quantity = self._sell_quantity(
                            origin_symbol, target_symbol)
                        partially_order = None
                        while partially_order is None:
                            partially_order = self.binance_client.order_market_sell(
                                symbol=origin_symbol + target_symbol,
                                quantity=order_quantity)

                    self.logger.info("Going back to scouting mode...")
                    return None

                if order_status.status == "CANCELED":
                    self.logger.info(
                        "Order is canceled, going back to scouting mode...")
                    return None

                time.sleep(1)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info(f"Unexpected Error: {e}")
                time.sleep(1)

        self.logger.debug(f"Order filled: {order_status}")
        return order_status

    def wait_for_order(
        self, order_id, origin_symbol: str, target_symbol: str,
        order_guard: OrderGuard
    ) -> Optional[BinanceOrder]:  # pylint: disable=unsubscriptable-object
        with order_guard:
            return self._wait_for_order(order_id, origin_symbol, target_symbol)

    def _should_cancel_order(self, order_status):
        minutes = (time.time() - order_status.time / 1000) / 60
        timeout = 0

        if order_status.side == "SELL":
            timeout = float(self.config.SELL_TIMEOUT)
        else:
            timeout = float(self.config.BUY_TIMEOUT)

        if timeout and minutes > timeout and order_status.status == "NEW":
            return True

        if timeout and minutes > timeout and order_status.status == "PARTIALLY_FILLED":
            if order_status.side == "SELL":
                return True

            if order_status.side == "BUY":
                current_price = self.get_ticker_price(order_status.symbol)
                if float(current_price) * (1 - 0.001) > float(
                        order_status.price):
                    return True

        return False

    def buy_alt(self, origin_coin: Coin, target_coin: Coin) -> BinanceOrder:
        return self.retry(self._buy_alt, origin_coin, target_coin)

    def _buy_quantity(self,
                      origin_symbol: str,
                      target_symbol: str,
                      target_balance: float = None,
                      from_coin_price: float = None):
        target_balance = target_balance or self.get_currency_balance(
            target_symbol)
        from_coin_price = from_coin_price or self.get_ticker_price(
            origin_symbol + target_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(target_balance * 10**origin_tick /
                          from_coin_price) / float(10**origin_tick)

    @staticmethod
    def float_as_decimal_str(num: float):
        return f"{num:0.08f}".rstrip("0").rstrip(
            ".")  # remove trailing zeroes too

    def _make_order(
        self,
        side: str,
        symbol: str,
        quantity: float,
        price: float,
        quote_quantity: float,
    ):
        params = {
            "symbol":
            symbol,
            "side":
            side,
            "quantity":
            self.float_as_decimal_str(quantity),
            "type":
            self.config.BUY_ORDER_TYPE
            if side == Client.SIDE_BUY else self.config.SELL_ORDER_TYPE,
        }
        if params["type"] == Client.ORDER_TYPE_LIMIT:
            params["timeInForce"] = self.binance_client.TIME_IN_FORCE_GTC
            params["price"] = self.float_as_decimal_str(price)
        elif side == Client.SIDE_BUY:
            del params["quantity"]
            params["quoteOrderQty"] = self.float_as_decimal_str(quote_quantity)
        return self.binance_client.create_order(**params)

    def _buy_alt(self, origin_coin: Coin, target_coin: Coin):
        """
        Buy altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, False)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        with self.cache.open_balances() as balances:
            balances.clear()

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = self.get_ticker_price(origin_symbol + target_symbol)

        order_quantity = self._buy_quantity(origin_symbol, target_symbol,
                                            target_balance, from_coin_price)
        self.logger.info(f"BUY QTY {order_quantity} of <{origin_symbol}>")

        # Try to buy until successful
        order = None
        order_guard = self.stream_manager.acquire_order_guard()
        while order is None:
            try:
                order = self._make_order(
                    side=Client.SIDE_BUY,
                    symbol=origin_symbol + target_symbol,
                    quantity=order_quantity,
                    quote_quantity=target_balance,
                    price=from_coin_price,
                )
                self.logger.info(order)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.warning(f"Unexpected Error: {e}")

        executed_qty = float(order.get("executedQty", 0))
        if executed_qty > 0 and order["status"] == "FILLED":
            order_quantity = executed_qty  # Market buys provide QTY of actually bought asset

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        order_guard.set_order(origin_symbol, target_symbol,
                              int(order["orderId"]))
        order = self.wait_for_order(order["orderId"], origin_symbol,
                                    target_symbol, order_guard)

        if order is None:
            return None

        self.logger.info(f"Bought {origin_symbol}")

        trade_log.set_complete(order.cumulative_quote_qty)

        return order

    def sell_alt(self, origin_coin: Coin, target_coin: Coin) -> BinanceOrder:
        return self.retry(self._sell_alt, origin_coin, target_coin)

    def _sell_quantity(self,
                       origin_symbol: str,
                       target_symbol: str,
                       origin_balance: float = None):
        origin_balance = origin_balance or self.get_currency_balance(
            origin_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(origin_balance * 10**origin_tick) / float(
            10**origin_tick)

    def _sell_alt(self, origin_coin: Coin, target_coin: Coin):
        """
        Sell altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, True)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        with self.cache.open_balances() as balances:
            balances.clear()

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = self.get_ticker_price(origin_symbol + target_symbol)

        order_quantity = self._sell_quantity(origin_symbol, target_symbol,
                                             origin_balance)
        self.logger.info(f"Selling {order_quantity} of {origin_symbol}")

        self.logger.info(f"Balance is {origin_balance}")
        order = None
        order_guard = self.stream_manager.acquire_order_guard()
        while order is None:
            try:
                order = self._make_order(
                    side=Client.SIDE_SELL,
                    symbol=origin_symbol + target_symbol,
                    quantity=order_quantity,
                    quote_quantity=target_balance,
                    price=from_coin_price,
                )
                self.logger.info(order)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.warning(f"Unexpected Error: {e}")

        self.logger.info("order")
        self.logger.info(order)

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        order_guard.set_order(origin_symbol, target_symbol,
                              int(order["orderId"]))
        order = self.wait_for_order(order["orderId"], origin_symbol,
                                    target_symbol, order_guard)

        if order is None:
            return None

        new_balance = self.get_currency_balance(origin_symbol)
        while new_balance >= origin_balance:
            new_balance = self.get_currency_balance(origin_symbol, True)

        self.logger.info(f"Sold {origin_symbol}")

        trade_log.set_complete(order.cumulative_quote_qty)

        return order
Highest_Bid_Price = 1.00009  #買單最高價格
Lowest_Ask_Price = 1.00399  #賣單最低價格
Refresh_Time = 116.5  #更新頻率(秒)

x = -2

while True:

    ##_1_清空所有訂單

    orders = client.get_open_orders(symbol='WBTCBTC')

    time.sleep(0.5)

    for i in range(0, len(orders), 1):
        cancel = client.cancel_order(symbol='WBTCBTC',
                                     orderId=orders[i]['orderId'])
        time.sleep(0.1)

    ##_2_取得帳戶當前之BTC與WBTC餘額

    BTC = client.get_asset_balance(asset='BTC')
    BTC_Balance = float(BTC.get('free'))

    WBTC = client.get_asset_balance(asset='WBTC')
    WBTC_Balance = float(WBTC.get('free'))
    Available_WBTC_Balance_For_Ask = math.floor(WBTC_Balance * 10000) / 10000

    time.sleep(0.5)

    ##_3_計算市場買賣單深度並依條件掛單
示例#15
0
class Operation:
    def __init__(self,
                 exchange_list,
                 apikey_trt=None,
                 secret_trt=None,
                 apikey_krk=None,
                 secret_krk=None,
                 apikey_bnb=None,
                 secret_bnb=None,
                 pair="BTCEUR"):
        self.apikey_trt = apikey_trt
        self.secret_trt = secret_trt
        self.apikey_krk = apikey_krk
        self.secret_krk = secret_krk
        self.apikey_bnb = apikey_bnb
        self.secret_bnb = secret_bnb
        self.exchange_list = exchange_list
        self.client = Client(self.apikey_bnb, self.secret_bnb)
        self.trt = []
        self.prtrt = []
        self.bnb = []
        self.prbnb = []
        self.len = 0
        self.pair = pair

    def thread_func(self):
        while (1):
            if len(self.prtrt) < 20000:
                tr = Thread(
                    target=lambda q, arg1, arg2: q.put(self.query(arg1, arg2)),
                    args=(q1, "trt", self.pair))
                self.prtrt.append(tr)
                bn = Thread(
                    target=lambda q, arg1, arg2: q.put(self.query(arg1, arg2)),
                    args=(q2, "bnb", self.pair))
                self.prbnb.append(bn)
            else:
                time.sleep(1)
                if len(self.trt) < 25:
                    self.bnb = self.bnb + self.prbnb
                    self.trt = self.trt + self.prtrt
                    self.prtrt.clear()
                    self.prbnb.clear()
                    time.sleep(30)

    def threadCreation(self):
        x = Thread(target=self.thread_func)
        x.start()

    def trade(self, exchange, fund_id, side, amount, price):
        nonce = str(int(time.time() * 1e6))
        print(amount)
        amount = round(amount, 8)
        if exchange == "trt":
            url = "https://api.therocktrading.com/v1/funds/" + fund_id + "/orders"
            payload_trt = {
                "fund_id": "BTCEUR",
                "side": side,
                "amount": amount,
                "price": 0
            }
            signature = hmac.new(self.secret_trt.encode(),
                                 msg=(str(nonce) + url).encode(),
                                 digestmod=hashlib.sha512).hexdigest()

            _headers = {
                'User-Agent': 'PyRock v1',
                "Content-Type": "application/json",
                "X-TRT-KEY": self.apikey_trt,
                "X-TRT-SIGN": signature,
                "X-TRT-NONCE": nonce
            }
            resp = requests.post(url,
                                 data=json.dumps(payload_trt),
                                 headers=_headers)
            try:
                return json.loads(resp.text)
            except KeyError:
                return "ERROR"
        elif exchange == "krk":
            api = krakenex.API(self.apikey_krk, self.secret_krk)
            k = KrakenAPI(api)
            resp = k.add_standard_order(fund_id, side, "limit", str(amount),
                                        str(price))
            resp = str(resp).replace("\'", "\"")
            return resp
        elif exchange == "bnb":

            if side == "buy":
                order = self.client.order_limit_buy(symbol=fund_id,
                                                    quantity=round(amount, 8),
                                                    price=price)
            elif side == "sell":
                order = self.client.order_limit_sell(symbol=fund_id,
                                                     quantity=round(amount, 8),
                                                     price=price)
            return dict(order)

    def __balance(self, exchange):
        nonce = str(int(time.time() * 1e6))
        d = dict()
        if exchange == "trt":

            url = "https://api.therocktrading.com/v1/balances"
            signature = hmac.new(self.secret_trt.encode(),
                                 msg=(str(nonce) + url).encode(),
                                 digestmod=hashlib.sha512).hexdigest()
            _headers = {
                "Content-Type": "application/json",
                "X-TRT-KEY": self.apikey_trt,
                "X-TRT-SIGN": signature,
                "X-TRT-NONCE": nonce
            }
            resp = requests.get(url, headers=_headers)
            d["trtbtc"] = json.loads(resp.text)["balances"][0]["balance"]
            d["trteur"] = json.loads(resp.text)["balances"][8]["balance"]
            return d
        elif exchange == "krk":
            api = krakenex.API(self.apikey_krk, self.secret_krk)
            k = KrakenAPI(api)
            resp = k.get_account_balance()
            d["krkbtc"] = resp["vol"]["XXBT"]
            d["krkbch"] = resp["vol"]["BCH"]
            return d
        elif exchange == "bnb":
            is_fine = True
            while is_fine:
                try:
                    is_fine = False
                except ConnectionError:
                    print(
                        f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}"
                    )
            try:
                d["bnbtrx"] = float(
                    self.client.get_asset_balance(asset="TRX")["free"])
                d["bnbbnb"] = float(
                    self.client.get_asset_balance(asset="BNB")["free"])
            except Exception:
                d["bnbtrx"] = float(
                    self.client.get_asset_balance(asset="TRX")["free"])
                d["bnbbnb"] = float(
                    self.client.get_asset_balance(asset="BNB")["free"])
            return d

    def balancethreading(self):
        d = dict()
        if "krk" in self.exchange_list:
            krk_balance = Thread(
                target=lambda q, arg1: q.put(self.__balance(arg1)),
                args=(q2, "krk"))
            krk_balance.start()
        if "trt" in self.exchange_list:
            trt_balance = Thread(
                target=lambda q, arg1: q.put(self.__balance(arg1)),
                args=(q1, "trt"))
            trt_balance.start()
        if "bnb" in self.exchange_list:
            bnb_balance = Thread(
                target=lambda q, arg1: q.put(self.__balance(arg1)),
                args=(q2, "bnb"))
            bnb_balance.start()
        try:
            trt_balance.join()
            d.update(q1.get())
        except:
            pass
        try:
            krk_balance.join()
            d.update(q2.get())
        except:
            pass
        try:
            bnb_balance.join()
            d.update(q2.get())
        except:
            pass
        return d

    def orderthreading(self, order1, order2=None):
        d = dict()
        bnb_order = Thread(
            target=lambda q, arg1, arg2: q.put(self.__order(arg1, arg2)),
            args=(q3, "bnb", order1))
        bnb_order.start()
        try:
            bnb_order.join()

            d.update(q3.get())
        except Exception:
            pass
        return d

    def cancel(self, order):
        self.client.cancel_order(symbol="TRXBNB", orderId=order)

    def __order(self, exchange, order):
        nonce = str(int(time.time() * 1e6))
        d = dict()
        resp = self.client.get_order(symbol="TRXBNB", orderId=order)
        print("binance", resp)
        d["status_bnb"] = resp["status"]
        return d

    def __fee(self, exchange):
        nonce = str(int(time.time() * 1e6))
        d = dict()
        if exchange == "trt":
            url = "https://api.therocktrading.com/v1/funds/BTCEUR"
            signature = hmac.new(self.secret_trt.encode(),
                                 msg=(str(nonce) + url).encode(),
                                 digestmod=hashlib.sha512).hexdigest()
            _headers = {
                "Content-Type": "application/json",
                "X-TRT-KEY": self.apikey_trt,
                "X-TRT-SIGN": signature,
                "X-TRT-NONCE": nonce
            }
            resp = requests.get(url, headers=_headers)
            d["feetrttaker"] = json.loads(resp.text)["buy_fee"]
            d["feetrtmaker"] = json.loads(resp.text)["sell_fee"]

            return d
        elif exchange == "krk":
            api = krakenex.API(self.apikey_krk, self.secret_krk)
            k = KrakenAPI(api)
            resp = pd.DataFrame(k.get_trade_volume("BTCEUR")[2])
            d["feekrk"] = resp["XXBTZEUR"][0]
            return d
        elif exchange == "bnb":
            resp = self.client.get_trade_fee(symbol="BNBTRX")
            print(resp)
            d["feebnbtaker"] = resp["tradeFee"][0]["taker"]
            d["feebnbmaker"] = resp["tradeFee"][0]["maker"]
            return d

    def feethreading(self):
        d = dict()
        if "krk" in self.exchange_list:
            krk_fee = Thread(target=lambda q, arg1: q.put(self.__fee(arg1)),
                             args=(q1, "krk"))
            krk_fee.start()
        if "trt" in self.exchange_list:
            trt_fee = Thread(target=lambda q, arg1: q.put(self.__fee(arg1)),
                             args=(q2, "trt"))
            trt_fee.start()
        if "bnb" in self.exchange_list:
            bnb_fee = Thread(target=lambda q, arg1: q.put(self.__fee(arg1)),
                             args=(q3, "bnb"))
            bnb_fee.start()
        try:
            krk_fee.join()

            d.update(q1.get())
        except:
            pass
        try:
            trt_fee.join()

            d.update(q2.get())
        except:
            pass
        try:
            bnb_fee.join()

            d.update(q3.get())
        except Exception:
            pass
        return d

    def tradethreading(self,
                       side,
                       exchange,
                       fund_id,
                       amount,
                       price,
                       side2=None,
                       exchange2=None,
                       fund_id2=None,
                       amount2=None,
                       price2=None):
        d = dict()
        print("bnb")
        bnb_trade = Thread(target=lambda q, arg1, arg2, arg3, arg4, arg5: q.
                           put(self.trade(arg1, arg2, arg3, arg4, arg5)),
                           args=(q1, exchange, fund_id, side, amount, price))
        bnb_trade.start()
        try:
            bnb_trade.join()
        except:
            pass
        try:
            d["bnb"] = q1.get()
        except:
            d["bnb"] = "ERROR"

        return d

    def min_qty_trt(self):
        try:
            resp_trt = requests.get(
                "https://api.therocktrading.com/v1/funds/?id=BTCEUR")
            return json.loads(resp_trt.text)
        except requests.exceptions.ConnectionError:
            print(
                f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}")
        except json.decoder.JSONDecodeError:
            print(
                f"{Fore.RED}[ERR] ERROR WHILE CONVERTING TO JSON [expecting value]{Style.RESET_ALL}"
            )

    def query(self, exchange, pair):
        if exchange == "trt":
            self.trt.pop(1)
            try:
                resp_trt = requests.get(
                    'https://api.therocktrading.com/v1/funds/' + self.pair +
                    '/orderbook?limit=1')
                return json.loads(resp_trt.text)
            except requests.exceptions.ConnectionError:
                print(
                    f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}"
                )
            except json.decoder.JSONDecodeError:
                print(
                    f"{Fore.RED}[ERR] ERROR WHILE CONVERTING TO JSON [expecting value]{Style.RESET_ALL}"
                )
        elif exchange == "krk":
            resp_krk = requests.get(
                'https://api.kraken.com/0/public/Depth')  # , params=params)
            return resp_krk.text
        elif exchange == "bnb":
            self.bnb.pop(1)
            try:
                resp_bnb = self.client.get_order_book(symbol=self.pair,
                                                      limit=5)
                return resp_bnb
            except requests.exceptions.ConnectionError:
                print(
                    f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}"
                )
            except requests.exceptions.ReadTimeout:
                print(
                    f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}"
                )
            except binance.exceptions.BinanceAPIException:
                print(
                    f"{Fore.RED}[ERR] CHECK INTERNET CONNECTION{Style.RESET_ALL}"
                )

    def querythread(self):
        d = dict()
        if "trt" in self.exchange_list:
            self.len = len(self.trt)
            trt_thread = self.trt[1]
            trt_thread.start()

        if "bnb" in self.exchange_list:
            bnb_thread = self.bnb[1]
            bnb_thread.start()

        try:
            trt_thread.join()
            d["trt"] = q1.get()
        except:
            pass
        try:
            bnb_thread.join()
            d["bnb"] = q2.get()
        except:
            pass

        return d
示例#16
0
class RmtSrvObj(BaseObj):
    def __init__(self, symbol, line_type, size=0, since='', debug=False, balance_min=0.01):
        self.rmt_srv_obj = Client(api_key, secret_key)
        self.balance_min = balance_min
        super(RmtSrvObj, self).__init__(symbol, line_type, size, since, debug)

    def get_kline(self):
        return self.rmt_srv_obj.get_klines(symbol=self.symbol, interval=self.type,limit=self.size)

    def get_kline_pd(self):
        return pd.DataFrame(self.get_kline(),columns=['open_time', 'open','high','low','close','volume','close_time',
            'quote_asset_volume','number_of_trades','taker_buy_base_asset_volume','taker_buy_quote_asset_volume','ignore'])

    def balance(self, coin=''):
        balance = {'free': 0, 'frozen': 0}
        for item in self.account:
            if coin == item['asset']:
                balance = {'free': item['free'], 'frozen': item['locked']}
                break
        return balance

    """
    'balances': 
    [{'asset': 'BTC', 'free': '0.00000000', 'locked': '0.00000000'}, 
    {'asset': 'ETH', 'free': '0.43767306', 'locked': '2.74720975'}, 
    {'asset': 'ICO', 'free': '0.00000000', 'locked': '0.00000000'}]
    """
    def get_account(self):
        user = self.rmt_srv_obj.get_account()
        # print(user)
        regular_user = user['balances']
        return regular_user

    def get_balance(self, coin):
        coin_info = {'coin': coin, 'free': 0, 'frozen': 0, 'balance': 0}
        for item in self.account:
            if item['asset'] == coin:
                coin_info['free'] = float(item['free'])
                coin_info['frozen'] = float(item['locked'])
                coin_info['balance'] = coin_info['free'] + coin_info['frozen']
                break
        return coin_info

    def get_available_coins(self):
        coins = []
        for item in self.account:
            free_coin = float(item['free'])
            frozen_coin = float(item['locked'])
            balance = free_coin + frozen_coin
            if balance > self.balance_min:
                coins.append({'coin': item['asset'], 'free': free_coin, 'frozen': frozen_coin, 'balance': balance})
        return coins

    def get_all_orders(self):
        return self.rmt_srv_obj.get_all_orders(symbol=self.symbol)

    def get_order(self, order_id):
        order = self.rmt_srv_obj.get_order(symbol=self.symbol, orderId=order_id)
        if not order:
            return None

        new_order = {}
        if order['status'] == 'CANCELED':
            new_order['status'] = 'Cancelled'
        elif order['status'] == 'NEW':
            new_order['status'] = 'Not deal'
        elif order['status'] == 'PARTIALLY_FILLED':
            new_order['status'] = 'Part dealt'
        elif order['status'] == 'FILLED':
            new_order['status'] = 'Dealt'
        elif order['status'] == 'REJECTED':
            new_order['status'] = 'Rejected'
        elif order['status'] == 'EXPIRED':
            new_order['status'] = 'Expired'
        else:
            new_order['status'] = 'Error'

        if order['side'] == 'BUY':
            new_order['type'] = 'buy'
        else:
            new_order['type'] = 'sell'
        new_order['symbol'] = order['symbol']
        new_order['timestamp'] = order['time']/1000
        new_order['create_date'] = datetime.fromtimestamp(new_order['timestamp']).strftime("%Y-%m-%d %H:%M:%S")
        new_order['order_id'] = str(order['orderId'])
        new_order['amount'] = order['origQty']
        new_order['avg_price'] = order['price']
        new_order['deal_amount'] = order['executedQty']
        new_order['price'] = order['price']
        return new_order

    def buy(self, price, amount):
        self.debug('Buy order: pair(%s), price(%s), amount(%s)' % (self.symbol, price, amount))
        ret = self.rmt_srv_obj.create_order(symbol=self.symbol, side=SIDE_BUY,
                                            type=ORDER_TYPE_LIMIT, timeInForce=TIME_IN_FORCE_GTC,
                                            price=price, quantity=amount)
        # self.debug(ret)
        try:
            if ret['orderId']:
                # self.debug('Return buy order ID: %s' % ret['orderId'])
                return ret['orderId']
            else:
                self.debug('Place order failed')
                return None
        except Exception:
            self.debug('Error result: %s' % ret)
            return None

    def sell(self, price, amount):
        self.debug('Sell order: pair(%s), price(%s), amount(%s)' % (self.symbol, price, amount))
        ret = self.rmt_srv_obj.create_order(symbol=self.symbol, side=SIDE_SELL,
                                            type=ORDER_TYPE_LIMIT, timeInForce=TIME_IN_FORCE_GTC,
                                            price=price, quantity=amount)
        # self.debug(ret)
        try:
            if ret['orderId']:
                # self.debug('Return sell order ID: %s' % ret['orderId'])
                return ret['orderId']
            else:
                self.debug('Place order failed')
                return None
        except Exception:
            self.debug('Error result: %s' % ret)
            return None

    def cancel_orders(self):
        orders = self.rmt_srv_obj.get_open_orders(symbol=self.symbol)
        for order in orders:
            self.rmt_srv_obj.cancel_order(symbol=self.symbol, orderId=order['orderId'])
示例#17
0
class FXConnector(Logger):
    ORDER_STATUS_NEW = 'NEW'
    ORDER_STATUS_PARTIALLY_FILLED = 'PARTIALLY_FILLED'
    ORDER_STATUS_FILLED = 'FILLED'
    ORDER_STATUS_CANCELED = 'CANCELED'
    ORDER_STATUS_PENDING_CANCEL = 'PENDING_CANCEL'
    ORDER_STATUS_REJECTED = 'REJECTED'
    ORDER_STATUS_EXPIRED = 'EXPIRED'

    SIDE_BUY = 'BUY'
    SIDE_SELL = 'SELL'

    ORDER_TYPE_LIMIT = 'LIMIT'
    ORDER_TYPE_MARKET = 'MARKET'
    ORDER_TYPE_STOP_LOSS = 'STOP_LOSS'
    ORDER_TYPE_STOP_LOSS_LIMIT = 'STOP_LOSS_LIMIT'
    ORDER_TYPE_TAKE_PROFIT = 'TAKE_PROFIT'
    ORDER_TYPE_TAKE_PROFIT_LIMIT = 'TAKE_PROFIT_LIMIT'
    ORDER_TYPE_LIMIT_MAKER = 'LIMIT_MAKER'

    TIME_IN_FORCE_GTC = 'GTC'  # Good till cancelled
    TIME_IN_FORCE_IOC = 'IOC'  # Immediate or cancel
    TIME_IN_FORCE_FOK = 'FOK'  # Fill or kill

    ORDER_RESP_TYPE_ACK = 'ACK'
    ORDER_RESP_TYPE_RESULT = 'RESULT'
    ORDER_RESP_TYPE_FULL = 'FULL'

    def __init__(self, key=None, secret=None):
        super().__init__()
        self.__key = key
        self.__secret = secret
        self.client = Client(key, secret)
        self.bs: BinanceWebsocket = None

        # self.connection = None
        self.ticker_connection = None
        self.user_data_connection = None

    def listen_symbols(self, symbols, on_ticker_received, user_data_handler):
        self.bs = BinanceWebsocket(self.client)
        self.bs.start_ticker(symbols, on_ticker_received)
        self.bs.start_user_info(user_data_handler)

        self.logInfo('Ticker and User WS initialized')

    def start_listening(self):
        self.bs.start()
        self.logInfo('WS listening started')

    def stop_listening(self):
        self.bs.stop_sockets()
        self.logInfo('Socket stopped')

    @retry(**DEFAULT_RETRY_SETTINGS)
    def cancel_order(self, sym, id):
        return self.client.cancel_order(symbol=sym, orderId=id)

    @retry(**DEFAULT_RETRY_SETTINGS)
    def cancel_open_orders(self, sym):
        orders = self.get_open_orders(sym)
        if orders:
            for order_id in orders:
                self.client.cancel_order(symbol=sym, orderId=order_id)

    def get_server_time(self):
        return self.client.get_server_time()

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_open_orders(self, sym):
        return [o['orderId'] for o in self.client.get_open_orders(symbol=sym)]

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_all_orders(self, sym, limit=500):
        return {
            o['orderId']: {
                'status': o['status'],
                'price': o['price'],
                'stop_price': o['stopPrice'],
                'vol': o['origQty'],
                'vol_exec': o['executedQty']
            }
            for o in self.client.get_all_orders(symbol=sym, limit=limit)
        }

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_all_tickers(self):
        return self.client.get_all_tickers()

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_orderbook_tickers(self):
        return self.client.get_orderbook_tickers()

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_order_status(self, sym, id):
        return self.client.get_order(symbol=sym, orderId=id)

    # @retry(stop_max_attempt_number=MAX_ATTEMPTS, wait_fixed=DELAY)
    def create_makret_order(self, sym, side, volume):
        return self.client.create_order(
            symbol=sym,
            side=side,
            type=FXConnector.ORDER_TYPE_MARKET,
            quantity=FXConnector.format_number(volume))

    # @retry(stop_max_attempt_number=MAX_ATTEMPTS, wait_fixed=DELAY)
    def create_limit_order(self, sym, side, price, volume):
        return self.client.create_order(
            symbol=sym,
            side=side,
            type=FXConnector.ORDER_TYPE_LIMIT,
            timeInForce=FXConnector.TIME_IN_FORCE_GTC,
            quantity=FXConnector.format_number(volume),
            price=FXConnector.format_number(price))

    # @retry(stop_max_attempt_number=MAX_ATTEMPTS, wait_fixed=DELAY)
    def create_stop_order(self, sym, side, stop_price, price, volume):
        return self.client.create_order(
            symbol=sym,
            side=side,
            type=FXConnector.ORDER_TYPE_STOP_LOSS_LIMIT,
            timeInForce=FXConnector.TIME_IN_FORCE_GTC,
            quantity=FXConnector.format_number(volume),
            stopPrice=FXConnector.format_number(stop_price),
            price=FXConnector.format_number(price))

    # @retry(stop_max_attempt_number=MAX_ATTEMPTS, wait_fixed=DELAY)
    def create_test_stop_order(self, sym, side, price, volume):
        return self.client.create_test_order(
            symbol=sym,
            side=side,
            type=FXConnector.ORDER_TYPE_STOP_LOSS_LIMIT,
            timeInForce=FXConnector.TIME_IN_FORCE_GTC,
            quantity=FXConnector.format_number(volume),
            stopPrice=FXConnector.format_number(price),
            price=FXConnector.format_number(price))

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_balance(self, asset):
        bal = self.client.get_asset_balance(asset=asset)
        return float(bal['free']), float(bal['locked'])

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_all_balances(self, assets: dict):
        res = self.client.get_account()

        if 'balances' in res:
            for bal in res['balances']:
                if bal['asset'] in assets:
                    assets[bal['asset']] = {
                        'f': float(bal['free']),
                        'l': float(bal['locked'])
                    }

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_all_balances_dict(self):
        res = self.client.get_account()

        if 'balances' in res:
            return {
                bal['asset']: {
                    'f': float(bal['free']),
                    'l': float(bal['locked'])
                }
                for bal in res['balances']
            }

        return {}

    @retry(**DEFAULT_RETRY_SETTINGS)
    def get_exchange_info(self):
        return self.client.get_exchange_info()
        # info = self.client.get_exchange_info()
        #
        # symbol_info = None
        # for s in info['symbols']:
        #     if s['symbol'] == sym:
        #         symbol_info = s
        #         break
        #
        # props = {}
        # for f in symbol_info['filters']:
        #     props.update(f)
        #
        # props.pop('filterType', None)
        #
        # return FXConnector.ExchangeInfo(**props)

    @classmethod
    def format_number(cls, num):
        return '{:.08f}'.format(num)
示例#18
0
        OrderID = order["clientOrderId"]
        if len(order["fills"]):  #if I did not buy anything, fills is empty
            coinOrderInfo = order["fills"][0]
            coinPriceBought = float(coinOrderInfo['price'])
            coinOrderQty = float(coinOrderInfo['qty'])
        else:
            coinPriceBought = 0
            coinOrderQty = 0
        break
    except:
        log("Error getting data from Binance servers, retrying.")

# if I got out by timeout
if Buy_Timeout:
    # cancel the order
    result = client.cancel_order(symbol=tradingPair, origClientOrderId=OrderID)
    if ORDER_STATUS_NEW in OrderStatus:
        #I did not buy anything, therefore stop here
        print("Did not succeed to buy")
        log("Did not succeed to buy")
        quitProgram()

# when order compelted reset to false for next order
orderCompleted = False

print('Buy order has been made!')
log("Buy order successfully made.")

# once finished waiting for buy order we can process the sell order
print('Processing sell order.')
log("Processing sell order.")
示例#19
0
    #calculate trades - This is the magic math!
    price = round(((B / ratio) - B) / A, 2)
    price_h = round((B * (1 - ratio)) / ((ratio * A) - size), 2)
    price_l = round((B * (1 - ratio)) / ((ratio * A) + size), 2)
    print('our price is {}, attempting to buy at {}, sell at {}'.format(
        price, price_l, price_h))

    #send trades to exchange
    buy_order_id = client.order_limit_buy(symbol=MARKET,
                                          quantity=AMOUNT,
                                          price=price_l)['orderId']
    sell_order = client.order_limit_sell(symbol=MARKET,
                                         quantity=AMOUNT,
                                         price=price_h)['orderId']
    #poll for trade execution

    while (True):
        #check each order and cancel/break on order filled
        time.sleep(POLL_TIME)
        if client.get_order(symbol=MARKET,
                            orderId=buy_order_id)['tatus'] is "FILLED":
            client.cancel_order(symbol=MARKET, orderId=sell_order_id)
            print('{}: bought {} {} at {}'.format(time.strftime('%x %X')),
                  AMOUNT, CURRENCY_A, price_l)
            break
        if client.get_order(symbol=MARKET,
                            orderId=sell_order_id)['tatus'] is "FILLED":
            client.cancel_order(symbol=MARKET, orderId=buy_order_id)
            print('{}: sold {} {} at {}'.format(time.strftime('%x %X')),
                  AMOUNT, CURRENCY_A, price_h)
            break
示例#20
0
class BnOrder():
    def __init__(self) -> None:
        self.chat_id = BN_CHAT_ID_GROUP
        # self.chat_id = BN_CHAT_ID
        self.client = Client(BN_API_KEY, BN_API_SECRET)
        # self.client = Client(BN_TEST_API_KEY, BN_TEST_API_SECRET)
        # self.client.API_URL = 'https://testnet.binance.vision/api'
        self.client.PUBLIC_API_VERSION = "v3"
        self.bm = bn_UserSocket(self.client)
        self.tso = None

    def process_message(self, msg):
        try:
            self.send_chat_message("Account Update:\n" + json.dumps(msg))
        except Exception as e:
            logging.error("Process Account Update Error:" + str(e))
            self.send_chat_message("Process Account Update Error: " + str(e))

    def create_test_order(self, chat_id, symbol, buy_price, amount):
        try:
            if self.is_authorized(chat_id):
                symbol = symbol.strip().upper() + "BTC"
                logging.error("SYMBOL: " + symbol)

                order = self.client.create_test_order(
                    symbol=symbol,
                    side=SIDE_BUY,
                    type=ORDER_TYPE_LIMIT,
                    timeInForce=TIME_IN_FORCE_GTC,
                    quantity=amount,
                    price=buy_price)
                text = "TEST ORDER CREATED: " + json.dumps(order)
                self.send_chat_message(text)
        except Exception as e:
            logging.error("Test Order Failed error:" + str(e))
            self.send_chat_message("CREATE TEST ORDER FAILED: " + str(e))

    def create_market_buy(self, chat_id, symbol, amount, to_currency="BTC"):
        try:
            if self.is_authorized(chat_id):
                symbol = symbol.strip().upper() + to_currency.strip().upper()
                amount = round(amount, 8)
                order = self.client.order_market_buy(symbol=symbol,
                                                     quantity=amount)
                text = "REAL BUY CREATED: " + json.dumps(order)
                self.send_chat_message(text)
        except Exception as e:
            logging.error("Test Order Failed error:" + str(e))
            self.send_chat_message("CREATE ORDER FAILED: " + str(e))
            raise e

    def get_exchange_symbol(self, sell_coin, buy_coin):
        try:
            symbol = buy_coin.strip().upper() + sell_coin.strip().upper()
            info = self.client.get_symbol_info(symbol)
            if info is not None:
                result = self.client.get_symbol_ticker(symbol=symbol)
                s, t = self.get_step_size(info)
                return symbol, "BUY", result["price"], info, s, t
        except Exception as e:
            logging.error("Symbol fail:" + str(e))

        try:
            symbol = sell_coin.strip().upper() + buy_coin.strip().upper()
            info = self.client.get_symbol_info(symbol)
            if info is not None:
                result = self.client.get_symbol_ticker(symbol=symbol)
                s, t = self.get_step_size(info)
                return symbol, "SELL", result["price"], info, s, t
        except Exception as e:
            logging.error("Symbol fail:" + str(e))
            raise e

    def get_step_size(self, info):
        step_size = 0.0
        tick_size = 0.0
        logging.error("INFO:" + json.dumps(info))
        for f in info['filters']:
            if f['filterType'] == 'LOT_SIZE':
                step_size = float(f['stepSize'])
            if f['filterType'] == 'PRICE_FILTER':
                tick_size = float(f['tickSize'])
        return step_size, tick_size

    def create_market_conversion(self, chat_id, sell_coin, total_spend,
                                 buy_coin):
        try:
            if self.is_authorized(chat_id):
                symbol, sale_type, price, _, step_size, _ = self.get_exchange_symbol(
                    sell_coin, buy_coin)
                precision = int(round(-math.log(step_size, 10), 0))

                logging.error("AMOUNT:" + str(total_spend))
                logging.error("step_size:" + str(step_size))
                logging.error("precision:" + str(precision))

                logging.error("SALE TYPE:" + str(sale_type))
                if sale_type == "SELL":
                    amt_str = "{:0.0{}f}".format(total_spend, precision)
                    logging.error("QUANTITY:" + str(amt_str))
                    order = self.client.order_market_sell(symbol=symbol,
                                                          quantity=amt_str)
                    text = "SELL " + str(
                        amt_str) + " of " + symbol + "\nOrderId:" + str(
                            order["orderId"]) + " STATUS:" + str(
                                order["status"]) + "\nFILLS:\n" + json.dumps(
                                    order["fills"])

                else:
                    amount = total_spend / float(price)
                    amt_str = "{:0.0{}f}".format(amount, precision)
                    logging.error("QUANTITY:" + str(amt_str))
                    order = self.client.order_market_buy(symbol=symbol,
                                                         quantity=amt_str)
                    text = "BUY " + str(
                        amt_str) + " of " + symbol + "\nOrderId:" + str(
                            order["orderId"]) + " STATUS:" + str(
                                order["status"]) + "\nFILLS:\n" + json.dumps(
                                    order["fills"])
                self.send_chat_message(text)
                return amt_str, sale_type, symbol, buy_coin, sell_coin
        except Exception as e:
            logging.error("Order Failed error:" + str(e))
            self.send_chat_message("CREATE ORDER FAILED: " + str(e))
            raise e

    def create_trailing_stop_limit(self, market, buy_coin, sell_coin, type,
                                   stop_percentage, interval):
        try:
            if self.tso is not None and self.tso.running is True:
                self.send_chat_message(
                    "OPEN Trailing Stop Limit, Cancel First. ")
            else:
                self.tso = TrailingStopLimit(chat_id=self.chat_id,
                                             client=self.client,
                                             market=market,
                                             buy_coin=buy_coin,
                                             sell_coin=sell_coin,
                                             type=type,
                                             stop_percentage=stop_percentage,
                                             interval=interval)
                run(self.tso)
        except Exception as e:
            logging.error("Order Failed error:" + str(e))
            self.send_chat_message("CREATE ORDER FAILED: " + str(e))
            raise e

    def create_oco_conversion(self, chat_id, sell_coin, amount, buy_coin):
        try:
            if self.is_authorized(chat_id):
                symbol, sale_type, price, info, step_size, price_tick_size = self.get_exchange_symbol(
                    sell_coin, buy_coin)
                precision = int(round(-math.log(step_size, 10), 0))
                amt_str = "{:0.0{}f}".format(float(amount), precision)
                price_precision = int(round(-math.log(price_tick_size, 10), 0))
                logging.error("QUANTITY:" + str(amt_str))
                if sale_type == "SELL":
                    # BUY Orders: Limit Price < Last Price < Stop Price
                    sell_price = "{:0.0{}f}".format(
                        float(price) * 0.97, price_precision)
                    stop_price = "{:0.0{}f}".format(
                        float(price) * 1.01, price_precision)
                    stop_limit_price = "{:0.0{}f}".format(
                        float(price) * 1.01, price_precision)
                    order_oco = self.client.create_oco_order(
                        symbol=symbol,
                        side='BUY',
                        quantity=amt_str,
                        price=sell_price,
                        stopPrice=stop_price,
                        stopLimitPrice=stop_limit_price,
                        stopLimitTimeInForce='GTC')
                else:
                    # TODO check filters
                    # quantity >= minQty
                    # quantity <= maxQty
                    # (quantity-minQty) % stepSize == 0
                    # SELL Orders: Limit Price > Last Price > Stop Price
                    sell_price = "{:0.0{}f}".format(
                        float(price) * 1.03, price_precision)
                    stop_price = "{:0.0{}f}".format(
                        float(price) * 0.99, price_precision)
                    stop_limit_price = "{:0.0{}f}".format(
                        float(price) * 0.989, price_precision)
                    logging.error("CURRENT PRICE: " + str(price) +
                                  "   SELL PRICE: " + str(sell_price) +
                                  "  STOP PRICE:" + str(stop_price) +
                                  "  STOP LIMIT PRICE:" +
                                  str(stop_limit_price))
                    order_oco = self.client.create_oco_order(
                        symbol=symbol,
                        side='SELL',
                        quantity=amt_str,
                        price=sell_price,
                        stopPrice=stop_price,
                        stopLimitPrice=stop_limit_price,
                        stopLimitTimeInForce='GTC')

                oco_text = order_oco[
                    "listOrderStatus"] + " " + self.format_orders(
                        order_oco["orderReports"])
                self.send_chat_message(oco_text)
        except Exception as e:
            logging.error("OCO Failed error:" + str(e))
            self.send_chat_message("CREATE OCO FAILED: " + str(e))
            raise e

    def format_orders(self, orders):
        oco_text = "OPEN ORDERS:\n"
        for o in orders:
            if o["type"] == "STOP_LOSS_LIMIT":
                oco_text = oco_text + "\nSTOP LOSS:\n" + o["side"] + " " + o[
                    "symbol"] + "- Stop Limit: " + o[
                        "stopPrice"] + " Price: " + o["price"] + " Qty:" + o[
                            "origQty"] + "\n"
            elif o["type"] == "LIMIT_MAKER":
                oco_text = oco_text + "\nPROFIT:\n" + o["side"] + " " + o[
                    "symbol"] + "- Price: " + o["price"] + " Qty:" + o[
                        "origQty"] + "\n"
            else:
                oco_text = oco_text + "\n" + json.dumps(o) + "\n"
        oco_text = oco_text + "\nCheck Order Status with: /checkorders\n"
        oco_text = oco_text + "\nCancel All Orders with: /cancelorders\n"
        return oco_text

    def create_order(self, chat_id, selling_coin, buying_coin, price, amount):
        try:
            if self.is_authorized(chat_id):
                symbol, sale_type, price, info, step_size = self.get_exchange_symbol(
                    selling_coin, buying_coin)
                precision = int(round(-math.log(step_size, 10), 0))
                if sale_type == "SELL":
                    amt_str = "{:0.0{}f}".format(float(amount), precision)
                    order = self.client.order_limit_sell(symbol=symbol,
                                                         quantity=amt_str,
                                                         price=round(
                                                             float(price), 5))
                else:
                    amt_str = "{:0.0{}f}".format(float(amount), precision)
                    order = self.client.order_limit_buy(symbol=symbol,
                                                        quantity=amt_str,
                                                        price=round(
                                                            float(price), 5))
                text = "LIMIT ORDER CREATED:\n" + json.dumps(order)
                self.send_chat_message(text)

                # self.last_order_id = order['orderId']
                # saved_orders = r.get(LIVE_ORDER_KEY.format(self.chat_id))
                # if saved_orders is None:
                #     r.set(LIVE_ORDER_KEY.format(self.chat_id), json.dumps({"orders": [order]}))
                # else:
                #     ar = json.loads(saved_orders.decode("utf-8"))
                #     ar["orders"].append(order)
                #     r.set(LIVE_ORDER_KEY.format(self.chat_id), json.dumps(ar))
                self.check_orders(chat_id=chat_id)

        except Exception as e:
            logging.error("Test Order Failed error:" + str(e))
            self.send_chat_message("CREATE ORDER FAILED: " + str(e))

    def check_orders(self, chat_id):
        try:
            if self.is_authorized(chat_id):
                orders = self.client.get_open_orders()
                self.send_chat_message(self.format_orders(orders))

                # saved_orders = r.get(LIVE_ORDER_KEY.format(self.chat_id))
                # if saved_orders is not None:
                #     ar = json.loads(saved_orders.decode("utf-8"))
                #     self.send_chat_message("SAVED ORDERS: " + json.dumps(ar))

        except Exception as e:
            logging.error("Check Order Failed error:" + str(e))
            self.send_chat_message("CHECK ORDERS FAILED: " + str(e))

    def cancel_open_orders(self, chat_id):
        try:
            if self.is_authorized(chat_id):
                if self.tso is not None:
                    self.tso.running = False
                    FORCE_STOP = True
                orders = self.client.get_open_orders()
                for order in orders:
                    result = self.client.cancel_order(symbol=order['symbol'],
                                                      orderId=order["orderId"])
                    text = "CANCEL RESULT:\n" + json.dumps(result)
                    self.send_chat_message(text)

        except Exception as e:
            logging.error("Cancel Order Failed error:" + str(e))
            orders = self.client.get_open_orders()
            if len(orders) > 0:
                self.send_chat_message("FAILED TO CANCEL ORDER: " + str(e))

    def get_usd_price(self, symbol):
        usd_price = 0
        try:
            usd_price = self.client.get_symbol_ticker(symbol=symbol.upper() +
                                                      "USDT")
            return usd_price["price"]
        except Exception as e:
            logging.error("USD Price Failed error:" + symbol + " -- " + str(e))
        return usd_price

    def get_btc_price(self, symbol):
        btc_price = 0
        try:
            btc_price = self.client.get_symbol_ticker(symbol=symbol.upper() +
                                                      "BTC")
            return btc_price["price"]
        except Exception as e:
            logging.error("BTC Price Failed error:" + symbol + " -- " + str(e))
        return btc_price

    def round_sense(self, price):
        price = float(price)
        if price is None or price == 0:
            return 0
        if price > 1000:
            return int(price)
        if price > 100:
            return round(price, 1)
        if price > 10:
            return round(price, 2)
        if price > 0.01:
            return round(price, 4)
        if price > 0.001:
            return round(price, 5)
        return round(price, 8)

    def get_user_balance(self, symbol):
        try:
            balance = self.client.get_asset_balance(asset=symbol)
            logging.error("CHeck" + json.dumps(balance))
            return float(balance["free"])
        except Exception as e:
            logging.error("Account settings error:" + str(e))
            self.send_chat_message("FAILED TO GET BALANCE: " + str(e))
            return 0

    def get_wallet(self, chat_id):
        try:
            if self.is_authorized(chat_id):
                info = self.client.get_account()
                balances = info["balances"]
                # "balances": [{"asset": "BNB", "free": "1014.21000000", "locked": "0.00000000"}, {"asset": "BTC", "free": "0.92797152", "locked": "0.00000000"}, {"asset": "BUSD", "free": "10000.00000000", "locked": "0.00000000"}, {"asset": "ETH", "free": "100.00000000", "locked": "0.00000000"}, {"asset": "LTC", "free": "500.00000000", "locked": "0.00000000"}, {"asset": "TRX", "free": "500000.00000000", "locked": "0.00000000"}, {"asset": "USDT", "free": "10000.00000000", "locked": "0.00000000"}, {"asset": "XRP", "free": "50000.00000000", "locked": "0.00000000"}]
                out = "<pre>FREE       LOCKED      BTC      USD\n"
                val = 0
                btc_val = 0
                for b in balances:
                    quantity = float(b["free"]) + float(b["locked"])
                    if quantity > 0:
                        if b["asset"].upper() != "BETH":
                            usd_price = float(self.get_usd_price(b["asset"]))
                            btc_price = float(self.get_btc_price(b["asset"]))
                            if b["asset"].upper() in ["BUSD", "USDT"]:
                                usd_value = float(b["free"]) + float(
                                    b["locked"])
                                if btc_price > 0:
                                    btc_value = usd_value / btc_price
                                else:
                                    btc_value = 0
                            else:
                                usd_value = usd_price * quantity
                                if b["asset"].upper() == "BTC":
                                    btc_price = 1
                                    btc_value = float(b["free"]) + float(
                                        b["locked"])
                                else:
                                    btc_value = btc_price * quantity
                            val = val + usd_value
                            btc_val = btc_val + btc_value
                            out = out + "\n" + b["asset"] + " @ $" + str(
                                round(usd_price,
                                      2)) + " BTC" + str(btc_price) + "\n"
                            out = out + str(self.round_sense(b["free"])).ljust(
                                10, ' ') + " " + str(
                                    self.round_sense(b["locked"])).ljust(
                                        8, ' ') + " " + str(
                                            self.round_sense(btc_value)
                                        ).ljust(8, ' ') + " " + str(
                                            self.round_sense(usd_value)) + "\n"
                out = out + "</pre>\n$" + str(round(val, 2)) + "\n₿" + str(
                    round(btc_val, 6))
                self.send_chat_message(out)

        except Exception as e:
            logging.error("Account settings error:" + str(e))
            self.send_chat_message("FAILED TO GET WALLET: " + str(e))

    def send_chat_message(self, text):
        try:
            bot_key = TELEGRAM_BOT
            send_message_url = f'https://api.telegram.org/bot{bot_key}/sendMessage?chat_id={self.chat_id}&text={text}&parse_mode=HTML'
            resp = requests.post(send_message_url)
        except Exception as e:
            logging.error("Failed to send chat message:" + str(e))

    def is_authorized(self, chat_id):
        if self.chat_id is None or int(self.chat_id) != int(chat_id):
            raise Exception("Unauthorized Chat, use only correct chat.")
        starter = self.bm.start_user_socket(self.process_message)
        logging.error("Stream resp:" + str(starter))
        return True

    def get_symbol_trades(self, chat_id, symbol):
        try:
            if self.is_authorized(chat_id):
                trades = self.client.get_my_trades(symbol=symbol.upper() +
                                                   'BTC')
                if len(trades) > 0:
                    sorted_trades = sorted(trades,
                                           key=lambda k: k['time'],
                                           reverse=True)
                    out = "<pre>DATE TIME    SYMBOL   SIDE    PRICE     QUANTITY\n"
                    for t in sorted_trades:
                        if t["isBuyer"] == True:
                            action = "BUY"
                        else:
                            action = "SELL"
                        time_str = datetime.datetime.fromtimestamp(
                            int(t["time"]) / 1000).strftime('%d-%m %H:%M')
                        out = out + time_str + "  " + t[
                            "symbol"] + "  " + action + "  " + t[
                                "price"] + "   " + t["qty"] + "\n"
                    out = "TRADES vs BTC:\n" + out + "</pre>"
                    self.send_chat_message(out)

                trades = self.client.get_my_trades(symbol=symbol.upper() +
                                                   'USDT')
                if len(trades) > 0:
                    sorted_trades = sorted(trades,
                                           key=lambda k: k['time'],
                                           reverse=True)
                    out = "<pre>DATE TIME    SYMBOL   SIDE    PRICE     QUANTITY\n"
                    for t in sorted_trades:
                        if t["isBuyer"] == True:
                            action = "BUY"
                        else:
                            action = "SELL"
                        time_str = datetime.datetime.fromtimestamp(
                            int(t["time"]) / 1000).strftime('%d-%m %H:%M')
                        out = out + time_str + "  " + t[
                            "symbol"] + "  " + action + "  " + t[
                                "price"] + "   " + t["qty"] + "\n"
                    out = "TRADES vs USDT:\n" + out + "</pre>"
                    self.send_chat_message(out)
        except Exception as e:
            logging.error("Failed to get trades for symbol chat message:" +
                          str(e))
            self.send_chat_message("Failed to get trades for " + symbol +
                                   " -- " + str(e))
示例#21
0
                            " Oops 2 ! \n")
                    client = Client(config.API_KEY,
                                    config.API_SECRET,
                                    tld='com')
                    continue

                for tick_2 in list_of_tickers:
                    if tick_2['symbol'] == symbolTicker:
                        symbolPrice = float(tick_2['price'])
                # END GET PRICE

                if (symbolPrice < auxPrice):

                    try:
                        result = client.cancel_order(
                            symbol=symbolTicker,
                            orderId=buyOrder.get('orderId'))

                        time.sleep(3)
                    except Exception as e:
                        with open("BNBBTC_scalper.txt", "a") as myfile:
                            myfile.write(
                                str(datetime.datetime.now()) +
                                " - an exception occured - {}".format(e) +
                                "Error Canceling Oops 4 ! \n")
                        break

                    buyOrder = client.create_order(
                        symbol=symbolTicker,
                        side='BUY',
                        type='STOP_LOSS_LIMIT',
示例#22
0
    if prev == 'BTC' and current == 'None':
        pair_symbol = 'BTCUSDT'
        order_type = 'SELL'
    if prev == 'ETH' and current == 'None':
        pair_symbol = 'ETHUSDT'
        order_type = 'SELL'


    # about buy/sell
    precision = round(np.log(lot_size_dict[pair_symbol])/np.log(10))
    if precision >= 0:
        round_size = 0
    else:
        round_size = int(-precision)

    min_notional = min_notional_dict[pair_symbol]

    orders = client.get_open_orders(symbol=pair_symbol)
    print orders

    for order in orders:
        cancel_res = client.cancel_order(
                    symbol=pair_symbol,
                    orderId=order['orderId'])
        time.sleep(0.1)

    if order_type == 'BUY':
        slowly_buy(client, pair_symbol, min_notional, round_size, 1)
    elif order_type == 'SELL':
        slowly_sell(client, pair_symbol, min_notional, round_size, 1)
示例#23
0
class Binance(object):
    def __init__(self):
        print("-- Connecting to binance ...")
        self.client = Client(os.environ['BINANCE_API_KEY'],
                             os.environ['BINANCE_API_SECRET'])

    def get_balance(self, coin):
        print("-- Getting balance for " + coin)
        assetJSON = self.client.get_asset_balance(coin)
        return float(assetJSON['free'])

    def get_price(self, coin, coinfrom):
        priceJSON = self.client.get_symbol_ticker(symbol=coin + coinfrom)
        return float(priceJSON['price'])

    def buy_market(self, coin, coinfrom, ignored, quantity, testmode):
        print("-- Buying market " + str(quantity) + " " + coin + " from " +
              coinfrom)
        self.symbol = coin + coinfrom
        if testmode:
            print("[TEST] " + str(quantity) + " " + coin + " buy at : " +
                  str(ignored) + " " + coinfrom +
                  " (price is ignored on Binance)")
        else:
            orderBuy = self.client.create_order(
                symbol=coin + coinfrom,
                side=self.client.SIDE_BUY,
                type=self.client.ORDER_TYPE_MARKET,
                # timeInForce=clientBinance.TIME_IN_FORCE_GTC,
                quantity=quantity,
                # price=repr(originalPrice)
            )

            completed = False
            while not completed:
                time.sleep(0.2)
                self.orderID = orderBuy['clientOrderId']
                orderBuySt = self.client.get_order(symbol=coin + coinfrom,
                                                   orderId=self.orderID)
                print("+ Order buy status : " + orderBuySt['status'] +
                      " at : " + orderBuySt['price'])

                if not orderBuySt == self.client.ORDER_STATUS_NEW:
                    completed = True

    def sell_market(self, coin, coinTo, ignored, quantity, testmode):
        print("-- Selling market " + str(quantity) + " " + coin + " to " +
              coinTo)
        if testmode:
            print("[TEST] " + str(quantity) + " " + coin + " sell at : " +
                  str(ignored) + " " + coinTo +
                  " (price is ignored on Binance)")
        else:
            orderSell = self.client.create_test_order(
                symbol=coin + coinTo,
                side=self.client.SIDE_SELL,
                type=self.client.ORDER_TYPE_MARKET,
                # timeInForce=clientBinance.TIME_IN_FORCE_GTC,
                quantity=quantity,
                # price=repr(newPrice)
            )

            completed = False
            while not completed:
                time.sleep(0.2)
                orderSellId = orderSell['clientOrderId']
                orderSellSt = self.client.get_order(symbol=coin + coinTo,
                                                    orderId=orderSellId)
                print("+ Order sell status : " + orderSellSt['status'] +
                      " at : " + orderSellSt['price'])

                if not orderSellSt == self.client.ORDER_STATUS_NEW:
                    completed = True

    def cancel_order(self):
        print("-- Canceling order")
        self.client.cancel_order(symbol=self.symbol, orderId=self.orderID)
        self.symbol = None
        self.orderID = None
示例#24
0
class Binance(Exchange):
    def __init__(self, api_key: str = None, secret_key: str = None):
        super().__init__()
        self.client = Client(api_key, secret_key)
        filters = self.client.get_exchange_info()['symbols']
        self.filters = {
            filt['symbol']: {
                'min_order_size': Decimal(filt['filters'][1]['minQty']),
                'max_order_size': Decimal(filt['filters'][1]['maxQty']),
                'order_step': Decimal(filt['filters'][1]['stepSize']),
                'min_notional': Decimal(filt['filters'][2]['minNotional']),
                'min_price': Decimal(filt['filters'][0]['minPrice']),
                'max_price': Decimal(filt['filters'][0]['maxPrice']),
                'price_step': Decimal(filt['filters'][0]['tickSize']),
                'base': filt['quoteAsset'],
                'commodity': filt['baseAsset'],
            }
            for filt in filters
        }

    def get_mid_price_orderbooks(self, products=None):
        prices_list = self.client.get_all_tickers()
        orderbooks = []
        for price_symbol in prices_list:
            currency_pair = binance_product_to_currencies(
                price_symbol['symbol'])
            product = '_'.join(currency_pair)
            if products is not None and product not in products:
                continue
            orderbook = OrderBook(product, Decimal(price_symbol['price']))
            if orderbook.get_wall_ask() <= Decimal('1e-8'):
                continue
            orderbooks.append(orderbook)
        return orderbooks

    def get_orderbooks(self, products=None, depth: int = 1):
        if depth != 1:
            raise NotImplementedError
        if products is not None:
            products = set(products)
        return self.get_orderbooks_of_depth1(products)

    def get_orderbooks_of_depth1(self, products):
        """
        get all orderbooks with depth equal to 1, then filter out those,
        which symbol is not in specified products
        """
        books_list = self.client.get_orderbook_tickers()
        orderbooks = []
        for book in books_list:
            currency_pair = binance_product_to_currencies(book['symbol'])
            product = '_'.join(currency_pair)
            if products is not None and product not in products:
                continue
            orderbook = OrderBook(product, {
                'ask': Decimal(book['askPrice']),
                'bid': Decimal(book['bidPrice'])
            })
            if orderbook.get_wall_ask() <= Decimal('1e-8'):
                continue
            orderbooks.append(orderbook)
        return orderbooks

    def get_taker_fee(self, product):
        return Decimal('0.001')

    def get_maker_fee(self, product):
        return Decimal('0.001')

    def through_trade_currencies(self):
        return {'BTC', 'BNB', 'ETH', 'USDT'}

    def get_resources(self):
        return {
            asset_balance['asset']: Decimal(asset_balance['free'])
            for asset_balance in self.client.get_account()['balances']
            if Decimal(asset_balance['free']) > Decimal(0)
        }

    def place_limit_order(self, order):
        logger.info("creating limit order - {}".format(str(order)))
        order = self._validate_order(order)
        logger.info("validated order - {}".format(str(order)))
        if order is None:
            return
        symbol = ''.join(order.product.split('_'))
        side = order._action.name
        quantity = order._quantity
        new_order_resp_type = 'FULL'
        price = order._price
        try:
            resp = self.client.create_order(
                side=side,
                symbol=symbol,
                quantity=quantity,
                newOrderRespType=new_order_resp_type,
                price=price.to_eng_string(),
                type=self.client.ORDER_TYPE_LIMIT_MAKER)
        except BinanceAPIException as e:
            return e

        order_id = resp['orderId']
        client_order_id = resp['clientOrderId']
        logger.info("order response - {}".format(str(resp)))

        return {
            'symbol': resp['symbol'],
            'orderId': order_id,
            'clientOrderId': client_order_id
        }

    def place_market_order(self, order, price_estimates):
        """
        place market order
        uses price estimates to check min notional and resources for buy orders
        returns dict with keys
        {'orderId', 'clientOrderId', 'executed_quantity', 'mean_price'}
        with corresponding values

        also returns commission_asset: fee
        for example
        {
            "orderId": 28,
            "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
            "executed_quantity": Decimal("10.00000000"),
            "mean_price": Decimal("3998.30000000"),
            "commission_USDT": Decimal("19.99150000"),
            "commission_BNB": Decimal("11.66365227")
        }
        """
        logger.info("creating market order - {}".format(str(order)))
        order = self._validate_order(order, price_estimates)
        logger.info("validated order - {}".format(str(order)))
        if order is None:
            return
        symbol = ''.join(order.product.split('_'))
        side = order._action.name
        quantity = order._quantity
        newOrderRespType = 'FULL'
        try:
            resp = self.client.order_market(side=side,
                                            symbol=symbol,
                                            quantity=quantity,
                                            newOrderRespType=newOrderRespType)
        except BinanceAPIException as e:
            return e

        parsed_response = self.parse_market_order_response(resp)
        parsed_response['price_estimates'] = price_estimates
        parsed_response['product'] = '_'.join(
            binance_product_to_currencies(parsed_response['symbol']))
        logger.info("parsed order response - {}".format(str(parsed_response)))
        return parsed_response

    def parse_market_order_response(self, resp):
        order_id = resp['orderId']
        client_order_id = resp['clientOrderId']
        executed_quantity = Decimal(resp['executedQty'])
        fills = resp['fills']
        value = sum(
            Decimal(fill['qty']) * Decimal(fill['price']) for fill in fills)
        total_quantity = sum(Decimal(fill['qty']) for fill in fills)
        mean_price = value / total_quantity
        commissions = {}
        for fill in fills:
            if fill['commissionAsset'] not in commissions:
                commissions[fill['commissionAsset']] = Decimal()
            commissions[fill['commissionAsset']] += Decimal(fill['commission'])

        ret = {
            'symbol': resp['symbol'],
            'orderId': order_id,
            'clientOrderId': client_order_id,
            'executed_quantity': executed_quantity,
            'mean_price': mean_price,
            'side': resp['side']
        }

        for asset, fee in commissions.items():
            ret['commission_' + asset] = fee

        return ret

    def _validate_order(self, order, price_estimates=None):
        resources = self.get_resources()
        symbol = ''.join(order.product.split('_'))
        filt = self.filters[symbol]

        if order._quantity < filt['min_order_size']:
            return
        if order._quantity > filt['max_order_size']:
            order._quantity = filt['max_order_size']
        order._quantity = quantize(order._quantity, filt['order_step'])

        if order._price is not None:
            if order._price < filt['min_price']:
                return
            if order._price > filt['max_price']:
                return
            if order._price % filt['price_step'] != 0:
                order._price = quantize(order._price,
                                        filt['price_step'],
                                        down=order._action.name == 'BUY')

        if order._price is None:
            value = (price_estimates[filt['commodity']] /
                     price_estimates[filt['base']]) * order._quantity
        else:
            value = order._price * order._quantity
        if value < filt['min_notional']:
            return

        if order._action.name == 'SELL':
            if resources[filt['commodity']] < order._quantity:
                order._quantity = resources[filt['commodity']]
                order = self._validate_order(order, price_estimates)
        else:
            if order._price is None:
                price_commodity = price_estimates[filt['commodity']]
                price_base = price_estimates[filt['base']]
                price = price_commodity / price_base
            else:
                price = order._price
            if resources[filt['base']] < order._quantity * price:
                order._quantity = resources[filt['base']] / (price *
                                                             Decimal('1.0001'))
                # any number
                order = self._validate_order(order, price_estimates)
        return order

    def get_order(self, params):
        """
        symbol or product: str
        order_id or orderId: int
        client_order_id  or origClientOrderId: str, optional
        :return: similiar to example
            {
                "symbol": "LTCBTC",
                "orderId": 1,
                "clientOrderId": "myOrder1",
                "price": "0.1",
                "origQty": "1.0",
                "orig_quantity": "1.0",
                "executedQty": "0.0",
                "executed_quantity": "0.0",
                "status": "NEW",
                "timeInForce": "GTC",
                "type": "LIMIT",
                "side": "BUY",
                "stopPrice": "0.0",
                "icebergQty": "0.0",
                "time": 1499827319559
            }
        """
        logger.info("get order = {}".format(str(params)))
        d = self._parse_params(params)
        resp = self.client.get_order(**d)
        resp.update({
            'orig_quantity': resp['origQty'],
            'executed_quantity': resp['executedQty']
        })
        logger.info("get order response - {}".format(str(resp)))
        return resp

    def cancel_limit_order(self, params):
        """
        symbol or product: str
        order_id or orderId: int
        client_order_id  or origClientOrderId: str, optional
        :return: similiar to example
            {
                "symbol": "LTCBTC",
                "origClientOrderId": "myOrder1",
                "orderId": 1,
                "clientOrderId": "cancelMyOrder1"
            }
        """
        logger.info("canceled order - {}".format(str(params)))
        d = self._parse_params(params)
        try:
            resp = self.client.cancel_order(**d)
        except BinanceAPIException as e:
            if e.message != "UNKNOWN_ORDER":
                raise e
            logger.warning("Exception{code} with message ={message}".format(
                code=e.code, message=e.message))
            resp = {}
        return resp

    def _parse_params(self, params):
        d = {}
        assert 'product' in params or 'symbol' in params
        if 'product' in params:
            d['symbol'] = ''.join(params['product'].split('_'))
        else:
            d['symbol'] = params['symbol']

        if 'order_id' in params or 'orderId' in params:
            d['orderId'] = params.get('order_id') or params['orderId']
        if 'origClientOrderId' in params or 'orig_client_order_id' in params:
            d['origClientOrderId'] = params.get(
                'orig_client_order_id') or params['origClientOrderId']
        assert d.get('origClientOrderId') is not None or d.get(
            'orderId') is not None
        return d
示例#25
0
class Bclient():

    def __init__(self, apiKey, apiSecret):
        self.client = Client(apiKey, apiSecret)

    def showBalances(self):
        try:
            accountInfo = self.client.get_account()
            balances = accountInfo['balances']
            for balance in balances:
                if float(balance['free']) > 0 or float(balance['locked']) > 0:
                    print(balance['asset'] + " - " + "Quantity: " + balance['free'] + " - " + "Locked: " + balance['locked'])
        except Exception as e:
            logging.error(e)

    def showAssetBalance(self, asset):
        try:
            accountInfo = self.client.get_asset_balance(asset=asset)
            return accountInfo['free']
        except Exception as e:
            logging.error(e)

    def getTicker(self, symbol):
        try:
            ticker = self.client.get_ticker(symbol=symbol)
            print("")
            print(ticker['symbol'] + " - " + "Last Price: " + ticker['lastPrice'] + " - " + "Volume: " + ticker['volume'])
            print("Price Change: " + ticker['priceChange'] + " - " + "Percentage Change: " + ticker['priceChangePercent'] + "%")
            print("Bid Price: " + ticker['bidPrice'] + " - " + "Ask Price: " + ticker['askPrice'])
            print("")
        except Exception as e:
            logging.error(e)

    def getSymbolDetails(self, symbol):
        try:
            info = self.client.get_symbol_info(symbol)
            assetDetails = []
            assetDetails.append(info["baseAsset"])
            assetDetails.append(info["baseAssetPrecision"])
            assetDetails.append(info["quoteAsset"])
            assetDetails.append(info["quotePrecision"])
            assetDetails.append(info["filters"][2]["stepSize"])
            return assetDetails
        except Exception as e:
            logging.error(e)

    def getOrderVolume(self, assetAmount, percentage):
        try:
            percentageDecimal = float(percentage) / 100.0
            return (float(assetAmount) / percentageDecimal) / 100
        except Exception as e:
            logging.error(e)

    def getOrderPrecision(self, assetVolume, precision):
        try:
            precision = precision.rstrip("0")
            decimals = str(precision[::-1].find('.'))
            strAssetVolume = str(assetVolume)
            volumeBeforeSplit = strAssetVolume.split(".")
            volumeBeforeDecimal = str(volumeBeforeSplit[0])
            volumeAfterDecimal = str(volumeBeforeSplit[1])
            afterDecimalPrecision = volumeAfterDecimal[:int(decimals)]
            return str(volumeBeforeDecimal) + "." + str(afterDecimalPrecision)
        except Exception as e:
            logging.error(e)

    def createBuyLimitOrder(self, symbol, price, percentage):
        try:
            symbolDetails = self.getSymbolDetails(symbol)
            stepSize = symbolDetails[4]
            quoteBalance = self.showAssetBalance(asset=symbolDetails[2])
            volumeSize = self.getOrderVolume(quoteBalance, percentage)
            preciseVolumeSize = self.getOrderPrecision(volumeSize, stepSize)
            print("Quote Balance: " + quoteBalance)
            print("Quote Volume: " + str(preciseVolumeSize))
            print(self.client.order_limit_buy(symbol=symbol, quantity=str(preciseVolumeSize), price=str(price)))
        except Exception as e:
            logging.error(e)

    def createSellLimitOrder(self, symbol, price, percentage):
        try:
            symbolDetails = self.getSymbolDetails(symbol)
            stepSize = symbolDetails[4]
            baseBalance = self.showAssetBalance(asset=symbolDetails[0])
            volumeSize = self.getOrderVolume(baseBalance, percentage)
            preciseVolumeSize = self.getOrderPrecision(volumeSize, stepSize)
            print("Base Balance: " + baseBalance)
            print("Base Volume: " + str(preciseVolumeSize))
            self.client.order_limit_sell(symbol=symbol, quantity=str(preciseVolumeSize), price=str(price))
        except Exception as e:
            logging.error(e)

    def getOpenOrders(self, symbol):
        try:
            orders = self.client.get_open_orders(symbol=symbol)
            orderList = []
            for order in orders:
                time = order['time'] / 1000.0
                cleaned_quantity = ("%.2f" % float(order['origQty']))
                cleaned_time = datetime.datetime.fromtimestamp(time).strftime('%Y-%m-%d %H:%M')
                orderList.append(order['orderId'])
                print("OrderId: " + str(order['orderId']) + " -  Price: " + str(order['price']) + " -  Quantity: " + str(cleaned_quantity)+ " -  Time: " + str(cleaned_time) + "  -  Executed Qty: " + order['executedQty'])
            return orderList
        except Exception as e:
            logging.error(e)

    def cancelAllOpenOrders(self, symbol):
        try:
            orders = self.getOpenOrders(symbol)
            for order in orders:
                cancel = self.client.cancel_order(symbol=symbol, orderId=order)
                print("Order Id: " + str(cancel['orderId']) + " - " + "is " + cancel['status'])
        except Exception as e:
            logging.error(e)
示例#26
0
class BinanceStore(with_metaclass(MetaSingleton, object)):
    _GRANULARITIES = {
        (TimeFrame.Minutes, 1): '1m',
        (TimeFrame.Minutes, 3): '3m',
        (TimeFrame.Minutes, 5): '5m',
        (TimeFrame.Minutes, 15): '15m',
        (TimeFrame.Minutes, 30): '30m',
        (TimeFrame.Minutes, 60): '1h',
        (TimeFrame.Minutes, 120): '2h',
        (TimeFrame.Minutes, 240): '4h',
        (TimeFrame.Minutes, 360): '6h',
        (TimeFrame.Minutes, 480): '8h',
        (TimeFrame.Minutes, 720): '12h',
        (TimeFrame.Days, 1): '1d',
        (TimeFrame.Days, 3): '3d',
        (TimeFrame.Weeks, 1): '1w',
        (TimeFrame.Months, 1): '1M',
    }

    BrokerCls = None  # Broker class will autoregister
    DataCls = None  # Data class will auto register

    @classmethod
    def getdata(cls, *args, **kwargs):
        """Returns ``DataCls`` with args, kwargs"""
        return cls.DataCls(*args, **kwargs)

    @classmethod
    def getbroker(cls, *args, **kwargs):
        """Returns broker with *args, **kwargs from registered ``BrokerCls``"""
        return cls.BrokerCls(*args, **kwargs)

    def __init__(self,
                 api_key,
                 api_secret,
                 coin_refer,
                 coin_target,
                 retries=5):
        self.binance = Client(api_key, api_secret)
        self.binance_socket = BinanceSocketManager(self.binance)
        self.coin_refer = coin_refer
        self.coin_target = coin_target
        self.retries = retries

        self._precision = None
        self._step_size = None

        self._cash = 0
        self._value = 0
        self.get_balance()

    def retry(method):
        @wraps(method)
        def retry_method(self, *args, **kwargs):
            for i in range(self.retries):
                time.sleep(500 / 1000)  # Rate limit
                try:
                    return method(self, *args, **kwargs)
                except BinanceAPIException:
                    if i == self.retries - 1:
                        raise

        return retry_method

    @retry
    def cancel_order(self, order_id):
        try:
            self.binance.cancel_order(symbol=self.symbol, orderId=order_id)
        except BinanceAPIException as api_err:
            if api_err.code == -2011:  # Order filled
                return
            else:
                raise api_err
        except Exception as err:
            raise err

    @retry
    def create_order(self, side, type, size, price):
        return self.binance.create_order(symbol=self.symbol,
                                         side=side,
                                         type=type,
                                         timeInForce=TIME_IN_FORCE_GTC,
                                         quantity=self.format_quantity(size),
                                         price=self.strprecision(price))

    @retry
    def close_open_orders(self):
        orders = self.binance.get_open_orders(symbol=self.symbol)
        for o in orders:
            self.cancel_order(o['orderId'])

    def format_quantity(self, size):
        precision = self.step_size.find('1') - 1
        if precision > 0:
            return '{:0.0{}f}'.format(size, precision)
        return floor(int(size))

    @retry
    def get_asset_balance(self, asset):
        balance = self.binance.get_asset_balance(asset)
        return float(balance['free']), float(balance['locked'])

    def get_balance(self):
        free, locked = self.get_asset_balance(self.coin_target)
        self._cash = free
        self._value = free + locked

    def get_interval(self, timeframe, compression):
        return self._GRANULARITIES.get((timeframe, compression))

    def get_precision(self):
        symbol_info = self.get_symbol_info(self.symbol)
        self._precision = symbol_info['baseAssetPrecision']

    def get_step_size(self):
        symbol_info = self.get_symbol_info(self.symbol)
        for f in symbol_info['filters']:
            if f['filterType'] == 'LOT_SIZE':
                self._step_size = f['stepSize']

    @retry
    def get_symbol_info(self, symbol):
        return self.binance.get_symbol_info(symbol)

    @property
    def precision(self):
        if not self._precision:
            self.get_precision()
        return self._precision

    def start_socket(self):
        if self.binance_socket.is_alive():
            return

        self.binance_socket.daemon = True
        self.binance_socket.start()

    @property
    def step_size(self):
        if not self._step_size:
            self.get_step_size()

        return self._step_size

    def stop_socket(self):
        self.binance_socket.close()
        reactor.stop()
        self.binance_socket.join()

    def strprecision(self, value):
        return '{:.{}f}'.format(value, self.precision)

    @property
    def symbol(self):
        return '{}{}'.format(self.coin_refer, self.coin_target)
示例#27
0
class BinanceApi(object):
    def __init__(self, api_key, api_secret, order_currency, payment_currency):
        self.api_key = api_key
        self.api_secret = api_secret
        self.client = Client(self.api_key, self.api_secret)
        self.bsm = BinanceSocketManager(client=self.client)
        self.orders = {}
        self.asset_balance = {}
        self.order_currency = order_currency
        self.payment_currency = payment_currency
        self.symbol = self.order_currency + self.payment_currency
        self.current_price = {}
        self.current_depth = {}
        self.bsm.start_symbol_ticker_socket(self.symbol,
                                            self._process_ticker_message)
        self.bsm.start_depth_socket(self.symbol, self._process_depth_message,
                                    BinanceSocketManager.WEBSOCKET_DEPTH_5)
        self.bsm.start_user_socket(self._process_user_info_message)
        self.bsm.start()
        self._set_asset_balance()

    def _process_ticker_message(self, msg):
        self.current_price = {
            "price": float(msg['c']),
            "timestamp": time.time() * 1000
        }
        #print self.current_price

    def _process_depth_message(self, msg):
        asks_depth = []
        bids_depth = []
        for ask in msg['asks']:
            asks_depth.append({
                "price": float(ask[0]),
                "quantity": float(ask[1])
            })
        for bid in msg['bids']:
            bids_depth.append({
                "price": float(bid[0]),
                "quantity": float(bid[1])
            })
        self.current_depth = {
            "asks": asks_depth,
            "bids": bids_depth,
            "timestamp": time.time() * 1000
        }
        #print self.current_depth

    def _process_user_info_message(self, msg):
        #print msg
        if msg['e'].encode('utf-8') == "outboundAccountInfo":
            '''TODO: 用户数据入库'''
            found = 0
            for balance in msg['B']:
                if balance['a'].encode('utf-8') == self.order_currency:
                    self.asset_balance[self.order_currency] = {
                        "free": float(balance['f']),
                        "locked": float(balance['l'])
                    }
                    found += 1
                elif balance['a'].encode('utf-8') == self.payment_currency:
                    self.asset_balance[self.payment_currency] = {
                        "free": float(balance['f']),
                        "locked": float(balance['l'])
                    }
                    found += 1
                elif found >= 2:
                    break
                else:
                    continue
            conn.execute('INSERT INTO asset_info  VALUES (?,?,?,?,?,?)', [
                str(uuid.uuid1()),
                self.asset_balance[self.order_currency]['free'] +
                self.asset_balance[self.order_currency]['locked'], 0.0,
                self.asset_balance[self.payment_currency]['free'] +
                self.asset_balance[self.payment_currency]['locked'], 'binance',
                time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            ])
            conn.commit()
        elif msg['e'].encode('utf-8') == "executionReport":
            if not self.orders.has_key(msg['i']):
                time.sleep(1)
            self.orders[msg['i']]['status'] = msg['X'].encode('utf-8')
            if msg['X'].encode('utf-8') in ["FILLED", "PARTIALLY_FILLED"]:
                trade = {
                    'trade_id':
                    msg['t'],
                    'commission':
                    float(msg['n']),
                    'commissionAsset':
                    msg['N'].encode('utf-8'),
                    'price':
                    float(msg['L']),
                    'quantity':
                    float(msg['l']),
                    'order_id':
                    msg['i'],
                    'date_time':
                    time.strftime("%Y-%m-%d %H:%M:%S",
                                  time.localtime(msg['T'] / 1000))
                }
                self.orders[msg['i']]['trades'][trade['trade_id']] = trade

                self.orders[msg['i']]['deal_quantity'] += trade['quantity']
                self.orders[msg['i']][
                    'deal_amount'] += trade['quantity'] * trade['price']
                self.orders[msg['i']]['deal_fee'] += trade['commission']
                '''手续费记录方式可能会存在问题,多币种咋办'''
                if self.orders[
                        msg['i']]['fee_asset'] != trade['commissionAsset']:
                    self.orders[msg['i']][
                        'fee_asset'] += trade['commissionAsset'] + ' '
                self.orders[msg['i']]['deal_price'] = self.orders[msg['i']][
                    'deal_amount'] / self.orders[msg['i']]['deal_quantity']

    def _set_asset_balance(self):
        tries = 0
        '''sleep?'''
        while tries < 5:
            try:
                asset = self.client.get_asset_balance(self.payment_currency)
            except BinanceAPIException as e:
                print e.code, e.message
                tries += 1
                continue
            if asset is not None:
                self.asset_balance[asset['asset']] = {
                    "free": float(asset['free']),
                    'locked': float(asset['locked'])
                }
                break
            time.sleep(0.5)
        if tries == 5:
            print "get asset balance failed! "
            return

        tries = 0
        while tries < 5:
            try:
                asset = self.client.get_asset_balance(self.order_currency)
            except BinanceAPIException as e:
                print e.code, e.message
                tries += 1
                continue
            if asset is not None:
                self.asset_balance[asset['asset']] = {
                    "free": float(asset['free']),
                    'locked': float(asset['locked'])
                }
                break
            time.sleep(0.5)
        if tries == 5:
            print "get asset balance failed! "
            return

    def get_current_price(self):
        return self.current_price

    def get_current_depth(self):
        return self.current_depth

    def create_order(self, side, price, quantity):
        try:
            order_info = self.client.create_order(
                symbol=self.symbol,
                side=side,
                type=ORDER_TYPE_LIMIT,
                price=str(price),
                quantity=quantity,
                timeInForce=TIME_IN_FORCE_GTC)
        except BinanceAPIException as e:
            return -1, {"code": e.code, "message": e.message}

        self.orders[order_info['orderId']] = {
            "side":
            side,
            "order_quantity":
            float(order_info['origQty']),
            "symbol":
            self.symbol,
            "order_price":
            float(order_info['price']),
            "status":
            order_info['status'].encode('utf-8'),
            'date_time':
            time.strftime("%Y-%m-%d %H:%M:%S",
                          time.localtime(order_info['transactTime'] / 1000)),
            'deal_quantity':
            0,
            'order_amount':
            float(order_info['price']) * float(order_info['origQty']),
            'deal_amount':
            0,
            'deal_fee':
            0,
            'fee_asset':
            '',
            'deal_price':
            0,
            'trades': {}
        }

        return order_info['orderId'], self.orders[order_info['orderId']]

    '''def order_buy(self, price, quantity, order_type=ORDER_TYPE_LIMIT):
        if order_type is ORDER_TYPE_LIMIT:
            try:
                order = self.client.order_limit_buy(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}
        else:
            try:
                order = self.client.order_market_buy(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}

        self.orders[order['orderId']] = {"side": "bid", "executedQty": [], "origQty": float(order['origQty']), "currency": self.symbol,
                                         "price": float(order['price']), "status": order['status'].encode('utf-8')}
        return order['orderId'], self.orders[order['orderId']]

    def order_sell(self, price, quantity, order_type=ORDER_TYPE_LIMIT):
        if order_type is ORDER_TYPE_LIMIT:
            try:
                order = self.client.order_limit_sell(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}
        else:
            try:
                order = self.client.order_market_sell(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}

        #self.orders[order_id] = "NEW"
        self.orders[order['orderId']] = {"side": "ask", "executedQty": [], "origQty": float(order['origQty']),"symbol": self.symbol,
                                         "price": float(order['price']), "status": order['status'].encode('utf-8')}
        return order['orderId'], self.orders[order['orderId']]'''

    def order_cancel(self, order_id):
        try:
            result = self.client.cancel_order(symbol=self.symbol,
                                              orderId=order_id)
        except BinanceAPIException as e:
            return -1, {"code": e.code, "message": e.message}
        #self.orders[result['orderId']]["status"] = "CANCELED"
        return result['orderId'], self.orders[result['orderId']]

    def get_order_info(self, order_id):
        if self.orders.has_key(order_id):
            if abs(self.orders[order_id]['order_quantity'] -
                   self.orders[order_id]['deal_quantity']) < 0.0001:
                self.orders[order_id]['status'] = 'FILLED'
            elif self.orders[order_id]['deal_quantity'] == 0:
                self.orders[order_id]['status'] = 'PARTIALLY_FILLED'
            return self.orders[order_id]
        return None

    def check_balance(self, currency):
        return self.asset_balance[currency]

    def get_asset_balance(self):
        return self.asset_balance

    def get_all_trade(self, order_id):
        return self.client.get_my_trades(symbol=self.symbol)

    def get_symbol_info(self, symbol):
        return self.client.get_symbol_info(symbol=symbol)
示例#28
0
class Market:
    def __init__(self):
        self.client = Client(api_key=apiKey, api_secret=apiSecret, tld='us')

    def buy_coin_possible(self, symbol, percentOfEquity):
        # Get equity amount of our USD, BTC, ETH
        accountValue = float(self.client.get_asset_balance("USD")["free"])
        accountValue += float(
            self.client.get_asset_balance("BTC")["free"]) * float(
                self.client.get_symbol_ticker(symbol="BTCUSD")["price"])
        accountValue += float(
            self.client.get_asset_balance("ETH")["free"]) * float(
                self.client.get_symbol_ticker(symbol="ETHUSD")["price"])

        # calculate how much of the symbol that is
        moneyToSpend = percentOfEquity * accountValue / 100.0
        symbolQuantity = moneyToSpend / float(
            self.client.get_symbol_ticker(symbol=symbol)["price"])

        # get recent trades to see current volatility
        recentTrades = self.client.get_recent_trades(symbol=symbol)
        lastTrade = {}
        totalSum = 0
        weightedSum = 0
        for trade in recentTrades:
            if lastTrade == {} or int(trade["time"]) > int(lastTrade["time"]):
                lastTrade = trade
            totalSum += float(trade["qty"])
            weightedSum += float(trade["price"]) * float(trade["qty"])
        weightedAvg = weightedSum / totalSum

        # calculate the price we should strive for with current volatility
        symbolQtyAdjustedBefore = symbolQuantity * (1.0 - takerFee)
        symbolQtyAdjustedAfter = symbolQtyAdjustedBefore * (1.0 - takerFee)
        endProfitPrice = 0
        if weightedAvg > float(lastTrade["price"]):
            endProfitPrice = weightedAvg + (weightedAvg -
                                            float(lastTrade["price"])) * .5
        else:
            endProfitPrice = float(
                lastTrade["price"]) + abs(weightedAvg -
                                          float(lastTrade["price"])) * .5

        # calculate stop loss at 3 : 1 risk ratio using expected profit
        expectedProfit = (endProfitPrice * symbolQtyAdjustedAfter) - (
            float(lastTrade["price"]) * symbolQtyAdjustedAfter)
        if expectedProfit <= 0:
            return
        stopLossPrice = float(lastTrade["price"]) - expectedProfit * (1 / 3)
        # possibleLoss = (stopLossPrice * symbolQtyAdjusted) - (float(lastTrade["price"]) * symbolQtyAdjusted) # for reference

        # set the limit buy so we get it at the price we want hopefully
        order = None
        try:
            order = self.client.order_limit_buy(
                symbol=symbol,
                quantity="{:0.0{}f}".format(symbolQuantity, 3),
                price="{:0.0{}f}".format(
                    float(lastTrade["price"]) +
                    float(lastTrade["price"]) * .001, 2),
            )
        except exceptions.BinanceAPIException as e:
            print(e)
            return

        # wait 3 seconds.  usually small orders will go through immediately but if this scales it wouldn't
        time.sleep(5)

        # see if it went through at our price, otherwise cancel it
        if order is not None:
            for openOrder in self.client.get_open_orders():
                if order["orderId"] == openOrder["orderId"]:
                    self.client.cancel_order(symbol=symbol,
                                             orderId=order["orderId"])
                    return

        try:
            # set our end/expected price for this trade
            self.client.order_limit_sell(
                symbol=symbol,
                quantity="{:0.0{}f}".format(symbolQtyAdjustedBefore, 3),
                price="{:0.0{}f}".format(endProfitPrice, 2))

            self.client.create_order(
                symbol=symbol,
                side=Client.SIDE_SELL,
                type=Client.ORDER_TYPE_STOP_LOSS_LIMIT,
                quantity="{:0.0{}f}".format(symbolQtyAdjustedBefore, 3),
                price="{:0.0{}f}".format(stopLossPrice, 2),
                stopPrice="{:0.0{}f}".format(stopLossPrice + .01, 2),
                timeInForce=Client.TIME_IN_FORCE_GTC)
        except exceptions.BinanceAPIException as e:
            print(e)
            return

    def get_symbol_price(self, symbol):
        recentTrades = self.client.get_recent_trades(symbol=symbol)
        lastTrade = {}

        for trade in recentTrades:
            if lastTrade == {} or int(trade["time"]) > int(lastTrade["time"]):
                lastTrade = trade

        return float(lastTrade["price"])

    def get_account_value(self):
        valueInUSD = 0.0
        usdBalance = self.client.get_asset_balance("USD")
        valueInUSD = valueInUSD + float(usdBalance["free"]) + float(
            usdBalance["locked"])
        time.sleep(.1)

        ethBalance = self.client.get_asset_balance("ETH")
        ethPrice = self.get_symbol_price("ETHUSD")
        valueInUSD = valueInUSD + float(ethBalance["free"]) * ethPrice + float(
            ethBalance["locked"]) * ethPrice
        time.sleep(.1)

        btcBalance = self.client.get_asset_balance("BTC")
        btcPrice = self.get_symbol_price("BTCUSD")
        valueInUSD = valueInUSD + float(btcBalance["free"]) * btcPrice + float(
            btcBalance["locked"]) * btcPrice
        time.sleep(.1)

        return valueInUSD
示例#29
0
from binance.exceptions import BinanceAPIException, BinanceWithdrawException, BinanceRequestException

try:
    client = Client(os.getenv('BINANCE_APIKEY', 'NOTDEF_APIKEY'),
                    os.getenv('BINANCE_SEKKEY', 'NOTDEF_APIKEY'), {
                        "verify": True,
                        "timeout": 20
                    })

    print('--- OPEN ORDERS ---------------------------------------')
    print(client.get_open_orders())

    print('--- CANCEL ORDER --------------------------------------')
    if len(sys.argv) == 3:
        try:
            result = client.cancel_order(symbol=sys.argv[1],
                                         orderId=sys.argv[2])
        except BinanceAPIException as e:
            print(f'Binance API exception: {e.status_code} - {e.message}')
            sys.exit(1)

        print(f'Result: {result}')
    else:
        print(f'run: {sys.argv[0]} SYMBOL ORDER_ID')

except BinanceAPIException as e:
    print(f'Binance API exception: {e.status_code} - {e.message}')

except BinanceRequestException as e:
    print(f'Binance request exception: {e.status_code} - {e.message}')

except BinanceWithdrawException as e:
示例#30
0
class TradeEngineBinance(TradeEngineBase):
    def __init__(self, marketname):
        super(TradeEngineBinance, self).__init__(marketname)

        # variables which start with uppercase letter may have configuration in setting.json
        self.ApiKey = ''
        self.SeceretKey = ''
        self.LotSize = 0.001
        self.PriceSpread = 0.01
        self.VolumePrecision = 6
        self.PricePrecision = 2
        self.RecvWindow = 30000

        self.load_setting()

        self.client_api = None

        SQLog.info("__init__,marketname=", marketname, "self.__dict__=",
                   self.__dict__)

    def open_api(self):
        SQLog.info("open_api,quote already open=", self.is_open())
        self.client_api = Client(self.ApiKey, self.SeceretKey)

        for stockcode in self.get_stockcode_pools():
            cc_coin = stockcode.split('.')
            instrument_id = cc_coin[1].upper() + 'USDT'
            result = self.client_api.get_open_orders(
                symbol=instrument_id, recvWindow=self.RecvWindow)
            for op in result:
                self.order_handler(
                    'CC.' + cc_coin[1].upper() + '.' + str(op.get('orderId')),
                    'CC.' + cc_coin[1].upper(), False,
                    SIDE_BUY == op.get('side').upper(), None,
                    float(op.get('executedQty')), float(op.get('origQty')),
                    float(op.get('price')))
        return True

    def close_api(self):
        super().close_api()
        self.client_api = None
        SQLog.info("close_api")
        return True

    def is_open(self):
        return not self.client_api is None

    def call_get_account(self):
        result = self.client_api.get_account(recvWindow=self.RecvWindow)
        with self.account_lock:
            self.nowstocks_dict.clear()
            self.nowasserts_total = 0
            if 'balances' in result:
                for coin in result['balances']:
                    if 'USDT' == coin.get('asset').upper():
                        self.nowbalance = float(coin.get('free')) + float(
                            coin.get('locked'))
                        self.nowpower = float(coin.get('free'))
                        self.nowasserts_total += self.nowbalance
                    elif float(coin.get('free')) + float(
                            coin.get('locked')) > self.LotSize:
                        self.nowstocks_dict['CC.' +
                                            coin.get('asset').upper()] = {
                                                'qty':
                                                float(coin.get('free')) +
                                                float(coin.get('locked'))
                                            }
                        self.nowasserts_total += self.quotes_dict.get(
                            'CC.' + coin.get('asset').upper(), {}).get(
                                'last_price', 0) * (float(coin.get('free')) +
                                                    float(coin.get('locked')))
        SQLog.info("call_get_account,nowbalance=", self.nowbalance,
                   "nowpower=", self.nowpower, "nowasserts_total=",
                   self.nowasserts_total, "nowstocks_dict=",
                   self.nowstocks_dict)
        return [True, self.nowbalance, self.nowstocks_dict]

    def call_get_market_snapshot(self, stockcodes):
        self.nowasserts_total = self.nowbalance
        for code in stockcodes:
            if code not in self.get_stockcode_pools(
            ) and not code == self.get_default_stock():
                continue

            cc_coin = code.split('.')
            ticker = self.client_api.get_ticker(symbol=cc_coin[1].upper() +
                                                'USDT')
            if code not in self.quotes_dict:
                self.quotes_dict[code] = {}
            q = self.quotes_dict[code]
            q['lot_size'] = self.LotSize
            q['price_spread'] = self.PriceSpread
            q['suspension'] = False
            q['last_price'] = float(ticker['lastPrice'])
            q['ask_price'] = float(ticker['askPrice'])
            q['bid_price'] = float(ticker['bidPrice'])
            if code in self.nowstocks_dict:
                self.nowasserts_total += q['last_price'] * float(
                    self.nowstocks_dict.get(code, {}).get('qty', 0))
        SQLog.info("call_get_market_snapshot,nowasserts_total=",
                   self.nowasserts_total, "quotes_dict=", self.quotes_dict)
        return [True, self.quotes_dict]

    def call_get_average_volatility(self, stockcode):
        cc_coin = stockcode.split('.')
        result = self.client_api.get_klines(
            symbol=cc_coin[1].upper() + 'USDT',
            interval=Client.KLINE_INTERVAL_1DAY,
            limit=50)
        #period = 7
        period = 3
        if len(result) >= max(period, 6):
            sumcloses = 0.0
            for j in range(-1, -1 - period, -1):
                sumcloses += float(result[j][4])
            average = round(sumcloses / period, self.precision(stockcode))

            sumv = 0.0
            for i in range(-1, -6, -1):
                sumv += abs(float(result[i][2]) / float(result[i][3]) -
                            1) if float(result[i][3]) > 0 else 0
                sumv += abs(float(result[i][4]) / float(result[i - 1][4]) -
                            1) if float(result[i - 1][4]) > 0 else 0
            volatility = round(sumv / 10, 6)
            SQLog.info("call_get_average_volatility,stockcode=", stockcode,
                       "average=", average, "volatility=", volatility)
            return [average, volatility]
        else:
            SQLog.warn(
                "call_get_average_volatility,result too small,stockcode=",
                stockcode, "result=", result)
            return [0, 0]

    def call_place_order(self, stockcode, volume, price, isbuy, ismarketorder):
        volume_v, price_v = self.round_order_param(stockcode, volume, price,
                                                   isbuy, ismarketorder)
        if volume_v <= 0:
            SQLog.info("call_place_order failed,volume_v<=0,stockcode=",
                       stockcode, "volume=", volume, "volume_v=", volume_v,
                       "price=", price, "price_v=", price_v, "isbuy=", isbuy,
                       "ismarketorder=", ismarketorder)
            return None
        if 0 == price_v and not ismarketorder:
            SQLog.info("call_place_order failed,price==0,stockcode=",
                       stockcode, "volume=", volume, "price=", price, "isbuy=",
                       isbuy, "ismarketorder=", ismarketorder)
            return None

        cc_coin = stockcode.split('.')
        instrument_id = cc_coin[1].upper() + 'USDT'

        if isbuy:
            result = self.client_api.order_limit_buy(
                symbol=instrument_id,
                quantity=round(volume_v, self.VolumePrecision),
                price=str(round(price_v, self.PricePrecision)),
                recvWindow=self.RecvWindow)
        else:
            result = self.client_api.order_limit_sell(
                symbol=instrument_id,
                quantity=round(volume_v, self.VolumePrecision),
                price=str(round(price_v, self.PricePrecision)),
                recvWindow=self.RecvWindow)
        if result.get('status') in [
                ORDER_STATUS_NEW, ORDER_STATUS_PARTIALLY_FILLED,
                ORDER_STATUS_FILLED
        ]:
            ret_oid = stockcode + '.' + str(result.get('orderId'))
            if isbuy:
                self.nowpower -= (volume_v * price_v * self.MaxFees)
            self.order_handler(ret_oid, stockcode, None, isbuy, None, None,
                               volume_v, price_v)
            SQLog.info("call_place_order,stockcode=", stockcode, "volume=",
                       volume, "volume_v=", volume_v, "price=", price,
                       "price_v=", price_v, "isbuy=", isbuy, "ismarketorder=",
                       ismarketorder, "orderid=", ret_oid)
            SQLog.info("--------------------PlaceOrderOK--------------------",
                       stockcode, "--------------------",
                       'BUY' if isbuy else 'SELL', volume_v, '@ ', price_v,
                       "--------------------", ret_oid)
            return stockcode + '.' + str(result.get('orderId'))
        else:
            raise Exception("call_place_order failed,timeout,stockcode=" +
                            stockcode + ",volume=" + str(volume) + ",price=" +
                            str(price) + ",isbuy=" + str(isbuy) +
                            ",ismarketorder=" + str(ismarketorder))

    def call_get_order(self, orderid):
        if orderid is None:
            SQLog.info("call_get_order,orderid=", orderid, "order=None")
            return None
        cco = orderid.split('.')
        coin = cco[1]
        oid = cco[2]
        try:
            result = self.client_api.get_order(symbol=coin.upper() + 'USDT',
                                               orderId=int(oid),
                                               recvWindow=self.RecvWindow)
            self.order_handler(
                orderid, 'CC.' + coin.upper(),
                result.get('status') in [
                    ORDER_STATUS_FILLED, ORDER_STATUS_CANCELED,
                    ORDER_STATUS_REJECTED, ORDER_STATUS_EXPIRED
                ], None, None, float(result.get('executedQty')), None, None)
        except Exception as e:
            SQLog.warn("call_get_order,failed,orderid=", orderid,
                       "Exception,e=", e)
        order = self.get_order_from_cache(orderid)
        SQLog.info("call_get_order,orderid=", orderid, "order=", order)
        return order

    def call_list_order(self):
        orders_notclose = {}
        with self.orders_dict_lock:
            for orderid, order in self.orders_dict.items():
                if not order.get('isclose'):
                    orders_notclose[orderid] = order.copy()

        SQLog.info("call_list_order,result=", orders_notclose)
        for oid, o in orders_notclose.items():
            self.call_get_order(oid)
        return True

    def call_cancel_order(self, orderid):
        if orderid is None:
            SQLog.info("call_cancel_order,orderid=", orderid, "return False")
            return False
        cco = orderid.split('.')
        coin = cco[1]
        oid = cco[2]
        try:
            result = self.client_api.cancel_order(symbol=coin.upper() + 'USDT',
                                                  orderId=int(oid),
                                                  recvWindow=self.RecvWindow)
            SQLog.info("call_cancel_order,orderid=", orderid, ",result=",
                       result)
            return True
        except Exception as e:
            SQLog.info("call_cancel_order,orderid=", orderid,
                       ",result=False,e=", e)
            return False

    def call_cancel_all_orders(self):
        orders_notclose = {}
        with self.orders_dict_lock:
            for orderid, order in self.orders_dict.items():
                if not order.get('isclose'):
                    orders_notclose[orderid] = order.copy()
        for oid, o in orders_notclose.items():
            self.call_cancel_order(oid)
        SQLog.info("call_cancel_all_orders")
        return True