class OrderManager:
    def __init__(self):
        self.client = Client(api_key=os.getenv('API_KEY', ''),
                             api_secret=os.getenv('SECRET_KEY', ''))

    def get_detailed_open_orders(self) -> List[DetailedOrder]:
        return [
            DetailedOrder(**order) for order in (self.client.get_open_orders())
        ]

    def get_open_orders_symbols(self) -> List[str]:
        return [
            order.get_symbol() for order in (self.get_detailed_open_orders())
        ]

    def get_open_orders(self) -> List[Order]:
        return [
            order.get_order() for order in (self.get_detailed_open_orders())
        ]

    def get_filled_order(self, symbol: str) -> List[DetailedOrder]:
        return [
            DetailedOrder(**order)
            for order in (self.client.get_all_orders(symbol=symbol))
        ]

    def is_order_filled(self, order: Order) -> bool:
        return self.get_order(order).is_cancelled

    def get_order(self, order: Order) -> DetailedOrder:
        order = self.client.get_all_orders(symbol=order.symbol,
                                           orderId=order.orderId)[0]
        return DetailedOrder(**order)
Beispiel #2
0
    def test_check_Binance_valid_credentials(self):
        error_raised = False

        api_key = os.getenv('Binance_API_Key')
        api_secret = os.getenv('Binance_API_Secret')

        try:
            client = ClientBinance(api_key, api_secret, {
                "verify": True,
                "timeout": 20
            })
            client.get_all_orders(symbol='BNBBTC', limit=1)
        except:
            error_raised = True
        self.assertFalse(error_raised, "Invalid Bianance credentials")
Beispiel #3
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)
class SystemClient:
    """Modified model of binance Client Model.
    Symbol is hardcoded due to task system rules,
    can be simply refactored.

    API Keys are hardcoded too, but can be simply refactored.
    """

    def __init__(self, sys_name):
        self.name = sys_name
        self.client = Client(Config.API_KEY, Config.API_SECRET)
        self.client.API_URL = Config.API_URL
    
    def get_balance(self):
        self.balance = self.client.get_account()['balances']
        return self.balance
    
    def get_trades(self):
        result_list = []
        self.trades = self.client.get_all_orders(symbol='BTCUSDT')

        for trade in self.trades:
            result_dict = {}
            result_dict['OrderID'] = trade['orderId']
            result_dict['OrderSymbol'] = trade['symbol']
            result_dict['OrderSide'] = trade['side']
            result_dict['ExecutionStatus'] = trade['status']
            result_dict['OriginalVolume'] = trade['origQty']
            result_dict['ExecutedVolume'] = trade['executedQty']
            result_dict['time'] = datetime.fromtimestamp(trade['time'] / 1000)

            result_list.append(result_dict)

        return result_list
Beispiel #5
0
def start(client) -> None:
    """start of the program"""

    # gets server time in UNIX
    server_time = client.get_server_time()

    # makes server time readable to normal people
    readable_time = datetime.datetime.fromtimestamp(
        round(server_time["serverTime"]) / 1000).strftime('%Y-%m-%d %H:%M:%S')

    print(server_time["serverTime"], "-", readable_time)

    # loop forever
    while True:

        client = Client(api["neo 0.076 8h 21"]["pub"],
                        api["neo 0.076 8h 21"]["priv"])

        # gets last order created
        last_trade = client.get_all_orders(symbol="WBTCBTC", limit=1)

        # starts main function
        main(client, last_trade)

        # sleeps for 61 seconds for funzies
        sleep(61)
Beispiel #6
0
def binance_get_all_orders(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.get_all_orders(**params)
        print(js_info)
        return js_info
    except Exception as e:
        print(e)
Beispiel #7
0
class market_api(object):

	def __init__(self):
		self.client = Client(cfg.api_keys['key'],cfg.api_keys['secret'], {"verify": True, "timeout": 20})

	def get_all_orders(self,symbol='VENETH'):
		return self.client.get_all_orders(symbol=symbol, requests_params={'timeout': 5})

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

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

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

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

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

	def get_latest_trades(self,symbol):
		return self.client.get_recent_trades(symbol=symbol)

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

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

	def get_tickers(self):
		return self.client.get_ticker()

	def get_all_prices(self):
		return self.client.get_all_tickers()

	def get_orderbook_tickers(self):
		return self.client.get_orderbook_tickers()
Beispiel #8
0
class BinanceClient():
    def __init__(self,
                 api_key=os.getenv("BINANCE_API_KEY"),
                 api_secret=os.getenv("BINANCE_API_SECRET")):
        self._client = Client(api_key, api_secret)

    def get_orders(self, symbol):
        all_orders = self._client.get_all_orders(symbol=symbol)
        orders = []
        for order in all_orders:
            if order['status'] == "FILLED":
                orders.append(order)
        return orders

    def get_base_pair(self, symbol):
        return symbol[:3]

    def get_klines(self, symbol):
        # Get price on order date
        # klines = client.get_historical_klines("ETHBTC", Client.KLINE_INTERVAL_30MINUTE, "1 Dec, 2017", "1 Jan, 2018")
        order_dt = datetime.datetime.utcfromtimestamp(order['time'] / 1000)
        order_dt_formatted = order_dt.strftime("%d %b, %Y")
        klines = self._client.get_historical_klines(
            pair, Client.KLINE_INTERVAL_30MINUTE, order_dt_formatted,
            order_dt_formatted)
        print(klines)
        # print ("order_datetime={order_datetime}".format(order_datetime=order_datetime))

    def get_base_pair_total(self, base_pair):
        alt_pairs = ALT_PAIRS[base_pair] if base_pair in ALT_PAIRS else None
        # print (alt_pairs)
        total = 0.0
        if alt_pairs is not None:
            for pair in alt_pairs:
                orders = self.get_orders(pair)
                for order in orders:
                    total += float(order['origQty']) * float(order['price'])
        return total
Beispiel #9
0
def GET_ALL_ORDERS(LOG,univ,out_file):

	LOG.write(TimeStamp() + "GET_ALL_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("symbol\torderId\tclientOrderId\tprice\torigQty\texecutedQty\tstatus\ttimeInForce\ttype\tside\tstopPrice\ticebergQty\ttime\tTS\n")
	for u in univ:
		if (u == "BTC"):
			continue
		try:
			sym = u + "BTC"
			#print(sym)
			data = client.get_all_orders(symbol=sym)
			if data is None:
				continue
			for T in data:
				TS = TimeStampUnixDateTime(T['time'])
				S = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' %    \
				    (u,T['orderId'],T['clientOrderId'],T['price'],T['origQty'], \
				       T['executedQty'],T['status'],T['timeInForce'],T['type'], \
				       T['side'],T['stopPrice'],T['icebergQty'],T['time'],TS)
				F.write(S)

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

	F.close()
Beispiel #10
0
class AuthAPI(AuthAPIBase):
    def __init__(self,
                 api_key: str = '',
                 api_secret: str = '',
                 api_url: str = 'https://api.binance.com') -> None:
        """Binance API object model
    
        Parameters
        ----------
        api_key : str
            Your Binance account portfolio API key
        api_secret : str
            Your Binance account portfolio API secret
        """

        # options
        self.debug = False
        self.die_on_api_error = False

        valid_urls = [
            'https://api.binance.com/', 'https://testnet.binance.vision/api/'
        ]

        # validate Binance API
        if api_url not in valid_urls:
            raise ValueError('Binance API URL is invalid')

        if len(api_url) > 1 and api_url[-1] != '/':
            api_url = api_url + '/'

        # validates the api key is syntactically correct
        p = re.compile(r"^[A-z0-9]{64,64}$")
        if not p.match(api_key):
            self.handle_init_error('Binance API key is invalid')

        # validates the api secret is syntactically correct
        p = re.compile(r"^[A-z0-9]{64,64}$")
        if not p.match(api_secret):
            self.handle_init_error('Binance API secret is invalid')

        self.mode = 'live'  # TODO: check if this needs to be set here
        self.api_url = api_url
        self.api_key = api_key
        self.api_secret = api_secret
        self.client = Client(self.api_key, self.api_secret, {
            'verify': False,
            'timeout': 20
        })

    def handle_init_error(self, err: str) -> None:
        if self.debug:
            raise TypeError(err)
        else:
            raise SystemExit(err)

    def getClient(self) -> Client:
        return self.client

    def getAccounts(self) -> pd.DataFrame:
        """Retrieves your list of accounts"""
        accounts = self.client.get_account()

        if 'balances' not in accounts:
            return pd.DataFrame(columns=[
                'index', 'id', 'currency', 'balance', 'hold', 'available',
                'profile_id', 'trading_enabled'
            ])

        df = pd.DataFrame(self.client.get_account()['balances'])
        df.columns = ['currency', 'available', 'hold']
        df['index'] = df.index
        df['id'] = df.index
        df['balance'] = df['available']
        df['profile_id'] = ''
        df['trading_enabled'] = True

        return df[[
            'index', 'id', 'currency', 'balance', 'hold', 'available',
            'profile_id', 'trading_enabled'
        ]]

    def getAccount(self, account: int) -> pd.DataFrame:
        """Retrieves a specific account"""
        accounts = self.client.get_account()

        if 'balances' not in accounts:
            return pd.DataFrame(columns=[
                'index', 'id', 'currency', 'balance', 'hold', 'available',
                'profile_id', 'trading_enabled'
            ])

        df = pd.DataFrame(self.client.get_account()['balances'])
        df.columns = ['currency', 'available', 'hold']
        df['index'] = df.index
        df['id'] = df.index
        df['balance'] = df['available']
        df['profile_id'] = ''
        df['trading_enabled'] = True

        return df[df['id'] == account][[
            'index', 'id', 'currency', 'balance', 'hold', 'available',
            'profile_id', 'trading_enabled'
        ]]

    def getFees(self, market: str = '') -> pd.DataFrame:
        if market != '':
            resp = self.client.get_trade_fee(symbol=market)
            if 'tradeFee' in resp and len(resp['tradeFee']) > 0:
                df = pd.DataFrame(resp['tradeFee'][0], index=[0])
                df['usd_volume'] = None
                df.columns = [
                    'maker_fee_rate', 'market', 'taker_fee_rate', 'usd_volume'
                ]
                return df[[
                    'maker_fee_rate', 'taker_fee_rate', 'usd_volume', 'market'
                ]]
            return pd.DataFrame(
                columns=['maker_fee_rate', 'taker_fee_rate', 'market'])
        else:
            resp = self.client.get_trade_fee()
            if 'tradeFee' in resp:
                df = pd.DataFrame(resp['tradeFee'])
                df['usd_volume'] = None
                df.columns = [
                    'maker_fee_rate', 'market', 'taker_fee_rate', 'usd_volume'
                ]
                return df[[
                    'maker_fee_rate', 'taker_fee_rate', 'usd_volume', 'market'
                ]]
            return pd.DataFrame(
                columns=['maker_fee_rate', 'taker_fee_rate', 'market'])

    def getMakerFee(self, market: str = '') -> float:
        if market == '':
            fees = self.getFees()
        else:
            fees = self.getFees(market)

        if len(fees) == 0 or 'maker_fee_rate' not in fees:
            print(
                f"error: 'maker_fee_rate' not in fees (using {DEFAULT_MAKER_FEE_RATE} as a fallback)"
            )
            return DEFAULT_MAKER_FEE_RATE

        if market == '':
            return fees
        else:
            return float(fees['maker_fee_rate'].to_string(index=False).strip())

    def getTakerFee(self, market: str = '') -> float:
        if market == '':
            fees = self.getFees()
        else:
            fees = self.getFees(market)

        if len(fees) == 0 or 'taker_fee_rate' not in fees:
            print(
                f"error: 'taker_fee_rate' not in fees (using {DEFAULT_TAKER_FEE_RATE} as a fallback)"
            )
            return DEFAULT_TAKER_FEE_RATE

        if market == '':
            return fees
        else:
            return float(fees['taker_fee_rate'].to_string(index=False).strip())

    def __convertStatus(self, val: str) -> str:
        if val == 'filled':
            return 'done'
        else:
            return val

    def getOrders(self,
                  market: str = '',
                  action: str = '',
                  status: str = 'all') -> pd.DataFrame:
        """Retrieves your list of orders with optional filtering"""

        # if market provided
        if market != '':
            # validates the market is syntactically correct
            if not self._isMarketValid(market):
                raise ValueError('Binance market is invalid.')

        # if action provided
        if action != '':
            # validates action is either a buy or sell
            if not action in ['buy', 'sell']:
                raise ValueError('Invalid order action.')

        # validates status is either open, pending, done, active, or all
        if not status in ['open', 'pending', 'done', 'active', 'all']:
            raise ValueError('Invalid order status.')

        resp = self.client.get_all_orders(symbol=market)
        if len(resp) > 0:
            df = pd.DataFrame(resp)
        else:
            df = pd.DataFrame()

        if len(df) == 0:
            return pd.DataFrame()

        df = df[[
            'time', 'symbol', 'side', 'type', 'executedQty',
            'cummulativeQuoteQty', 'status'
        ]]
        df.columns = [
            'created_at', 'market', 'action', 'type', 'size', 'filled',
            'status'
        ]
        df['created_at'] = df['created_at'].apply(lambda x: int(str(x)[:10]))
        df['created_at'] = df['created_at'].astype("datetime64[s]")
        df['size'] = df['size'].astype(float)
        df['filled'] = df['filled'].astype(float)
        df['action'] = df['action'].str.lower()
        df['type'] = df['type'].str.lower()
        df['status'] = df['status'].str.lower()
        df['price'] = df['filled'] / df['size']

        # pylint: disable=unused-variable
        for k, v in df.items():
            if k == 'status':
                df[k] = df[k].map(self.__convertStatus)

        if action != '':
            df = df[df['action'] == action]
            df = df.reset_index(drop=True)

        if status != 'all' and status != '':
            df = df[df['status'] == status]
            df = df.reset_index(drop=True)

        return df

    def marketBuy(self, market: str = '', quote_quantity: float = 0) -> list:
        """Executes a market buy providing a funding amount"""

        # validates the market is syntactically correct
        if not self._isMarketValid(market):
            raise ValueError('Binance market is invalid.')

        # validates quote_quantity is either an integer or float
        if not isinstance(quote_quantity, int) and not isinstance(
                quote_quantity, float):
            raise TypeError('The funding amount is not numeric.')

        try:
            current_price = self.getTicker(market)[1]

            base_quantity = np.divide(quote_quantity, current_price)

            df_filters = self.getMarketInfoFilters(market)
            step_size = float(df_filters.loc[df_filters['filterType'] ==
                                             'LOT_SIZE']['stepSize'])
            precision = int(round(-math.log(step_size, 10), 0))

            # remove fees
            base_quantity = base_quantity - (base_quantity *
                                             self.getTradeFee(market))

            # execute market buy
            stepper = 10.0**precision
            truncated = math.trunc(stepper * base_quantity) / stepper
            print('Order quantity after rounding and fees:', truncated)
            return self.client.order_market_buy(symbol=market,
                                                quantity=truncated)
        except Exception as err:
            ts = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
            print(ts, 'Binance', 'marketBuy', str(err))
            return []

    def marketSell(self, market: str = '', base_quantity: float = 0) -> list:
        """Executes a market sell providing a crypto amount"""

        # validates the market is syntactically correct
        if not self._isMarketValid(market):
            raise ValueError('Binance market is invalid.')

        if not isinstance(base_quantity, int) and not isinstance(
                base_quantity, float):
            raise TypeError('The crypto amount is not numeric.')

        try:
            df_filters = self.getMarketInfoFilters(market)
            step_size = float(df_filters.loc[df_filters['filterType'] ==
                                             'LOT_SIZE']['stepSize'])
            precision = int(round(-math.log(step_size, 10), 0))

            # remove fees
            base_quantity = base_quantity - (base_quantity *
                                             self.getTradeFee(market))

            # execute market sell
            stepper = 10.0**precision
            truncated = math.trunc(stepper * base_quantity) / stepper
            print('Order quantity after rounding and fees:', truncated)
            return self.client.order_market_sell(symbol=market,
                                                 quantity=truncated)
        except Exception as err:
            ts = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
            print(ts, 'Binance', 'marketSell', str(err))
            return []

    def getTradeFee(self, market: str) -> float:
        resp = self.client.get_trade_fee(symbol=market,
                                         timestamp=self.getTime())

        ### DEBUG ###
        if 'success' not in resp:
            print('*** getTradeFee(' + market + ') - missing "success" ***')
            print(resp)

        if 'tradeFee' not in resp:
            print('*** getTradeFee(' + market + ') - missing "tradeFee" ***')
            print(resp)
        else:
            if len(resp['tradeFee']) == 0:
                print('*** getTradeFee(' + market + ') - "tradeFee" empty ***')
                print(resp)
            else:
                if 'taker' not in resp['tradeFee'][0]:
                    print('*** getTradeFee(' + market +
                          ') - missing "trader" ***')
                    print(resp)

        if resp['success']:
            return resp['tradeFee'][0]['taker']
        else:
            return DEFAULT_TRADE_FEE_RATE

    def getMarketInfo(self, market: str) -> dict:
        # validates the market is syntactically correct
        if not self._isMarketValid(market):
            raise TypeError('Binance market required.')

        return self.client.get_symbol_info(symbol=market)

    def getMarketInfoFilters(self, market: str) -> pd.DataFrame:
        return pd.DataFrame(
            self.client.get_symbol_info(symbol=market)['filters'])

    def getTicker(self, market: str) -> tuple:
        # validates the market is syntactically correct
        if not self._isMarketValid(market):
            raise TypeError('Binance market required.')

        resp = self.client.get_symbol_ticker(symbol=market)

        if 'price' in resp:
            return (self.getTime().strftime('%Y-%m-%d %H:%M:%S'),
                    float('{:.8f}'.format(float(resp['price']))))

        now = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
        return (now, 0.0)

    def getTime(self) -> datetime:
        """Retrieves the exchange time"""

        try:
            resp = self.client.get_server_time()
            epoch = int(str(resp['serverTime'])[0:10])
            return datetime.fromtimestamp(epoch)
        except:
            return None
Beispiel #11
0
class BinanceAPI:

    def __init__(self, api_key, api_secret):
        API_KEY = api_key
        API_SECRET = api_secret

        self.client = Client(API_KEY, API_SECRET)


    def get_ticker(self, pair):
        try:
            value = self.client.get_ticker(symbol=pair)
            return value
        except Exception as e:
            print("Exception : " + str(e))


    def get_current_price(self, pair):
        try:
            ticker = self.client.get_symbol_ticker(symbol=pair)
            value = ticker["price"]
            return float(value)
        except Exception as e:
            print("Exception : " + str(e))


    def get_klines(self, pair, number):
        try:
            klines = pd.DataFrame(self.client.get_klines(symbol=pair, interval=Client.KLINE_INTERVAL_30MINUTE, limit=number),columns = ["OpenTime","Open","High","Low","Close","Volume","CloseTime","QuoteVolume","TradeCount","TakerVolume","TakerQuoteVolume","Ignore"])
            value = klines[["OpenTime","Close","High","Low","Volume","QuoteVolume","TakerVolume","TakerQuoteVolume","TradeCount"]].copy()
            value.loc[:, "OpenTime"] = pd.to_datetime(value["OpenTime"].apply(lambda x: datetime.fromtimestamp(int(x/1000))))
            value = value.set_index("OpenTime")
            return value
        except Exception as e:
            print("Exception : " + str(e))


    def get_historical_klines(self, pair, start, end):
        try:
            klines = pd.DataFrame(self.client.get_historical_klines(start_str = start,end_str = end,symbol=pair, interval=Client.KLINE_INTERVAL_30MINUTE, limit=500),columns = ["OpenTime","Open","High","Low","Close","Volume","CloseTime","QuoteVolume","TradeCount","TakerVolume","TakerQuoteVolume","Ignore"])
            value = klines[["OpenTime","Close","High","Low","Volume","QuoteVolume","TakerVolume","TakerQuoteVolume","TradeCount"]].copy()
            value.loc[:, "OpenTime"] = pd.to_datetime(value["OpenTime"].apply(lambda x: datetime.fromtimestamp(int(x/1000))))
            value = value.set_index("OpenTime")
            return value
        except Exception as e:
            print("Exception : " + str(e))


    def get_balance(self, symbol):
        try:
            value = self.client.get_asset_balance(asset=symbol)
            return value
        except Exception as e:
            print('Exception : {}'.format(e))

    def get_free_balance(self, symbol):
        try:
            value = self.client.get_asset_balance(asset=symbol)
            return float(value["free"])
        except Exception as e:
            print('Exception : {}'.format(e))


    def get_futures_balance(self, symbol):
        try:
            value = self.client.futures_account_balance()
            balance = [balance["balance"] for balance in value if balance["asset"] == symbol]
            return float(str(*balance))
        except Exception as e:
            print('Exception : {}'.format(e))
            


    def create_limit_order(self, symbol, price, quantity, side_str):
        try:
            if side_str == "BUY":
                side = self.client.SIDE_BUY
            elif side_str == "SELL":
                side = self.client.SIDE_SELL
            order = self.client.order_limit(
            symbol=symbol,
            side=side,
            timeInForce=self.client.TIME_IN_FORCE_IOC,
            price=price,
            quantity=quantity)
            print(order)
            print("buy order created.\nSymbol:{0:5}\nPrice:{1:5}\nQuantity:{2:5}",symbol,price,quantity)
        except Exception as e:
            print("Exception : " + str(e))


    def create_market_order(self, symbol, quantity, side_str):
        try:
            if side_str == "BUY":
                side = self.client.SIDE_BUY
            elif side_str == "SELL":
                side = self.client.SIDE_SELL
            order = self.client.order_market(
            symbol=symbol,
            side=side,
            quantity=quantity)
            print(order)
            print("buy order created.\nSymbol:{0:5}\nPrice:{1:5}\nQuantity:{2:5}",symbol,price,quantity)
        except Exception as e:
            print("Exception : " + str(e))


    def create_test_order(self, symbol, quantity, side_str):
        try:
            if side_str == "BUY":
                side = self.client.SIDE_BUY
            elif side_str == "SELL":
                side = self.client.SIDE_SELL
            order = self.client.create_test_order(
            symbol=symbol,
            side=side,
            type=self.client.ORDER_TYPE_MARKET,
            quantity=quantity)
            print(order)
            print("buy order created.\nSymbol:{0:5}\nQuantity:{1:5}".format(symbol,quantity))
        except Exception as e:
            print("Exception : " + str(e))



    def create_futures_order(self, symbol, quantity, side_str):
        try:
            if side_str == "BUY":
                side = self.client.SIDE_BUY
            elif side_str == "SELL":
                side = self.client.SIDE_SELL
            order = self.client.futures_create_order(
            symbol=symbol,
            side=side,
            type=self.client.ORDER_TYPE_MARKET,
            quantity=quantity)
            #print(order)
            print("buy order created.\nSymbol:{0:5}\nQuantity:{1:5}".format(symbol,quantity))
        except Exception as e:
            print("Exception : " + str(e))




    def get_base_asset(self, symbol):
        try:
            return self.client.get_symbol_info(symbol)["baseAsset"];
        except Exception as e:
            print("Exception : " + str(e))


    def get_quote_asset(self, symbol):
        try:
            return self.client.get_symbol_info(symbol)["quoteAsset"];
        except Exception as e:
            print("Exception : " + str(e))

    def get_all_tickers(self):
        try:
            return self.client.get_all_tickers();
        except Exception as e:
            print("Exception : " + str(e))

    def get_all_orders(self):
        try:
            return self.client.get_all_orders();
        except Exception as e:
            print("Exception : " + str(e))
Beispiel #12
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'])
Beispiel #13
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)
Beispiel #14
0
class BinanceOrders(ExchangeOrders):
    '''Handle order calls to binance.'''
    def __init__(self, config=config.binance):
        self.client = Client(config['api_key'], config['api_secret'])

    def buy_order(self, symbol, quantity, test=True):
        """
        Place a market buy order via the binance API.

        Parameters:
        ------------
        symbol: string
            A valid binance cryptocurreny symbol.

        quantity: int | float
            The amount of <symbol> to buy.

        test: boolean
            True ---> Simulate a buy via the Binance API to check authorization.

        """

        if test:
            order = self.client.create_test_order(symbol=symbol,
                                                  side=SIDE_BUY,
                                                  type=ORDER_TYPE_MARKET,
                                                  quantity=quantity)
        else:
            order = self.client.create_order(symbol=symbol,
                                             side=SIDE_BUY,
                                             type=ORDER_TYPE_MARKET,
                                             quantity=quantity)
        # return True if order else False
        return order

    def sell_order(self, symbol, quantity, test=True):
        """
        Place a market buy order via the binance API.

        Parameters:
        ------------
        symbol: string
            A valid binance cryptocurreny symbol.

        quantity: int | float
            The amount of <symbol> to buy.

        test: boolean
            True ---> Simulate a buy via the Binance API to check authorization.

        """

        if test:
            order = self.client.create_test_order(symbol=symbol,
                                                  side=SIDE_SELL,
                                                  type=ORDER_TYPE_MARKET,
                                                  quantity=quantity)
        else:
            order = self.client.create_order(symbol=symbol,
                                             side=SIDE_sell,
                                             type=ORDER_TYPE_MARKET,
                                             quantity=quantity)
        # return True if order else False
        return order

    def account_balance(self):
        """Check account balance for all cryptocurrencies."""
        return self.client.get_account()['balances']

    def coin_balance(self, symbol):
        """Check balance for a given cryptocurreny"""
        return self.client.get_asset_balance(symbol)

    def account_status(self):
        """Check for normal account status."""
        status = self.client.get_account_status()
        if status['msg'] == 'Normal' and status['success']:
            return True
        else:
            return False

    def all_orders(self, symbol):
        """Get records of all orders."""
        return self.client.get_all_orders(symbol=symbol)

    def trades(self, symbol):
        """Get records of all trades."""
        return self.client.get_my_trades(symbol=symbol)
Beispiel #15
0
def enterSellPosition():
    #here check conditions to Sell
    return


def strategy():
    return


#-----------------------------------------------------------------------#
# CONNECT TO WEBSCOKET
symbol = 'btcusdt'
interval = '1m'
ws = websocket.WebSocketApp(
    f'wss://stream.binance.com:9443/ws/{symbol}@kline_{interval}',
    on_open=on_open,
    on_message=on_message,
    on_close=on_close,
    on_error=on_error)

#-----------------------------------------------------------------------#
# START RECEIVING INFO
#ws.run_forever()

orders = client.get_all_orders(symbol=symbol.upper())
quantity = float(orders[-1]['executedQty'])
sell_order = self.client.create_order(symbol=symbol.upper(),
                                      side='SELL',
                                      type='MARKET',
                                      quantity=quantity)
print(sell_order)
Beispiel #16
0
from pprint import pprint
import configapi2

#import configapi2
#print(configapi2.API_KEY)

api_key = configapi2.API_KEY
api_secret = configapi2.SECRET_KEY
client = Client(api_key, api_secret)
'''
order = client.order_limit_buy(
    symbol='DOGEUSDT',
    quantity=450,
    price='0.03')

pprint(order)
'''

# 215750186
'''
result = client.cancel_order(
    symbol='DOGEUSDT',
    orderId=215750186)

print(result)
'''

orders = client.get_all_orders(symbol='DOGEUSDT')
#orders = client.get_open_orders(symbol='DOGEUSDT')
print('ALL ORDER:', orders)
data = pd.read_json("trades.txt")
data.to_csv("Binance - trades.csv")
#Trades - End

orders = []

#Orders - Start
for instr in instruments['symbols']:
    index = 0
    recordcount = 500

    while (recordcount == 500):

        order = client.get_all_orders(symbol=instr['symbol'],
                                      limit=500,
                                      orderId=index)

        if order != [] and order is not None:
            orders.extend(order)

            recordcount = len(order)
            index = int(order[recordcount - 1]['orderId']) + 1
        else:
            recordcount = 0

for tr in orders:
    tr['time'] = dt.datetime.fromtimestamp(int(tr['time']) / 1000)

with open('orders.txt', 'w') as outfile:
    json.dump(orders, outfile, default=myconverter)
Beispiel #18
0
class trade_realtime():
    def __init__(self, api_key, api_secret, total_list=None):
        self.coin_list = total_list
        self.api_key = api_key
        self.api_secret = api_secret
        self.client = Client(api_key, api_secret)

    def get_time(self):
        server_time = self.client.get_server_time()
        #  {
        #         "serverTime": 1499827319559
        # }
        return int(server_time['serverTime'])

    def get_exchange_status(self):
        return self.client.get_system_status()

    def get_coin_price(self, coin_list):
        # kwargs = {'data': coin}
        output_data = []
        for coin in coin_list:
            price_d = ast.literal_eval(
                json.dumps(self.client.get_symbol_ticker(symbol=coin)))
            print(price_d)
            price = float(price_d['price'])
            output_data.append(price)

        return output_data

    def get_trade(self, start, end):
        output_data = []
        for coin in self.coin_list:
            output_data.append(
                self.client.get_aggregate_trades(symbol=coin,
                                                 startTime=start,
                                                 endTime=end))

        return output_data

    def get_kline(self, start, end):

        output_data = []
        for coin in self.coin_list:
            output_data.append(
                self.client.get_klines(symbol=coin,
                                       interval=Client.KLINE_INTERVAL_5MINUTE,
                                       limit=500,
                                       startTime=start,
                                       endTime=end))
        return output_data

    def get_historical_klines(self, symbol, interval, start, end):

        # init our list
        output_data = []

        # setup the max limit
        limit = 500
        timeframe = interval_to_milliseconds(interval)
        start_ts = start
        idx = 0
        # it can be difficult to know when a symbol was listed on Binance so allow start time to be before list date
        symbol_existed = False
        while True:
            # fetch the klines from start_ts up to max 500 entries or the end_ts if set
            temp_data = self.client.get_klines(symbol=symbol,
                                               interval=interval,
                                               limit=limit,
                                               startTime=start_ts,
                                               endTime=end)

            # handle the case where our start date is before the symbol pair listed on Binance
            if not symbol_existed and len(temp_data):
                symbol_existed = True

            if symbol_existed:
                # append this loops data to our output data
                output_data += temp_data

                # update our start timestamp using the last value in the array and add the interval timeframe
                start_ts = temp_data[len(temp_data) - 1][0] + timeframe
            else:
                # it wasn't listed yet, increment our start date
                start_ts += timeframe

            idx += 1
            # check if we received less than the required limit and exit the loop
            if len(temp_data) < limit:
                # exit the while loop
                break

            # sleep after every 3rd call to be kind to the API
            if idx % 3 == 0:
                time.sleep(1)

        return output_data

    def get_orderbook_ticker(self):
        pass

    def order_limit_buy(self, **params):

        return self.client.order_limit_buy(**params)

    def order_limit_sell(self, **params):

        return self.client.order_limit_sell(**params)

    def order_market_sell(self, **params):
        return self.client.order_market_sell(**params)

    def order_market_buy(self, **params):
        return self.client.order_market_buy(**params)

    def get_open_orders(self, **params):
        return self.client.get_open_orders(**params)

    def create_test_order(self, **params):

        self.client.create_test_order()

    def get_order(self, **params):
        self.client.get_order(self, **params)

    def get_all_orders(self, **params):
        self.client.get_all_orders(self, **params)

    def cancel_order(self, **params):
        self.client.cancel_order(self, **params)

    def get_account(self, **params):
        return (self.client.get_account(recvWindow=self.get_time()))

    def get_asset_balance(self, asset, **params):
        bal = self.client.get_asset_balance(asset=asset,
                                            recvWindow=self.get_time())
        return ast.literal_eval(json.dumps(bal))['free']

    def start_trade():
        pass

    def get_kline_lag_time(self, coin, lookback_in_ms):

        # lookback = 2*60*1000 #5mins
        # rt.pred_coin_list=[coin]

        end_ts = self.get_time()
        #  calendar.timegm(time.gmtime()) -lookback

        start_ts = end_ts - lookback_in_ms
        #  print("start=",start_ts)
        # print("end=",end_ts)

        f = self.get_historical_klines(symbol=coin,
                                       interval=Client.KLINE_INTERVAL_30MINUTE,
                                       end=end_ts,
                                       start=start_ts)
        f = ast.literal_eval(json.dumps(f))
        return f

    def getState(self, coin_list):

        features = np.empty((LOOK_BACK, 0), float)
        coin_f_index = [2, 3, 4, 5, 7]
        for coin in coin_list:
            coin_f = np.array(self.get_kline_lag_time(coin, LOOK_BACK_IN_MS),
                              dtype=np.float).reshape(-1, 12)
            coin_f = coin_f[coin_f.shape[0] - LOOK_BACK:, coin_f_index]
            if (coin_f.shape[0] < 10):
                print("something is wrong with binance api,return shape=",
                      coin_f.shape)
                return
            #print("coin_f shape ",coin_f.shape)
            #print("features shape ",features.shape)

            # COIN_FEATURE = np.concatenate((COIN_FEATURE, tmp), axis=0)
            features = np.hstack((features, coin_f))
        # features = self.create_input(features,LOOK_BACK)
        # DF_FEATURES
        #reshape for tensorflow backend
        features = features.reshape(1, DF_FEATURES, 1, LOOK_BACK)

        print("create_predictive_input, features shape ", features.shape)

        # print("kline shape after modify",features.shape)
        # features = self.create_input(features ,LOOK_BACK)
        return features
Beispiel #19
0
class BinanceOperator:
    def __init__(self, api_key, secret):
        self.client = Client(api_key, secret)
        self.symbol_status = {}
        # self.base_url = 'https://api.binance.com'

    # def get_open_orders(self):
    #     endpoint = '/api/v3/openOrders'
    #     ts = int(time.time()*1000)
    #     symbol = 'LTCBTC'
    #     query = urlencode({'symbol': symbol, 'timestamp': ts})
    #     signature = hmac.new(self.api_secret.encode('utf-8'), query.encode('utf-8'), hashlib.sha256).hexdigest()
    #     params = {
    #         'symbol': symbol,
    #         'timestamp': ts,
    #         'signature': signature,
    #     }
    #     header = {'X-MBX-APIKEY': self.api_key}
    #     url = self.base_url + endpoint
    #     response = requests.get(url, headers=header, params=params)
    #     orders = json.loads(response.text)
    #     return orders

    # def create_order(self, order):
    #     endpoint = '/api/v3/order/test'
    #     ts = int(time.time()*1000)
    #     symbol = 'LTCBTC'
    #     query = urlencode({'symbol': symbol, 'timestamp': ts})
    #     signature = hmac.new(self.api_secret.encode('utf-8'), query.encode('utf-8'), hashlib.sha256).hexdigest()
    #     params = {
    #         'symbol': symbol,
    #         'timestamp': ts,
    #         'signature': signature,
    #     }
    #     header = {'X-MBX-APIKEY': self.api_key}
    #     url = self.base_url + endpoint
    #     response = requests.post(url, headers=header, params=params)
    #     orders = json.loads(response.text)
    #     return orders

    def create_market_buy(self, symbol, total):
        price = float(self.client.get_symbol_ticker(symbol=symbol)['price'])
        qty = self.estimate_quantity(symbol, total, price)
        response = self.client.order_market_buy(symbol=symbol, quantity=qty)
        self.symbol_status[symbol] = {
            'status': 'long',
            'quantity': qty,
            'price': price
        }
        return response

    def create_market_sell(self, symbol):
        last_order = list(
            filter(lambda o: o['side'] == 'BUY',
                   self.client.get_all_orders(symbol=symbol)))[-1]
        qty = last_order['executedQty']
        buy_price = float(last_order['cummulativeQuoteQty'])

        response = self.client.order_market_sell(symbol=symbol, quantity=qty)

        # DO PnL estimation and save it
        if response['status'] == 'FILLED':
            sell_price = float(response['cummulativeQuoteQty'])
            profit = round((sell_price - buy_price) / buy_price, 4)
            logging.info('SOLD {}: {} @ {} - Profit: {}%\n'.format(
                symbol, qty, sell_price, profit * 10))
            self.symbol_status[symbol] = {
                'status': 'short',
                'quantity': qty,
                'price': sell_price
            }
        return response

    def estimate_quantity(self, symbol, total, current_price):
        info = requests.get('https://www.binance.com/api/v1/exchangeInfo')
        data = json.loads(info.text)
        sym = list(filter(lambda x: x['symbol'] == symbol, data['symbols']))[0]
        lot_info = list(
            filter(lambda x: x['filterType'] == 'LOT_SIZE', sym['filters']))[0]

        min_qty = float(lot_info['minQty'])
        max_qty = float(lot_info['maxQty'])
        step_size = lot_info['stepSize']
        qty = round(total / current_price, 8)
        if qty >= min_qty:
            approximator = step_size.find('1') - 1
            qty = math.floor(qty * 10**approximator) / float(10**approximator)
            return qty
        elif qty > max_qty:
            return max_qty
        else:
            return 0

    def buying_allowed(self, symbol):
        # If symbol not traded yet, add to the symbol status dictionary
        if symbol not in self.symbol_status:
            self.symbol_status[symbol] = {
                'status': 'short',
                'quantity': 0,
                'price': 0
            }
        return True if self.symbol_status[symbol][
            'status'] == 'short' else False

    # COULD ALSO CHECK THAT QUANTITY IS SAME AS LAST BUY (?)
    def selling_allowed(self, symbol):
        return True if symbol in self.symbol_status and self.symbol_status[
            symbol]['status'] == 'long' else False
Beispiel #20
0
def modify():
    #Binance API
    client = Client(api_key, secret_key)
    balances = client.get_account().get('balances')
    prices = client.get_all_tickers()
    trades = []
    for pair in pairs:
        trade = (client.get_all_orders(symbol=pair, limit=1000))
        for order in trade:
            trades.append(order)

    #Excel Values
    workbook = openpyxl.load_workbook('trading.xlsx')
    Home = workbook.get_sheet_by_name('Home')
    DetailledHome = workbook.get_sheet_by_name('DetailledHome')
    Wallet = workbook.get_sheet_by_name('Wallet')
    values = workbook.get_sheet_by_name('Values')

    #Fill Wallet sheet
    for i in range(len(balances)):
        Wallet[f'A{i+2}'] = balances[i].get('asset')
        Wallet[f'B{i+2}'] = balances[i].get('free')
        Wallet[f'C{i+2}'] = balances[i].get('locked')
    Wallet['E1'] = "Last update at " + str(
        datetime.now().strftime("%H:%M:%S %d/%m/%Y"))

    #Fill DetailledHome sheet
    trade_id = []
    for i in range(2, 10000):
        val = DetailledHome[f'B{i}'].value
        if val != None:
            trade_id.append(val)

    for order in trades:
        if trade_id.count(order.get('orderId')) == 0:
            DetailledHome[f'A{len(trade_id)+2}'] = order.get('symbol')
            DetailledHome[f'B{len(trade_id)+2}'] = order.get('orderId')
            DetailledHome[f'C{len(trade_id)+2}'] = order.get('orderListId')
            DetailledHome[f'D{len(trade_id)+2}'] = order.get('clientOrderId')
            DetailledHome[f'E{len(trade_id)+2}'] = order.get('price')
            DetailledHome[f'F{len(trade_id)+2}'] = order.get('origQty')
            DetailledHome[f'G{len(trade_id)+2}'] = order.get('executedQty')
            DetailledHome[f'H{len(trade_id)+2}'] = order.get(
                'cummulativeQuoteQty')
            DetailledHome[f'I{len(trade_id)+2}'] = order.get('status')
            DetailledHome[f'J{len(trade_id)+2}'] = order.get('timeInForce')
            DetailledHome[f'K{len(trade_id)+2}'] = order.get('type')
            DetailledHome[f'L{len(trade_id)+2}'] = order.get('side')
            DetailledHome[f'M{len(trade_id)+2}'] = order.get('stopPrice')
            DetailledHome[f'N{len(trade_id)+2}'] = order.get('icebergQty')
            DetailledHome[f'O{len(trade_id)+2}'] = datetime.fromtimestamp(
                int(str(order.get('time'))[:-3]))
            DetailledHome[f'P{len(trade_id)+2}'] = order.get('time')
            DetailledHome[f'Q{len(trade_id)+2}'] = datetime.fromtimestamp(
                int(str(order.get('updateTime'))[:-3]))
            DetailledHome[f'R{len(trade_id)+2}'] = order.get('updateTime')
            DetailledHome[f'S{len(trade_id)+2}'] = order.get('isWorking')
            DetailledHome[f'T{len(trade_id)+2}'] = order.get(
                'origQuoteOrderQty')
            trade_id.append(order.get('orderId'))
        else:
            index = trade_id.index(order.get('orderId'))
            DetailledHome[f'A{index+2}'] = order.get('symbol')
            DetailledHome[f'B{index+2}'] = order.get('orderId')
            DetailledHome[f'C{index+2}'] = order.get('orderListId')
            DetailledHome[f'D{index+2}'] = order.get('clientOrderId')
            DetailledHome[f'E{index+2}'] = order.get('price')
            DetailledHome[f'F{index+2}'] = order.get('origQty')
            DetailledHome[f'G{index+2}'] = order.get('executedQty')
            DetailledHome[f'H{index+2}'] = order.get('cummulativeQuoteQty')
            DetailledHome[f'I{index+2}'] = order.get('status')
            DetailledHome[f'J{index+2}'] = order.get('timeInForce')
            DetailledHome[f'K{index+2}'] = order.get('type')
            DetailledHome[f'L{index+2}'] = order.get('side')
            DetailledHome[f'M{index+2}'] = order.get('stopPrice')
            DetailledHome[f'N{index+2}'] = order.get('icebergQty')
            DetailledHome[f'O{index+2}'] = datetime.fromtimestamp(
                int(str(order.get('time'))[:-3]))
            DetailledHome[f'P{index+2}'] = order.get('time')
            DetailledHome[f'Q{index+2}'] = datetime.fromtimestamp(
                int(str(order.get('updateTime'))[:-3]))
            DetailledHome[f'R{index+2}'] = order.get('updateTime')
            DetailledHome[f'S{index+2}'] = order.get('isWorking')
            DetailledHome[f'T{index+2}'] = order.get('origQuoteOrderQty')
    DetailledHome['V1'] = "Last update at " + str(
        datetime.now().strftime("%H:%M:%S %d-%m-%Y"))

    #Feel Home sheet
    for i in range(len(trade_id)):
        Home[f'A{i+2}'] = f'=DetailledHome!O{i+2}'
        Home[f'B{i+2}'] = f'=DetailledHome!A{i+2}'
        Home[f'C{i+2}'] = f'=DetailledHome!L{i+2}'
        Home[f'D{i+2}'] = round(
            float(DetailledHome[f'F{i+2}'].value) *
            float(DetailledHome[f'E{i+2}'].value), 4)
        Home[f'E{i+2}'] = f'=DetailledHome!F{i+2}'
        Home[f'G{i+2}'] = f'=DetailledHome!E{i+2}'
        Home[f'H{i+2}'] = f'=DetailledHome!I{i+2}'
    Home['K1'] = '=DetailledHome!V1'

    #Fill Values sheet
    for i in range(len(prices)):
        values[f'A{i+2}'] = prices[i].get('symbol')
        values[f'B{i+2}'] = prices[i].get('price')
    values['D1'] = "Last update at " + str(
        datetime.now().strftime("%H:%M:%S %d-%m-%Y"))

    #Save Excel
    try:
        workbook.save('trading.xlsx')
        print('Saved !')
    except:
        print('Not saved because file is open...')
        pass
Beispiel #21
0
class BinBot(object):
    def __init__(self):
        self.client = Client(binance_config.api_key, binance_config.api_secret)
        self.fee = 0.0005  #if user has BNB tokens
        self.orderbook = self.get_orderbook_total()
        self.bit_rate = self.extract_btc_eth_rate(self.orderbook)
        self.update_orderbook()
        self.symbol_keys = self.get_keys(self.orderbook)
        self.current_btc, self.current_eth = self.update_account()

    def get_orderbook_total(self):
        """ Returns orderbook from binance package. """
        return self.client.get_orderbook_tickers()

    def update_orderbook(self):
        """ Updates orderbook by analyzing exchange rates in BTC and removing
            coins in no_trade in binance_config. 
        """
        try:
            self.orderbook = self.get_orderbook_total()
            self.bit_rate = self.extract_btc_eth_rate(self.orderbook)
            self.orderbook = self.modify_orderbook(self.orderbook)
        except binexc.BinanceAPIException as e:
            print(e.status_code)
            print(e.message)
            time.sleep(10)
            self.update_orderbook()

    def update_account(self):
        """ Returns the amount of BTC or ETH in the account. """
        flag = False
        #If local time compared to Binance NTP server time is offset by +1000ms then API will throw error
        while (flag == False):
            try:
                acc = self.client.get_account(
                    recvWindow=binance_config.recv_window)
                flag = True
            except binexc.BinanceAPIException as e:
                print(str(e.status_code) + " : " + e.message)
                time.sleep(1)
        btc_eth = []
        for k in acc['balances']:
            if (k['asset'] == 'BTC' or k['asset'] == 'ETH'):
                btc_eth.append(k['free'])
            if (len(btc_eth) == 2):
                break
        if (btc_eth[0] >= btc_eth[1]):
            return btc_eth[0], btc_eth[1]
        else:
            return btc_eth[1], btc_eth[0]

    def alt_asset_amount(self, symbol, symbol_length=3):
        """ Returns the total amount of an altcoin on the account.
        
            Keyword Arguments:
            symbol -- the symbol of the altcoin e.g. 'NEO'
            symbol_length -- 'NEO' will have symbol_length of 3
                             'LINK' will have symbol_length of 4
                              Work around for the API
                              (default 3)
        """

        acc = self.client.get_account(recvWindow=binance_config.recv_window)
        for k in acc['balances']:
            if (k['asset'] == symbol[0, symbol_length]):
                return k['free']
        return "Symbol Not Found"

    def get_keys(self, orderbook):
        """ Returns symbols of all coins on Binance """
        _keys = []
        for k in orderbook:
            _keys.append(list(k.keys())[0])
        return _keys

    def extract_btc_eth_rate(self, orderbook):
        """ Returns ETHBTC exchange rate """
        for i in range(0, len(orderbook)):
            if (orderbook[i]['symbol'][0:6] == 'ETHBTC'):
                odbk = orderbook[i]
                odbk['btc_one'] = 1 / float(odbk['askPrice'])
                return orderbook[i]

    def modify_orderbook(self, orderbook):
        """ Helper function to modify orderbook to remove trading pairs that
            are not involved eg BTCUSDT """
        ob_sorted = sorted(orderbook, key=lambda k: k['symbol'])
        ob_sorted = self.del_non_pair_coins(ob_sorted)
        ob_dict = self.transform_data_list(ob_sorted)
        return ob_dict

    def del_non_pair_coins(self, orders):
        """ Deletes coins that are no longer listed on Binance as well as coins 
            listed on the binance_config.no_trade list
        """
        i = 0
        orders_to_return = []
        while (i < len(orders) - 1):
            if (orders[i]['symbol'][0:3] == orders[i + 1]['symbol'][0:3]):
                if (orders[i]['symbol'] == 'ETC'
                        or orders[i]['symbol'][-4:] == 'USDT'
                        or orders[i]['symbol'][0:4] in binance_config.no_trade
                        or orders[i]['symbol'][0:3] in binance_config.no_trade
                        or orders[i]['symbol'][-3:] == 'BNB'):
                    i += 1
                elif (orders[i + 1]['symbol'][-4:] == 'USDT'):
                    i += 1
                else:
                    orders_to_return.append(orders[i])
                    orders_to_return.append(orders[i + 1])
                    i += 2
            else:
                i += 1
        return orders_to_return

    def transform_data_list(self, orders):
        """ Transforms data from dictionary into list(BTC=0, ETH=1) """
        transform = []
        for i in range(0, len(orders), 2):
            transform.append(
                {orders[i]['symbol'][0:3]: [orders[i], orders[i + 1]]})
        return transform

    def orderbook_btc_eth(self, orderbook):
        """ Looks for viable trading pairs in the BTC --> ETH direction """
        btc_to_eth = {}
        btc_pos = 0
        eth_pos = 1
        for k in orderbook:
            try:
                btc_to_eth[list(k.keys())[0]] = 1 / float(k[list(
                    k.keys())[0]][btc_pos]['askPrice']) * float(k[list(
                        k.keys())[0]][eth_pos]['bidPrice'])
            except ZeroDivisionError as e:
                print(e)
        return sorted(btc_to_eth.items(),
                      key=operator.itemgetter(1),
                      reverse=True)

    def orderbook_eth_btc(self, orderbook):
        """ Looks for viable trading pairs in the ETH --> BTC direction """
        eth_to_btc = {}
        btc_pos = 0
        eth_pos = 1
        for k in orderbook:
            try:
                eth_to_btc[list(k.keys())[0]] = 1 / float(k[list(
                    k.keys())[0]][eth_pos]['askPrice']) * float(k[list(
                        k.keys())[0]][btc_pos]['bidPrice'])
            except ZeroDivisionError as e:
                print(e)
        return sorted(eth_to_btc.items(),
                      key=operator.itemgetter(1),
                      reverse=True)

    #Without client validation - no google authenticator
    #symbol - string,   quantity = int, price = string -- must be 0.0002
    def order_buy_alt(self, _symbol, _quantity, _price, order_rank, attempt=1):
        """ Buys an altcoin using Binance package
            
            Keyword Arguments:
            _symbol -- String: Symbol name of trading pair eg NEOBTC 
            _quantity -- Integer: Quantity to buy
            _price -- String: Price to buy at
            order_rank -- Integer: The order of buy/sell exection
            attempt -- Integer: Total of attempts to buy at the price
        """
        try:
            self.client.create_order(symbol=_symbol,
                                     side=enum.SIDE_BUY,
                                     type=enum.ORDER_TYPE_LIMIT,
                                     timeInForce=enum.TIME_IN_FORCE_GTC,
                                     quantity=_quantity,
                                     price=_price,
                                     disable_validation=True)
            return True
        except binexc.BinanceAPIException as e:
            print(e.status_code, e.message, " | order_buy_alt")
            return False

    def order_sell_alt(self,
                       _symbol,
                       _quantity,
                       _price,
                       order_rank,
                       attempt=1):
        """ Sells an altcoin using Binance package
            
            Keyword Arguments:
            _symbol -- String: Symbol name of trading pair eg NEOBTC 
            _quantity -- Integer: Quantity to buy
            _price -- String: Price to buy at
            order_rank -- Integer: The order of buy/sell exection
            attempt -- Integer: Total of attempts to buy at the price
        """
        try:
            self.client.create_order(symbol=_symbol,
                                     side=enum.SIDE_SELL,
                                     type=enum.ORDER_TYPE_LIMIT,
                                     timeInForce=enum.TIME_IN_FORCE_GTC,
                                     quantity=_quantity,
                                     price=_price,
                                     disable_validation=True)
        except binexc.BinanceAPIException as e:
            #print(e.message, e.status_code, " | order_sell_alt")
            if (order_rank is 4 or order_rank is 2):
                if (attempt <= 25):
                    attempt += 1
                    self.order_sell_alt(_symbol, _quantity, _price, order_rank,
                                        attempt)
                    time.sleep(0.02)
            else:
                print("Went to market price | order_sell_alt", e.message,
                      e.status_code)
                self.order_sell_market(_symbol, _quantity)

    def order_sell_market(self, _symbol, _quantity):
        """Sells coins into either ETH or BTC at MARKET VALUE.
            Use for upgrades for flexibility of binbot
                Say the order you originally placed was bought before your order arrived
                on the binance servers. This will immediately sell your coins and depending
                on the fluctuation of the market could still result in a (most likely milder)
                profit. 
        """
        try:
            self.crypto_storage.client.create_order(
                symbol=_symbol,
                side=enum.SIDE_SELL,
                type=enum.ORDER_TYPE_MARKET,
                quantity=_quantity)
        except binexc.BinanceAPIException as e:
            print(e.status_code)
            print(e.message)
            self.order_sell_market(_symbol, _quantity)

    def test_order_buy_alt(self, _symbol, _quantity, _price):
        """ FOR TESTING BINBOT BEFORE YOU LOSE MONEY
            Important to test if your orders will execute in time.
            Buys an altcoin using Binance package
            
            Keyword Arguments:
            _symbol -- String: Symbol name of trading pair eg NEOBTC 
            _quantity -- Integer: Quantity to buy
            _price -- String: Price to buy at
            order_rank -- Integer: The order of buy/sell exection
            attempt -- Integer: Total of attempts to buy at the price
        """
        try:
            self.client.create_test_order(symbol=_symbol,
                                          side=enum.SIDE_BUY,
                                          type=enum.ORDER_TYPE_LIMIT,
                                          timeInForce=enum.TIME_IN_FORCE_GTC,
                                          quantity=_quantity,
                                          price=_price,
                                          disable_validation=True)
        except binexc.BinanceAPIException as e:
            print(e.status_code)
            print(e.message)

    def test_order_sell_alt(self, _symbol, _quantity, _price):
        """ FOR TESTING BINBOT BEFORE YOU LOSE MONEY
            Important to test if your orders will execute in time.
            Sells an altcoin using Binance package
            
            Keyword Arguments:
            _symbol -- String: Symbol name of trading pair eg NEOBTC 
            _quantity -- Integer: Quantity to buy
            _price -- String: Price to buy at
            order_rank -- Integer: The order of buy/sell exection
            attempt -- Integer: Total of attempts to buy at the price
        """
        try:
            self.client.create_test_order(symbol=_symbol,
                                          side=enum.SIDE_SELL,
                                          type=enum.ORDER_TYPE_LIMIT,
                                          timeInForce=enum.TIME_IN_FORCE_GTC,
                                          quantity=_quantity,
                                          price=_price,
                                          disable_validation=True)
        except binexc.BinanceAPIException as e:
            print(e.status_code)
            print(e.message)

    def hunt(self, trials=10000, sleep_time=0.1):
        """ This is the main function of BinBot.
            This function will search for arbitrage opportunities and execute orders
            if it finds an inefficient pair.
            
            Keyword Arguments:
            trials -- Integer: how many loops the bot will run (default 10,000)
            sleep_time -- Float: The Binance API (since I last checked) will only allow
                                you to access it 18 times per second. So need a sleep time
                                to avoid this problem. Remember the longer the sleep time
                                the less likely your arbitrage oppurtunity will still be
                                available. (default 0.1)
        """
        num_runs = 0
        pre_arbitrage_assets = self.load_arbitrage_assets()
        time.sleep(sleep_time)
        while (num_runs < trials):
            try:
                self.update_orderbook()
            except ConnectionError as e:
                print(e + "will suspend bot for 10 seconds")
                time.sleep(10)
                continue
            #Search for inefficiency
            orderbook_btc = self.orderbook_btc_eth(self.orderbook)
            orderbook_eth = self.orderbook_eth_btc(self.orderbook)
            if (orderbook_btc[0][1] -
                (self.fee * orderbook_btc[0][1]) > self.bit_rate['btc_one']
                    and orderbook_eth[0][1] - (self.fee * orderbook_eth[0][1])
                    > float(self.bit_rate['askPrice'])):
                #print('found' + orderbook_btc[0][0] + orderbook_eth[0][0] + str(num_runs))
                num_runs += 1
                purchase = []
                for k in self.orderbook:
                    if (list(k.keys())[0] == orderbook_btc[0][0]):
                        purchase.insert(0, k)
                    if (list(k.keys())[0] == orderbook_eth[0][0]):
                        purchase.insert(1, k)
                btc_limit = binance_config.btc_trade_limit
                while (btc_limit > 0.001):
                    if (self.determine_feasibility(
                            orderbook_btc[0][0], orderbook_eth[0][0], purchase,
                            btc_limit) is True):
                        self.execute_trade(orderbook_btc[0][0],
                                           orderbook_eth[0][0], purchase,
                                           btc_limit)
                        break
                    else:
                        btc_limit = btc_limit - 0.001
            num_runs += 1
            if (num_runs % 100 == 0):
                print(str(num_runs))
        post_arbitrage_assets = self.load_arbitrage_assets()

        #Print results
        time_delta = datetime.datetime.now().replace(
            microsecond=0) - pre_arbitrage_assets['datetime']
        print('Initial: BTC:', pre_arbitrage_assets['BTC'], 'ETH:',
              pre_arbitrage_assets['ETH'], 'BNB:', pre_arbitrage_assets['BNB'])
        print('After__: BTC:', post_arbitrage_assets['BTC'], 'ETH:',
              post_arbitrage_assets['ETH'], 'BNB:',
              post_arbitrage_assets['BNB'])
        print(
            'Diff___: BTC:',
            float(post_arbitrage_assets['BTC']) -
            float(pre_arbitrage_assets['BTC']), 'ETH:',
            float(post_arbitrage_assets['ETH']) -
            float(pre_arbitrage_assets['ETH']), 'BNB:',
            float(post_arbitrage_assets['BNB']) -
            float(pre_arbitrage_assets['BNB']), 'TIME:',
            divmod(time_delta.total_seconds(), 60))

    def determine_feasibility(self, btc_sym, eth_sym, purchase,
                              btc_trade_limit):
        """ Determines if an arbitrage opportunity is profitable. """
        if (btc_trade_limit / float(purchase[0][btc_sym][0]['askPrice']) <=
                float(purchase[0][btc_sym][0]['askQty']) and
                btc_trade_limit / float(purchase[0][btc_sym][0]['askPrice']) <=
                float(purchase[0][btc_sym][1]['bidQty'])):
            eth_capital = (btc_trade_limit /
                           float(purchase[0][btc_sym][0]['askPrice'])) * float(
                               purchase[0][btc_sym][1]['bidPrice'])
            if (eth_capital / float(purchase[1][eth_sym][1]['askPrice']) <=
                    float(purchase[1][eth_sym][1]['askQty']) and
                    eth_capital / float(purchase[1][eth_sym][1]['askPrice']) <=
                    float(purchase[1][eth_sym][0]['bidQty'])):
                #and eth_capital / float(purchase[1][eth_sym][1]['askPrice']) >= 1):
                return True
            else:
                return False
        else:
            return False

    def execute_trade(self, btc_sym, eth_sym, purchase, btc_trade_limit):
        """ Executes trade in  BTC-->ALT_1-->ETH-->ALT_2-->BTC order.
                Side note: Making threads will improve likelihood of success. 
                            This implementation is inefficient. 
        """
        amount_btc = math.floor(btc_trade_limit /
                                float(purchase[0][btc_sym][0]['askPrice']))
        eth_capital = (btc_trade_limit /
                       float(purchase[0][btc_sym][0]['askPrice'])) * float(
                           purchase[0][btc_sym][1]['bidPrice'])
        amount_eth = math.floor(eth_capital /
                                float(purchase[1][eth_sym][1]['askPrice']))
        if (amount_btc * float(purchase[0][btc_sym][0]['askPrice']) > 0.001
                and amount_eth * float(purchase[1][eth_sym][0]['bidPrice']) >
                0.001):
            if self.order_buy_alt(
                    purchase[0][btc_sym][0]['symbol'], amount_btc,
                    purchase[0][btc_sym][0]['askPrice'], 1) is True:
                print("1: " + purchase[0][btc_sym][0]['symbol'] + " " +
                      str(amount_btc) + " " +
                      purchase[0][btc_sym][0]['askPrice'])

                self.order_sell_alt(purchase[0][btc_sym][1]['symbol'],
                                    amount_btc,
                                    purchase[0][btc_sym][1]['bidPrice'], 2)
                print("2: " + purchase[0][btc_sym][1]['symbol'] + " " +
                      str(amount_btc) + " " +
                      purchase[0][btc_sym][1]['bidPrice'])

                if self.order_buy_alt(
                        purchase[1][eth_sym][1]['symbol'], amount_eth,
                        purchase[1][eth_sym][1]['askPrice'], 3) is True:
                    print("3: " + purchase[1][eth_sym][1]['symbol'] + " " +
                          str(amount_eth) + " " +
                          purchase[1][eth_sym][1]['askPrice'])

                    self.order_sell_alt(purchase[1][eth_sym][0]['symbol'],
                                        amount_eth,
                                        purchase[1][eth_sym][0]['bidPrice'], 4)
                    print("4: " + purchase[1][eth_sym][0]['symbol'] + " " +
                          str(amount_eth) + " " +
                          purchase[1][eth_sym][0]['bidPrice'])

        self.remove_any_open_orders([
            purchase[0][btc_sym][0]['symbol'],
            purchase[0][btc_sym][1]['symbol'],
            purchase[1][eth_sym][1]['symbol'],
            purchase[1][eth_sym][0]['symbol']
        ])

    def remove_any_open_orders(self, poss_orders=[]):
        """ For upgrading flexibility of BinBot. Removes any open orders. """
        for order in poss_orders:
            open_orders = self.get_open_orders_symbol(_symbol=order)
            if len(open_orders) is not 0:
                self.order_sell_market(_symbol=open_orders[0]['symbol'],
                                       _quantity=open_orders[0]['origQty'])

    def check_server_time_difference(self):
        """ Checks the amount of time it takes for your packets to reach Binance 
            servers and return to your computer.
            VERY IMPORTANT: If your packets take too long, your trades will not execute
        """
        for i in range(0, 10):
            local_time_one = int(time.time() * 1000)
            server_time = self.client.get_server_time()
            diff_one = server_time['serverTime'] - local_time_one
            local_time_two = int(time.time() * 1000)
            diff_two = local_time_two - server_time['serverTime']
            print("local1: %s server: %s local2: %s diff1: %s diff2: %s" %
                  (local_time_one, server_time['serverTime'], local_time_two,
                   diff_one, diff_two))
            time.sleep(2)

    def get_specific_symbol(self, coin_sym='ETH', trade_currency='BTC'):
        """Returns a specific trading pair to see what price it is at in the orderbook.
            If no parameters are given, it will return the price of ETHBTC.
        
            Keyword Arguments:
            coin_sym -- This is the first symbol in the trading pair (default 'ETH')
            trade_currency -- This is the second symbol in the trading pair (default 'BTC')
        """
        if trade_currency != 'BTC' and trade_currency != 'ETH' and trade_currency != 'BNB':
            print('Trade currency can only be BTC or ETH')
            return {}
        trade_pair = coin_sym + trade_currency
        for k in self.orderbook:
            if list(k.keys())[0] == coin_sym[0:3]:
                for pair in k[list(k.keys())[0]]:
                    if pair['symbol'] == trade_pair:
                        return pair
        print('Pair not in orderbook.')
        return {}

    def get_orderbook_symbol(self, _symbol='ETHBTC', _limit=10):
        """ Returns the orderbook (buy/sell prices) of a given symbol.
            Limit will hold the orderbook to only 10 prices of the buy/sell pair
            
            Returns:
            Dictionary of prices
        """
        return self.client.get_order_book(symbol=_symbol, limit=_limit)

    def get_open_order_symbol(self, _symbol='ETHBTC'):
        """Get all open orders of a symbol """
        try:
            return self.client.get_open_orders(symbol=_symbol)
        except binexc.BinanceAPIException as e:
            print(e.message)
            self.get_open_orders_symbol(_symbol)

    def get_past_orders(self, _symbol='ETHBTC'):
        """ Get the user's past orders. 
        """
        return self.client.get_all_orders(symbol=_symbol)

    def load_arbitrage_assets(self):
        """ Loads the amount of coins in the user's account """
        flag = False
        btc_eth_bnb = {}
        while (flag is False):
            try:
                acc = self.client.get_account(
                    recvWindow=binance_config.recv_window)
                flag = True
            except binexc.BinanceAPIException as e:
                print(str(e.status_code) + " : " + e.message)
                time.sleep(1)
        #acc['balances']
        for cryptoasset in acc['balances']:
            if cryptoasset['asset'] == 'BTC':
                btc_eth_bnb['BTC'] = cryptoasset['free']
            if cryptoasset['asset'] == 'ETH':
                btc_eth_bnb['ETH'] = cryptoasset['free']
            if cryptoasset['asset'] == 'BNB':
                btc_eth_bnb['BNB'] = cryptoasset['free']
            if len(btc_eth_bnb) is 3:
                break
        btc_eth_bnb['datetime'] = datetime.datetime.now().replace(
            microsecond=0)
        return btc_eth_bnb
Beispiel #22
0
  elif count == 2:
    counter = 4
  elif count == 3:
    counter = 3
  elif count == 4:
    counter = 2
  elif count == 5:
    counter = 1
  elif count > 6:
    counter = 0

  ## get completed orders and print
  index = 1
  if count < 7:
    print("\033[1;36;40m" + 'completed ============ =========' + "\033[1;37;40m")
    all_orders = client.get_all_orders(symbol='BTCAUD', limit=100)

    for a in sorted(all_orders, reverse=True, key=lambda i: i['orderId']):
      if a['status'] == 'FILLED':
        aud = float(a['origQty']) * float(a['price'])
        print('  ' + str(index) + ': ' + "\033[1;32;40m" + str("${:,.2f}".format(aud)).rjust(7, ' ') + "\033[1;37;40m" + ' @ ' + "\033[1;35;40m" + str("${:,.0f}".format(float(a['price']))) + "\033[1;37;40m" + ' ' + "\033[1;37;44m" + str(a['status'])[0:7].center(9, ' ') + "\033[1;37;40m")
        index += 1
        counter -= 1
      elif a['status'] == 'PARTIALLY_FILLED':
        aud = float(a['origQty']) * float(a['price'])
        print('  ' + str(index) + ': ' + "\033[1;32;40m" + str("${:,.2f}".format(aud)).rjust(7, ' ') + "\033[1;37;40m" + ' @ ' + "\033[1;35;40m" + str("${:,.0f}".format(float(a['price']))) + "\033[1;37;40m" + ' ' + "\033[1;33;40m" + str(a['status'])[0:7].center(9, ' ') + "\033[1;37;40m")
        index += 1
        counter -= 1

      if counter == -1:
        break
Beispiel #23
0
class ApiClient:
    def __init__(self):
        self._client = None
        self._lock = threading.Lock()
        self._orders_since_run = []

    def connect(self):
        self._client = Client(API_KEY, API_SECRET)

    def get_raw_client(self):
        return self._client

    def get_asset_balance(self, asset):
        if self._client is None:
            print("client is undefined")
            return
        return self._client.get_asset_balance(asset)

    def get_balance(self):
        balance = self._client.get_account()
        my_balance = list(
            filter(
                lambda coin: float(coin['locked']) != 0 or float(coin['free'])
                != 0, balance['balances']))
        return my_balance

    def get_current_price(self, symbol):
        return float(self._client.get_symbol_ticker(symbol=symbol)['price'])

    def get_candles(self, symbol='ETHUSDT', interval='1m', limit=500):
        klines = self._client.get_klines(symbol=symbol,
                                         interval=interval,
                                         limit=limit)
        return [
            BinanceCandleStick(a[1], a[2], a[3], a[4], a[5], a[8])
            for a in klines
        ]

    def get_candles_dataframe(self,
                              symbol='ETHUSDT',
                              interval='1m',
                              limit=500):
        klines = self._client.get_klines(symbol=symbol,
                                         interval=interval,
                                         limit=limit)
        arr = []
        for candle in klines:
            obj = {
                'Open': float(candle[1]),
                'High': float(candle[2]),
                'Low': float(candle[3]),
                'Close': float(candle[4]),
                'Volume': candle[5],
                'Number Of Trades': candle[8]
            }
            arr.append(obj)
        return pd.DataFrame(arr)

    def get_close_prices_dataframe(self,
                                   symbol='ETHUSDT',
                                   interval='1m',
                                   limit=500):
        with self._lock:
            klines = self._client.get_klines(symbol=symbol,
                                             interval=interval,
                                             limit=limit)
            close_arr = [float(a[4]) for a in klines]
            np_arr = np.array(close_arr)
            data = {'Close': pd.Series(np_arr)}
            return pd.DataFrame(data)

    def get_all_orders(self, symbol='ETHUSDT'):
        return self._client.get_all_orders(symbol=symbol)

    def verify_limit_order(self, symbol, order_id):
        print(f"Verifying order ID {order_id}")
        order_recorded = False
        order_status = None
        while not order_recorded:
            try:
                time.sleep(2)
                order_status = self._client.get_order(symbol=symbol,
                                                      orderId=order_id)
            except BinanceAPIException as e:
                print(f"get_order failed: {e}")
                time.sleep(5)
            except Exception as e:
                print(f"Unexpected error: {e}")
                return False

        if order_status is None:
            print("Order status is None!")
            return False

        while order_status['status'] != 'FILLED':
            try:
                order_status = self._client.get_order(symbol=symbol,
                                                      orderId=order_id)
                time.sleep(1)
            except BinanceAPIException as e:
                print(e)
                time.sleep(2)
            except Exception as e:
                print(f"Unexpected error: {e}")
                return False

        return True

    def _execute_market_buy(self, symbol, quantity):
        api_res = None
        try:
            api_res = self._client.order_market_buy(symbol=symbol,
                                                    quantity=quantity)
            print(f"API result: {api_res}")
        except BinanceAPIException as e:
            print(f"Binance error: {e} - Error code: - {e.code}")
            if e.code == -2010:  # Account has insufficient balance for requested action
                print("No money.")
                return False
        except Exception as e:
            print(f"Unexpected error: {e}")

        return api_res

    def _execute_market_sell(self, symbol, quantity):
        api_res = None
        try:
            api_res = self._client.order_market_sell(symbol=symbol,
                                                     quantity=quantity)
            print(f"API result: {api_res}")
        except BinanceAPIException as e:
            print(f"Binance error: {e} - Error code: - {e.code}")
            if e.code == -2010:  # Account has insufficient balance for requested action
                print("No money.")
                return False
        except Exception as e:
            print(f"Unexpected error: {e}")

        return api_res

    def market_sell(self, symbol=None, quantity=None):
        if symbol is None or quantity is None:
            raise ValueError(
                "You MUST pass symbol and quantity. Be careful with this method!"
            )

        current_balance = self.get_asset_balance(
            asset=symbol.replace('USDT', ''))['free']
        print(f"Starting balance: {current_balance} {symbol}")

        if float(current_balance) < quantity:
            print(
                f"Cannot sell {quantity} when there is only {current_balance} available"
            )
            return False

        api_res = False
        for i in range(5):
            api_res = self._execute_market_sell(symbol, quantity)
            if api_res:
                break
            else:
                print(f"Market sell failed. Attempt number {i+1}")

        if not api_res:
            print("Error sending market sell")
            return False

        print(
            f"Sell order for {quantity} {symbol} filled. Order ID: {api_res['orderId']}"
        )

        after_sell_balance = self.get_asset_balance(
            asset=symbol.replace('USDT', ''))['free']
        print(f"Balance after sell order: {after_sell_balance} {symbol}")

        if isclose(float(current_balance) - quantity,
                   float(after_sell_balance),
                   abs_tol=1):
            print("Market sell order success")

        return api_res

    def market_buy(self, symbol=None, quantity=None):
        if symbol is None or quantity is None:
            raise ValueError(
                "You MUST pass symbol and quantity. Be careful with this method!"
            )

        current_balance = self.get_asset_balance(
            asset=symbol.replace('USDT', ''))['free']
        print(f"Starting balance: {current_balance} {symbol}")

        api_res = False
        for i in range(5):
            api_res = self._execute_market_buy(symbol, quantity)
            if api_res:
                break
            else:
                print(f"Market buy failed. Attempt number {i+1}")

        if not api_res:
            print("Error sending market buy")
            return False

        # print("Verifying market buy order")
        # order_verified = self.verify_order(symbol, api_res['orderId'])
        # if not order_verified:
        #     print(f"Order {api_res['orderId']} verification failed")
        # else:
        #     print(f"Buy order for {quantity} {symbol} filled. Order ID: {api_res['orderId']}")
        print(
            f"Buy order for {quantity} {symbol} filled. Order ID: {api_res['orderId']}"
        )

        after_buy_balance = self.get_asset_balance(
            asset=symbol.replace('USDT', ''))['free']
        print(f"Balance after buy order: {after_buy_balance} {symbol}")

        if isclose(float(current_balance) + quantity,
                   float(after_buy_balance),
                   abs_tol=1):
            print("Market buy order success")

        return api_res
Beispiel #24
0
    quantity=0.01,
    price=25000
    )"""
"""price = float(order['fills'][0]['price'])
pprint.pprint(price)"""
print("************************************************")

allcoins_info = client.get_all_tickers()
"""for coin in allcoins_info:
    if coin['symbol'] == 'XRPBUSD':
        our_price = coin['price']"""

#print(our_price)
print("**********************************************")

orders = client.get_all_orders(symbol='BTCBUSD')

order = client.get_order(symbol='XRPBUSD', orderId='42755')
#delete order
"""result = client.cancel_order(
    symbol='BTCBUSD',
    orderId='1787')"""
#open_orders = client.get_open_orders(symbol='BTCBUSD')

#account_snapshot = client.get_account_snapshot(type='SPOT')
"""for filter in symbol_info['filters']:
    if filter['filterType'] == 'PERCENT_PRICE':
        multiplierDown = float(filter['multiplierDown'])
        pprint.pprint(multiplierDown)
        multiplierUp = float(filter['multiplierUp'])
        pprint.pprint(multiplierUp)"""
Beispiel #25
0
class TradingAccount():
    def __init__(self, app={}):
        """Trading account object model

        Parameters
        ----------
        app : object
            PyCryptoBot object
        """

        # config needs to be a dictionary, empty or otherwise
        if not isinstance(app, object):
            raise TypeError('App is not a PyCryptoBot object.')

        if app.getExchange() == 'binance':
            self.client = Client(app.getAPIKey(), app.getAPISecret(), {
                'verify': False,
                'timeout': 20
            })

        # if trading account is for testing it will be instantiated with a balance of 1000
        self.balance = pd.DataFrame(
            [['QUOTE', 1000, 0, 1000], ['BASE', 0, 0, 0]],
            columns=['currency', 'balance', 'hold', 'available'])

        self.app = app

        if app.isLive() == 1:
            self.mode = 'live'
        else:
            self.mode = 'test'

        self.orders = pd.DataFrame()

    def __convertStatus(self, val):
        if val == 'filled':
            return 'done'
        else:
            return val

    def _checkMarketSyntax(self, market):
        """Check that the market is syntactically correct

        Parameters
        ----------
        market : str
            market to check
        """
        if self.app.getExchange() == 'coinbasepro' and market != '':
            p = re.compile(r"^[1-9A-Z]{2,5}\-[1-9A-Z]{2,5}$")
            if not p.match(market):
                raise TypeError('Coinbase Pro market is invalid.')
        elif self.app.getExchange() == 'binance':
            p = re.compile(r"^[A-Z]{6,12}$")
            if not p.match(market):
                raise TypeError('Binance market is invalid.')

    def getOrders(self, market='', action='', status='all'):
        """Retrieves orders either live or simulation

        Parameters
        ----------
        market : str, optional
            Filters orders by market
        action : str, optional
            Filters orders by action
        status : str
            Filters orders by status, defaults to 'all'
        """

        # validate market is syntactically correct
        self._checkMarketSyntax(market)

        if action != '':
            # validate action is either a buy or sell
            if not action in ['buy', 'sell']:
                raise ValueError('Invalid order action.')

        # validate status is open, pending, done, active or all
        if not status in [
                'open', 'pending', 'done', 'active', 'all', 'filled'
        ]:
            raise ValueError('Invalid order status.')

        if self.app.getExchange() == 'binance':
            if self.mode == 'live':
                resp = self.client.get_all_orders(symbol=market)
                if len(resp) > 0:
                    df = pd.DataFrame(resp)
                else:
                    df = pd.DataFrame()

                if len(df) == 0:
                    return pd.DataFrame()

                df = df[[
                    'time', 'symbol', 'side', 'type', 'executedQty',
                    'cummulativeQuoteQty', 'status'
                ]]
                df.columns = [
                    'created_at', 'market', 'action', 'type', 'size', 'value',
                    'status'
                ]
                df['created_at'] = df['created_at'].apply(
                    lambda x: int(str(x)[:10]))
                df['created_at'] = df['created_at'].astype("datetime64[s]")
                df['size'] = df['size'].astype(float)
                df['value'] = df['value'].astype(float)
                df['action'] = df['action'].str.lower()
                df['type'] = df['type'].str.lower()
                df['status'] = df['status'].str.lower()
                df['price'] = df['value'] / df['size']

                # pylint: disable=unused-variable
                for k, v in df.items():
                    if k == 'status':
                        df[k] = df[k].map(self.__convertStatus)

                if action != '':
                    df = df[df['action'] == action]
                    df = df.reset_index(drop=True)

                if status != 'all' and status != '':
                    df = df[df['status'] == status]
                    df = df.reset_index(drop=True)

                return df
            else:
                # return dummy orders
                if market == '':
                    return self.orders
                else:
                    if (len(self.orders) > 0):
                        return self.orders[self.orders['market'] == market]
                    else:
                        return pd.DataFrame()
        if self.app.getExchange() == 'coinbasepro':
            if self.mode == 'live':
                # if config is provided and live connect to Coinbase Pro account portfolio
                model = CBAuthAPI(self.app.getAPIKey(),
                                  self.app.getAPISecret(),
                                  self.app.getAPIPassphrase(),
                                  self.app.getAPIURL())
                # retrieve orders from live Coinbase Pro account portfolio
                self.orders = model.getOrders(market, action, status)
                return self.orders
            else:
                # return dummy orders
                if market == '':
                    return self.orders
                else:
                    return self.orders[self.orders['market'] == market]

    def getBalance(self, currency=''):
        """Retrieves balance either live or simulation

        Parameters
        ----------
        currency: str, optional
            Filters orders by currency
        """

        if self.app.getExchange() == 'binance':
            if self.mode == 'live':
                resp = self.client.get_account()
                if 'balances' in resp:
                    df = pd.DataFrame(resp['balances'])
                    df = df[(df['free'] != '0.00000000')
                            & (df['free'] != '0.00')]
                    df['free'] = df['free'].astype(float)
                    df['locked'] = df['locked'].astype(float)
                    df['balance'] = df['free'] - df['locked']
                    df.columns = ['currency', 'available', 'hold', 'balance']
                    df = df[['currency', 'balance', 'hold', 'available']]
                    df = df.reset_index(drop=True)

                    if currency == '':
                        # retrieve all balances
                        return df
                    else:
                        # retrieve balance of specified currency
                        df_filtered = df[df['currency'] ==
                                         currency]['available']
                        if len(df_filtered) == 0:
                            # return nil balance if no positive balance was found
                            return 0.0
                        else:
                            # return balance of specified currency (if positive)
                            if currency in ['EUR', 'GBP', 'USD']:
                                return float(
                                    self.app.truncate(
                                        float(df[df['currency'] == currency]
                                              ['available'].values[0]), 2))
                            else:
                                return float(
                                    self.app.truncate(
                                        float(df[df['currency'] == currency]
                                              ['available'].values[0]), 4))
                else:
                    return 0.0
            else:
                # return dummy balances
                if currency == '':
                    # retrieve all balances
                    return self.balance
                else:
                    if self.app.getExchange() == 'binance':
                        self.balance = self.balance.replace('QUOTE', currency)
                    else:
                        # replace QUOTE and BASE placeholders
                        if currency in ['EUR', 'GBP', 'USD']:
                            self.balance = self.balance.replace(
                                'QUOTE', currency)
                        else:
                            self.balance = self.balance.replace(
                                'BASE', currency)

                    if self.balance.currency[self.balance.currency.isin(
                        [currency])].empty == True:
                        self.balance.loc[len(
                            self.balance)] = [currency, 0, 0, 0]

                    # retrieve balance of specified currency
                    df = self.balance
                    df_filtered = df[df['currency'] == currency]['available']

                    if len(df_filtered) == 0:
                        # return nil balance if no positive balance was found
                        return 0.0
                    else:
                        # return balance of specified currency (if positive)
                        if currency in ['EUR', 'GBP', 'USD']:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 2))
                        else:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 4))

        else:
            if self.mode == 'live':
                # if config is provided and live connect to Coinbase Pro account portfolio
                model = CBAuthAPI(self.app.getAPIKey(),
                                  self.app.getAPISecret(),
                                  self.app.getAPIPassphrase(),
                                  self.app.getAPIURL())
                if currency == '':
                    # retrieve all balances
                    return model.getAccounts()[[
                        'currency', 'balance', 'hold', 'available'
                    ]]
                else:
                    df = model.getAccounts()
                    # retrieve balance of specified currency
                    df_filtered = df[df['currency'] == currency]['available']
                    if len(df_filtered) == 0:
                        # return nil balance if no positive balance was found
                        return 0.0
                    else:
                        # return balance of specified currency (if positive)
                        if currency in ['EUR', 'GBP', 'USD']:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 2))
                        else:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 4))

            else:
                # return dummy balances

                if currency == '':
                    # retrieve all balances
                    return self.balance
                else:
                    # replace QUOTE and BASE placeholders
                    if currency in ['EUR', 'GBP', 'USD']:
                        self.balance = self.balance.replace('QUOTE', currency)
                    elif currency in ['BCH', 'BTC', 'ETH', 'LTC', 'XLM']:
                        self.balance = self.balance.replace('BASE', currency)

                    if self.balance.currency[self.balance.currency.isin(
                        [currency])].empty == True:
                        self.balance.loc[len(
                            self.balance)] = [currency, 0, 0, 0]

                    # retrieve balance of specified currency
                    df = self.balance
                    df_filtered = df[df['currency'] == currency]['available']

                    if len(df_filtered) == 0:
                        # return nil balance if no positive balance was found
                        return 0.0
                    else:
                        # return balance of specified currency (if positive)
                        if currency in ['EUR', 'GBP', 'USD']:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 2))
                        else:
                            return float(
                                self.app.truncate(
                                    float(df[df['currency'] == currency]
                                          ['available'].values[0]), 4))

    def saveTrackerCSV(self, market='', save_file='tracker.csv'):
        """Saves order tracker to CSV

        Parameters
        ----------
        market : str, optional
            Filters orders by market
        save_file : str
            Output CSV file
        """

        # validate market is syntactically correct
        self._checkMarketSyntax(market)

        if self.mode == 'live':
            if self.app.getExchange() == 'coinbasepro':
                # retrieve orders from live Coinbase Pro account portfolio
                df = self.getOrders(market, '', 'done')
            elif self.app.getExchange() == 'binance':
                # retrieve orders from live Binance account portfolio
                df = self.getOrders(market, '', 'done')
            else:
                df = pd.DataFrame()
        else:
            # return dummy orders
            if market == '':
                df = self.orders
            else:
                if 'market' in self.orders:
                    df = self.orders[self.orders['market'] == market]
                else:
                    df = pd.DataFrame()

        if list(df.keys()) != [
                'created_at', 'market', 'action', 'type', 'size', 'value',
                'fees', 'price', 'status'
        ]:
            # no data, return early
            return False

        df_tracker = pd.DataFrame()

        last_action = ''
        for market in df['market'].sort_values().unique():
            df_market = df[df['market'] == market]

            df_buy = pd.DataFrame()
            df_sell = pd.DataFrame()

            pair = 0
            # pylint: disable=unused-variable
            for index, row in df_market.iterrows():
                if row['action'] == 'buy':
                    pair = 1

                if pair == 1 and (row['action'] != last_action):
                    if row['action'] == 'buy':
                        df_buy = row
                    elif row['action'] == 'sell':
                        df_sell = row

                if row['action'] == 'sell' and len(df_buy) != 0:
                    df_pair = pd.DataFrame(
                        [[
                            df_sell['status'], df_buy['market'],
                            df_buy['created_at'], df_buy['type'],
                            df_buy['size'], df_buy['value'], df_buy['fees'],
                            df_buy['price'], df_sell['created_at'],
                            df_sell['type'], df_sell['size'], df_sell['value'],
                            df_sell['fees'], df_sell['price']
                        ]],
                        columns=[
                            'status', 'market', 'buy_at', 'buy_type',
                            'buy_size', 'buy_value', 'buy_fees', 'buy_price',
                            'sell_at', 'sell_type', 'sell_size', 'sell_value',
                            'sell_fees', 'sell_price'
                        ])
                    df_tracker = df_tracker.append(df_pair, ignore_index=True)
                    pair = 0

                last_action = row['action']

        if list(df_tracker.keys()) != [
                'status', 'market', 'buy_at', 'buy_type', 'buy_size',
                'buy_value', 'buy_fees', 'buy_price', 'sell_at', 'sell_type',
                'sell_size', 'sell_value', 'sell_fees', 'sell_price'
        ]:
            # no data, return early
            return False

        df_tracker['profit'] = np.subtract(
            np.subtract(df_tracker['sell_value'], df_tracker['buy_value']),
            np.add(df_tracker['buy_fees'], df_tracker['sell_fees']))
        df_tracker['margin'] = np.multiply(
            np.true_divide(df_tracker['profit'], df_tracker['buy_value']), 100)
        df_sincebot = df_tracker[df_tracker['buy_at'] > '2021-02-1']

        try:
            df_sincebot.to_csv(save_file, index=False)
        except OSError:
            raise SystemExit('Unable to save: ', save_file)

    def buy(self,
            cryptoMarket,
            fiatMarket,
            fiatAmount=0,
            manualPrice=0.00000000):
        """Places a buy order either live or simulation

        Parameters
        ----------
        cryptoMarket: str
            Crypto market you wish to purchase
        fiatMarket, str
            QUOTE market funding the purchase
        fiatAmount, float
            QUOTE amount of crypto currency to purchase
        manualPrice, float
            Used for simulations specifying the live price to purchase
        """

        # fiat funding amount must be an integer or float
        if not isinstance(fiatAmount, float) and not isinstance(
                fiatAmount, int):
            raise TypeError('QUOTE amount not numeric.')

        # fiat funding amount must be positive
        if fiatAmount <= 0:
            raise Exception('Invalid QUOTE amount.')

        if self.app.getExchange() == 'binance':
            # validate crypto market is syntactically correct
            p = re.compile(r"^[A-Z]{3,8}$")
            if not p.match(cryptoMarket):
                raise TypeError('Binance crypto market is invalid.')

            # validate fiat market is syntactically correct
            p = re.compile(r"^[A-Z]{3,8}$")
            if not p.match(fiatMarket):
                raise TypeError('Binance fiat market is invalid.')
        else:
            # crypto market should be either BCH, BTC, ETH, LTC or XLM
            if cryptoMarket not in ['BCH', 'BTC', 'ETH', 'LTC', 'XLM']:
                raise Exception(
                    'Invalid crypto market: BCH, BTC, ETH, LTC, ETH, or XLM')

            # fiat market should be either EUR, GBP, or USD
            if fiatMarket not in ['EUR', 'GBP', 'USD']:
                raise Exception('Invalid QUOTE market: EUR, GBP, USD')

        # reconstruct the exchange market using crypto and fiat inputs
        if self.app.getExchange() == 'binance':
            market = cryptoMarket + fiatMarket
        else:
            market = cryptoMarket + '-' + fiatMarket

        if self.app.getExchange() == 'binance':
            if self.mode == 'live':
                # execute a live market buy
                resp = self.client.order_market_buy(symbol=market,
                                                    quantity=fiatAmount)

                # TODO: not finished
                print(resp)
            else:
                # fiat amount should exceed balance
                if fiatAmount > self.getBalance(fiatMarket):
                    raise Exception('Insufficient funds.')

                # manual price must be an integer or float
                if not isinstance(manualPrice, float) and not isinstance(
                        manualPrice, int):
                    raise TypeError('Optional manual price not numeric.')

                price = manualPrice
                # if manualPrice is non-positive retrieve the current live price
                if manualPrice <= 0:
                    if self.app.getExchange() == 'binance':
                        api = BPublicAPI()
                        price = api.getTicker(market)
                    else:
                        resp = requests.get(
                            'https://api-public.sandbox.pro.coinbase.com/products/'
                            + market + '/ticker')
                        if resp.status_code != 200:
                            raise Exception(
                                'GET /products/' + market +
                                '/ticker {}'.format(resp.status_code))
                        resp.raise_for_status()
                        json = resp.json()
                        price = float(json['price'])

                # calculate purchase fees
                fee = fiatAmount * 0.005
                fiatAmountMinusFee = fiatAmount - fee
                total = float(fiatAmountMinusFee / float(price))

                # append dummy order into orders dataframe
                ts = pd.Timestamp.now()
                price = (fiatAmountMinusFee * 100) / (total * 100)
                order = pd.DataFrame([[
                    '', market, 'buy', 'market',
                    float('{:.8f}'.format(total)), fiatAmountMinusFee, 'done',
                    '{:.8f}'.format(float(price))
                ]],
                                     columns=[
                                         'created_at', 'market', 'action',
                                         'type', 'size', 'value', 'status',
                                         'price'
                                     ],
                                     index=[ts])
                order['created_at'] = order.index
                self.orders = pd.concat(
                    [self.orders, pd.DataFrame(order)], ignore_index=False)

                # update the dummy fiat balance
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'balance'] = self.getBalance(fiatMarket) - fiatAmount
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'available'] = self.getBalance(fiatMarket) - fiatAmount

                # update the dummy crypto balance
                self.balance.loc[self.balance['currency'] == cryptoMarket,
                                 'balance'] = self.getBalance(cryptoMarket) + (
                                     fiatAmountMinusFee / price)
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'available'] = self.getBalance(cryptoMarket) + (
                        fiatAmountMinusFee / price)

        else:
            if self.mode == 'live':
                # connect to coinbase pro api (authenticated)
                model = CBAuthAPI(self.app.getAPIKey(),
                                  self.app.getAPISecret(),
                                  self.app.getAPIPassphrase(),
                                  self.app.getAPIURL())

                # execute a live market buy
                if fiatAmount > 0:
                    resp = model.marketBuy(market, fiatAmount)
                else:
                    resp = model.marketBuy(market,
                                           float(self.getBalance(fiatMarket)))

                # TODO: not finished
                print(resp)
            else:
                # fiat amount should exceed balance
                if fiatAmount > self.getBalance(fiatMarket):
                    raise Exception('Insufficient funds.')

                # manual price must be an integer or float
                if not isinstance(manualPrice, float) and not isinstance(
                        manualPrice, int):
                    raise TypeError('Optional manual price not numeric.')

                price = manualPrice
                # if manualPrice is non-positive retrieve the current live price
                if manualPrice <= 0:
                    resp = requests.get(
                        'https://api-public.sandbox.pro.coinbase.com/products/'
                        + market + '/ticker')
                    if resp.status_code != 200:
                        raise Exception('GET /products/' + market +
                                        '/ticker {}'.format(resp.status_code))
                    resp.raise_for_status()
                    json = resp.json()
                    price = float(json['price'])

                # calculate purchase fees
                fee = fiatAmount * 0.005
                fiatAmountMinusFee = fiatAmount - fee
                total = float(fiatAmountMinusFee / price)

                # append dummy order into orders dataframe
                ts = pd.Timestamp.now()
                price = (fiatAmountMinusFee * 100) / (total * 100)
                order = pd.DataFrame([[
                    '', market, 'buy', 'market',
                    float('{:.8f}'.format(total)), fiatAmountMinusFee, 'done',
                    price
                ]],
                                     columns=[
                                         'created_at', 'market', 'action',
                                         'type', 'size', 'value', 'status',
                                         'price'
                                     ],
                                     index=[ts])
                order['created_at'] = order.index
                self.orders = pd.concat(
                    [self.orders, pd.DataFrame(order)], ignore_index=False)

                # update the dummy fiat balance
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'balance'] = self.getBalance(fiatMarket) - fiatAmount
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'available'] = self.getBalance(fiatMarket) - fiatAmount

                # update the dummy crypto balance
                self.balance.loc[self.balance['currency'] == cryptoMarket,
                                 'balance'] = self.getBalance(cryptoMarket) + (
                                     fiatAmountMinusFee / price)
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'available'] = self.getBalance(cryptoMarket) + (
                        fiatAmountMinusFee / price)

    def sell(self,
             cryptoMarket,
             fiatMarket,
             cryptoAmount,
             manualPrice=0.00000000):
        """Places a sell order either live or simulation

        Parameters
        ----------
        cryptoMarket: str
            Crypto market you wish to purchase
        fiatMarket, str
            QUOTE market funding the purchase
        fiatAmount, float
            QUOTE amount of crypto currency to purchase
        manualPrice, float
            Used for simulations specifying the live price to purchase
        """
        if self.app.getExchange() == 'binance':
            # validate crypto market is syntactically correct
            p = re.compile(r"^[A-Z]{3,8}$")
            if not p.match(cryptoMarket):
                raise TypeError('Binance crypto market is invalid.')

            # validate fiat market is syntactically correct
            p = re.compile(r"^[A-Z]{3,8}$")
            if not p.match(fiatMarket):
                raise TypeError('Binance fiat market is invalid.')
        else:
            # crypto market should be either BCH, BTC, ETH, LTC or XLM
            if cryptoMarket not in ['BCH', 'BTC', 'ETH', 'LTC', 'XLM']:
                raise Exception(
                    'Invalid crypto market: BCH, BTC, ETH, LTC, ETH, or XLM')

            # fiat market should be either EUR, GBP, or USD
            if fiatMarket not in ['EUR', 'GBP', 'USD']:
                raise Exception('Invalid QUOTE market: EUR, GBP, USD')

        # reconstruct the exchange market using crypto and fiat inputs
        if self.app.getExchange() == 'binance':
            market = cryptoMarket + fiatMarket
        else:
            market = cryptoMarket + '-' + fiatMarket

        # crypto amount must be an integer or float
        if not isinstance(cryptoAmount, float) and not isinstance(
                cryptoAmount, int):
            raise TypeError('Crypto amount not numeric.')

        # crypto amount must be positive
        if cryptoAmount <= 0:
            raise Exception('Invalid crypto amount.')

        if self.app.getExchange() == 'binance':
            if self.mode == 'live':
                # execute a live market buy
                resp = self.client.order_market_sell(symbol=market,
                                                     quantity=cryptoAmount)

                # TODO: not finished
                print(resp)
            else:
                # crypto amount should exceed balance
                if cryptoAmount > self.getBalance(cryptoMarket):
                    raise Exception('Insufficient funds.')

                # manual price must be an integer or float
                if not isinstance(manualPrice, float) and not isinstance(
                        manualPrice, int):
                    raise TypeError('Optional manual price not numeric.')

                # calculate purchase fees
                fee = cryptoAmount * 0.005
                cryptoAmountMinusFee = cryptoAmount - fee

                price = manualPrice
                # if manualPrice is non-positive retrieve the current live price
                if manualPrice <= 0:
                    resp = requests.get(
                        'https://api-public.sandbox.pro.coinbase.com/products/'
                        + market + '/ticker')
                    if resp.status_code != 200:
                        raise Exception('GET /products/' + market +
                                        '/ticker {}'.format(resp.status_code))
                    resp.raise_for_status()
                    json = resp.json()
                    price = float(json['price'])

                total = price * cryptoAmountMinusFee

                # append dummy order into orders dataframe
                ts = pd.Timestamp.now()
                price = ((price * cryptoAmount) * 100) / (cryptoAmount * 100)
                order = pd.DataFrame([[
                    '', market, 'sell', 'market', cryptoAmountMinusFee,
                    float('{:.8f}'.format(total)), 'done', '{:.8f}'.format(
                        float(price))
                ]],
                                     columns=[
                                         'created_at', 'market', 'action',
                                         'type', 'size', 'value', 'status',
                                         'price'
                                     ],
                                     index=[ts])
                order['created_at'] = order.index
                self.orders = pd.concat(
                    [self.orders, pd.DataFrame(order)], ignore_index=False)

                # update the dummy fiat balance
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'balance'] = self.getBalance(fiatMarket) + total
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'available'] = self.getBalance(fiatMarket) + total

                # update the dummy crypto balance
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'balance'] = self.getBalance(cryptoMarket) - cryptoAmount
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'available'] = self.getBalance(cryptoMarket) - cryptoAmount

        else:
            if self.mode == 'live':
                # connect to Coinbase Pro API live
                model = CBAuthAPI(self.app.getAPIKey(),
                                  self.app.getAPISecret(),
                                  self.app.getAPIPassphrase(),
                                  self.app.getAPIURL())

                # execute a live market sell
                resp = model.marketSell(market,
                                        float(self.getBalance(cryptoMarket)))

                # TODO: not finished
                print(resp)
            else:
                # crypto amount should exceed balance
                if cryptoAmount > self.getBalance(cryptoMarket):
                    raise Exception('Insufficient funds.')

                # manual price must be an integer or float
                if not isinstance(manualPrice, float) and not isinstance(
                        manualPrice, int):
                    raise TypeError('Optional manual price not numeric.')

                # calculate purchase fees
                fee = cryptoAmount * 0.005
                cryptoAmountMinusFee = cryptoAmount - fee

                price = manualPrice
                if manualPrice <= 0:
                    # if manualPrice is non-positive retrieve the current live price
                    resp = requests.get(
                        'https://api-public.sandbox.pro.coinbase.com/products/'
                        + market + '/ticker')
                    if resp.status_code != 200:
                        raise Exception('GET /products/' + market +
                                        '/ticker {}'.format(resp.status_code))
                    resp.raise_for_status()
                    json = resp.json()
                    price = float(json['price'])

                total = price * cryptoAmountMinusFee

                # append dummy order into orders dataframe
                ts = pd.Timestamp.now()
                price = ((price * cryptoAmount) * 100) / (cryptoAmount * 100)
                order = pd.DataFrame([[
                    market, 'sell', 'market', cryptoAmountMinusFee,
                    float('{:.8f}'.format(total)), 'done', price
                ]],
                                     columns=[
                                         'market', 'action', 'type', 'size',
                                         'value', 'status', 'price'
                                     ],
                                     index=[ts])
                order['created_at'] = order.index
                self.orders = pd.concat(
                    [self.orders, pd.DataFrame(order)], ignore_index=False)

                # update the dummy fiat balance
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'balance'] = self.getBalance(fiatMarket) + total
                self.balance.loc[
                    self.balance['currency'] == fiatMarket,
                    'available'] = self.getBalance(fiatMarket) + total

                # update the dummy crypto balance
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'balance'] = self.getBalance(cryptoMarket) - cryptoAmount
                self.balance.loc[
                    self.balance['currency'] == cryptoMarket,
                    'available'] = self.getBalance(cryptoMarket) - cryptoAmount
Beispiel #26
0
class Bot(object):
    TIME  = 0
    OPEN  = 1
    HIGH  = 2
    LOW   = 3
    CLOSE = 4
    TREND = 'UP'

    API_KEY = ''
    API_SECRET = ''

    current_stop = {}
    price_round = 0
    min_points_list = []
    data_dict = {
        'timestamp': [],
        'close':[],
        'low':[]
    }


    def __init__(self, symbol):
        self.logger = Logger().init_logger()
        config = configparser.ConfigParser()
        config.read('conf.ini')
        self.API_KEY = config['API_KEYS']['api_key']
        self.API_SECRET = config['API_KEYS']['api_secret']
        self.client = Client(self.API_KEY, self.API_SECRET)
        self.symbol = symbol
        order = self.client.get_all_orders(symbol=self.symbol)[-1]
        self.current_stop = {
            'orderId': order['orderId'],
            'price': float(order['stopPrice'])
        }
        p = float(self.client.get_symbol_info(symbol=self.symbol)['filters'][2]['minQty'])
        while p != 1:
            p = p * 10
            self.price_round = self.price_round + 1
        self.logger.info("bot started guarding, current stop: {}, price round: {}".format(self.current_stop, self.price_round))

    def get_historical_data(self, time_interval):
        startDay = (datetime.datetime.now()).strftime('%Y-%m-%d')
        return self.client.get_historical_klines(self.symbol, time_interval, startDay)

    def data_dict_init(self, historical_data):
        self.data_dict['timestamp'].append(datetime.datetime.fromtimestamp(historical_data[-2][self.TIME] / 1e3).strftime("%d/%m/%Y, %H:%M:%S"))
        self.data_dict['close'].append(float(historical_data[-2][self.CLOSE]))
        self.data_dict['low'].append(float(historical_data[-2][self.LOW]))
        self.data_dict['timestamp'].append(datetime.datetime.fromtimestamp(historical_data[-1][self.TIME] / 1e3).strftime("%d/%m/%Y, %H:%M:%S"))
        self.data_dict['close'].append(float(historical_data[-1][self.CLOSE]))
        self.data_dict['low'].append(float(historical_data[-1][self.LOW]))
        self.logger.info("data dictionary has initiated {}".format(self.data_dict))
        self.min_points_list.append(
            [
                self.data_dict['timestamp'][-1],
                self.data_dict['low'][-1]
            ]
        )

    def populate_data_dict(self, historical_data):
        if self.data_dict['timestamp'][-1] == datetime.datetime.fromtimestamp(historical_data[-2][self.TIME] / 1e3).strftime("%d/%m/%Y, %H:%M:%S"):
            return
        self.data_dict['timestamp'].append(datetime.datetime.fromtimestamp(historical_data[-2][self.TIME] / 1e3).strftime("%d/%m/%Y, %H:%M:%S"))
        self.data_dict['close'].append(float(historical_data[-2][self.CLOSE]))
        self.data_dict['low'].append(float(historical_data[-2][self.LOW]))

    def validate_min_list(self):
        mp_list = []
        if len(self.min_points_list) < 2:
            return
        for mp in self.min_points_list:
            mp_list.append(mp[1])
        diff = np.diff(mp_list)
        if diff[-1] < 0:
            self.logger.warning("the minimum list has lost it's validity with a new lower low")

    def create_min_list(self):
        diff_array = np.diff(self.data_dict['close'])
        if float(diff_array[-1]) > 0 and self.TREND == 'DOWN':
            self.TREND = 'UP'
            if self.min_points_list[-1][1] > self.data_dict['low'][-2]:
                self.min_points_list.pop()
            if self.data_dict['low'][-2] < self.data_dict['low'][-1]:
                self.min_points_list.append(
                    [
                        self.data_dict['timestamp'][-2],
                        self.data_dict['low'][-2]
                    ]
                )
            else:
                self.min_points_list.append(
                    [
                        self.data_dict['timestamp'][-1],
                        self.data_dict['low'][-1]
                    ]
                )
            self.logger.info("list of minimums is: {}".format(self.min_points_list))
        if float(diff_array[-1]) < 0 and self.TREND == 'UP':
            self.TREND = 'DOWN'
        print("diff: {} trend:{}".format(diff_array[-1], self.TREND))
        sleep(3)

    def wait_for_data(self, time_interval):
        time = datetime.datetime.now().strftime("%M")
        if 'h' in time_interval:
            while time != '00':
                time = datetime.datetime.now().strftime("%M")
                sleep(5)
            return
        interval = int(time_interval.replace('m',''))
        while int(time) % interval != 0:
                time = datetime.datetime.now().strftime("%M")
                sleep(5)

    def change_stop_limit(self, stop):
        self.client.cancel_order(orderId=self.current_stop['orderId'], symbol=self.symbol)
        quantity = float(self.client.get_asset_balance(asset=self.symbol.replace('USDT',''))['free'])
        quantity = round(quantity, self.price_round)
        order = self.client.create_order(type="STOP_LOSS_LIMIT", side="SELL",price=stop, stopPrice=stop, quantity=quantity, symbol=self.symbol, timeInForce='GTC')
        self.current_stop = {
            'orderId': order['orderId'],
            'price': stop
        }
        self.logger.info("stop has changed: {}".format(self.current_stop))

    def is_new_stop(self):
        mp_list = []
        diff_abs_list = []
        if len(self.min_points_list) < 3:
            return False
        for mp in self.min_points_list:
            mp_list.append(mp[1])
        diff = np.diff(mp_list)
        for d in diff:
            diff_abs_list.append(d/abs(d))
        if diff_abs_list[-1] + diff_abs_list[-2] == 2:
            if self.min_points_list[-3][1] > self.current_stop['price']:
                return True
        return False

    def trade_guard(self, time_interval):
        historical_data = self.get_historical_data(time_interval)
        self.data_dict_init(historical_data)

        while True:
            self.wait_for_data(time_interval)
            historical_data = self.get_historical_data(time_interval)
            self.populate_data_dict(historical_data)
            self.create_min_list()
            if self.is_new_stop():
                self.change_stop_limit(self.min_points_list[-3][1])
Beispiel #27
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 BinanceExchange(AbstractExchange):
    _exchange_name = EXCHANGE__BINANCE
    _exchange_token = 'BNB'
    _intervals = {
        Candle.INTERVAL__1MINUTE: Client.KLINE_INTERVAL_1MINUTE,
        Candle.INTERVAL__5MINUTE: Client.KLINE_INTERVAL_5MINUTE,
        Candle.INTERVAL__15MINUTE: Client.KLINE_INTERVAL_15MINUTE,
        Candle.INTERVAL__1HOUR: Client.KLINE_INTERVAL_1HOUR
    }

    def __init__(self, api_key, api_secret, watchlist):
        super().__init__(api_key, api_secret, watchlist)
        self.client = Client(api_key, api_secret)

    def build_market_name(self, crypto, base_currency):
        # Binance uses HYDROBTC format
        return f"{crypto}{base_currency}"

    def initialize_market(self, crypto, base_currency, recheck=False):
        """
            Make sure we have MarketParams for the given market
        """
        market = self.build_market_name(crypto, base_currency)

        params = MarketParams.get_market(
            market, exchange=MarketParams.EXCHANGE__BINANCE)
        if not params or recheck:
            # Have to query the API and populate
            """
                {
                    'symbol': 'ASTBTC',
                    'status': 'TRADING',
                    'baseAsset': 'AST',
                    'baseAssetPrecision': 8,
                    'quoteAsset': 'BTC',
                    'quotePrecision': 8,
                    'orderTypes': ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'],
                    'icebergAllowed': False,
                    'filters': [
                        {
                            'filterType': 'PRICE_FILTER',
                            'minPrice': '0.00000001',
                            'maxPrice': '100000.00000000',
                            'tickSize': '0.00000001'
                        },
                        {
                            'filterType': 'LOT_SIZE',
                            'minQty': '1.00000000',
                            'maxQty': '90000000.00000000',
                            'stepSize': '1.00000000'
                        },
                        {
                            'filterType': 'MIN_NOTIONAL',
                            'minNotional': '0.00100000'
                        }
                    ]
                }
            """
            response = self.client.get_symbol_info(symbol=market)
            if not response:
                raise Exception(
                    f"Couldn't retrieve current ticker for '{self.build_market_name(crypto, base_currency)}' on {self.exchange_name}"
                )

            tick_size = None
            step_size = None
            min_notional = None
            multiplier_up = None
            avg_price_minutes = None

            for filter in response["filters"]:
                if filter['filterType'] == 'PRICE_FILTER':
                    tick_size = Decimal(filter["tickSize"])

                elif filter['filterType'] == 'LOT_SIZE':
                    step_size = Decimal(filter["stepSize"])

                elif filter['filterType'] == 'MIN_NOTIONAL':
                    min_notional = Decimal(filter["minNotional"])

                elif filter['filterType'] == 'PERCENT_PRICE':
                    multiplier_up = Decimal(filter["multiplierUp"])
                    avg_price_minutes = Decimal(filter["avgPriceMins"])

            if params:
                params.tick_size = tick_size
                params.step_size = step_size
                params.min_notional = min_notional
                params.multiplier_up = multiplier_up
                params.avg_price_minutes = avg_price_minutes
                params.save()

                print(f"Re-loaded MarketParams for {market}")
            else:
                MarketParams.create(exchange=MarketParams.EXCHANGE__BINANCE,
                                    market=market,
                                    price_tick_size=tick_size,
                                    lot_step_size=step_size,
                                    min_notional=min_notional,
                                    multiplier_up=multiplier_up,
                                    avg_price_minutes=avg_price_minutes)

                print(f"Loaded MarketParams for {market}")

    def ingest_latest_candles(self, market, interval, since=None, limit=5):
        """
            Get the most recent n (limit) candles.

              [
                1499040000000,      // Open time
                "0.01634790",       // Open
                "0.80000000",       // High
                "0.01575800",       // Low
                "0.01577100",       // Close
                "148976.11427815",  // Volume
                1499644799999,      // Close time
                "2434.19055334",    // Quote asset volume
                308,                // Number of trades
                "1756.87402397",    // Taker buy base asset volume
                "28.46694368",      // Taker buy quote asset volume
                "17928899.62484339" // Ignore
              ]
        """
        if limit == 1:
            # Never ingest the most recent (still-open) candle
            return

        print(f"{market} candles: {limit} | {since}")

        # Give the exchange a breather so we don't get API limited
        if limit > 10:
            time.sleep(3)

        if since:
            # Convert Unix timestamp to binance's millisecond timestamp
            since = since * 1000 + 1

        raw_data = self.client.get_klines(symbol=market,
                                          interval=self._intervals[interval],
                                          startTime=since,
                                          limit=limit)
        # print(json.dumps(raw_data, indent=4))

        # Never ingest the most recent (still-open) candle (most recent is last)
        Candle.batch_create_candles(market, interval,
                                    self._format_candles(raw_data[:-1]))

    def load_historical_candles(self, market, interval, since):
        """
            This is a historical batch update of all candles from 'since' to now.

              [
                1499040000000,      // Open time
                "0.01634790",       // Open
                "0.80000000",       // High
                "0.01575800",       // Low
                "0.01577100",       // Close
                "148976.11427815",  // Volume
                1499644799999,      // Close time
                "2434.19055334",    // Quote asset volume
                308,                // Number of trades
                "1756.87402397",    // Taker buy base asset volume
                "28.46694368",      // Taker buy quote asset volume
                "17928899.62484339" // Ignore
              ]
        """
        candles = self.client.get_historical_klines(market,
                                                    self._intervals[interval],
                                                    since)
        return self._format_candles(candles)

    def _format_candles(self, candles):
        results = []
        for candle in candles:
            results.append({
                "timestamp": candle[0] / 1000.0,
                "open": Decimal(candle[1]),
                "high": Decimal(candle[2]),
                "low": Decimal(candle[3]),
                "close": Decimal(candle[4])
            })

        return results

    def get_current_balance(self, asset='BTC'):
        return Decimal(self.client.get_asset_balance(asset=asset)["free"])

    def get_current_balances(self):
        if config.is_test:
            pass

        else:
            """ {
                    'asset': 'BTC', 
                    'free': '0.00000000', 
                    'locked': '0.00000000'
                }
            """
            return {
                'BTC': self.get_current_balance(asset='BTC'),
                'BNB': self.get_current_balance(asset='BNB')
            }

    def buy(self, market, quantity):
        """
            Place a market buy order. As soon as it completes submit a stop-loss
            limit order.
        """
        # Adjust quantity as needed to conform to MarketParams; quantity can only
        #   be divided down to so many digits of precision, depending on the
        #   particular market.
        market_params = MarketParams.get_market(market)
        quantized_qty = quantity.quantize(market_params.lot_step_size)
        """ {
                'symbol': 'BNBBTC',
                'orderId': 58158667,
                'clientOrderId': 'jFTEtmTTUTqspMi6Oq08R9',
                'transactTime': 1529546953007,
                'price': '0.00000000',
                'origQty': '1.55000000',
                'executedQty': '1.55000000',
                'status': 'FILLED',
                'timeInForce': 'GTC',
                'type': 'MARKET',
                'side': 'BUY'
            }
        """
        try:
            buy_order_response = self.client.order_market_buy(
                symbol=market,
                quantity=quantized_qty,
                newOrderRespType=Client.
                ORDER_RESP_TYPE_FULL  # Need the full details to get 'commission' (aka fees).
            )
        except Exception as e:
            print(f"-------------- MARKET BUY EXCEPTION!! --------------" +
                  f" | {market}" + f" | quantized_qty: {quantized_qty}")

            # Throw it back up to bomb us out
            raise e

        if config.verbose:
            print(
                f"BUY ORDER: {json.dumps(buy_order_response, sort_keys=True, indent=4)}"
            )

        order_id = buy_order_response["orderId"]
        timestamp = buy_order_response["transactTime"] / 1000

        if buy_order_response["status"] != 'FILLED':
            # TODO: handle unfilled market buys
            raise Exception(
                f"Buy order not FILLED (yet?)\n{buy_order_response}")

        elif buy_order_response["status"] == 'FILLED':
            # Calculate an aggregate purchase price
            total_spent = Decimal(0.0)
            total_qty = Decimal(0.0)
            total_commission = Decimal(0.0)
            for fill in buy_order_response["fills"]:
                """ {
                        "price": "4000.00000000",
                        "qty": "1.00000000",
                        "commission": "4.00000000",
                        "commissionAsset": "USDT"
                    }
                """
                total_spent += Decimal(fill["price"]) * Decimal(fill["qty"])
                total_qty += Decimal(fill["qty"])
                total_commission += Decimal(fill["commission"])

            purchase_price = total_spent / total_qty

            return {
                "order_id": order_id,
                "price": purchase_price,
                "quantity": total_qty,
                "fees": total_commission,
                "timestamp": timestamp
            }

    def reload_exchange_token(self, quantity):
        print(
            f"Reloading {quantity:.4f} {self.exchange_token} exchange tokens")
        market = f'{self.exchange_token}BTC'
        return self.buy(market, quantity)

    def market_sell(self, market, quantity):
        # Round prices to conform to price_tick_size for this market
        market_params = MarketParams.get_market(market)
        quantized_qty = quantity.quantize(market_params.lot_step_size)

        try:
            response = self.client.order_market_sell(
                symbol=market,
                quantity=quantized_qty,
                newOrderRespType=Client.
                ORDER_RESP_TYPE_FULL  # Need the full details to get 'commission' (aka fees).
            )
        except Exception as e:
            error_msg = (f"MARKET SELL ORDER: {market}" +
                         f" | quantized_qty: {quantized_qty}\n" + f"{e}")
            cprint(error_msg, "red")

            # TODO: Email error notifications?
            raise e

        print(f"MARKET SELL ORDER: {response}")

        order_id = response["orderId"]
        timestamp = response["transactTime"] / 1000

        if response["status"] != 'FILLED':
            # TODO: handle unfilled market sells
            raise Exception(f"Market sell order not FILLED (yet?)\n{response}")

        elif response["status"] == 'FILLED':
            # Calculate an aggregate sale price
            total_made = Decimal('0.0')
            total_qty = Decimal(response["executedQty"])
            total_commission = Decimal('0.0')
            for fill in response["fills"]:
                """ {
                        "price": "4000.00000000",
                        "qty": "1.00000000",
                        "commission": "4.00000000",
                        "commissionAsset": "BNB"
                    }
                """
                total_made += Decimal(fill["price"]) * Decimal(fill["qty"])
                total_commission += Decimal(fill["commission"])

            sell_price = total_made / total_qty

            return {
                "order_id": order_id,
                "price": sell_price,
                "quantity": total_qty,
                "fees": total_commission,
                "timestamp": timestamp
            }

        else:
            raise Exception("Unhandled case!")

    def limit_sell(self, market, quantity, bid_price):
        # Round prices to conform to price_tick_size for this market
        market_params = MarketParams.get_market(market)
        quantized_qty = quantity.quantize(market_params.lot_step_size)
        bid_price = bid_price.quantize(market_params.price_tick_size)

        try:
            response = self.client.order_limit_sell(
                symbol=market,
                quantity=quantized_qty,
                price=
                f"{bid_price:0.8f}",  # Pass as string to ensure input accuracy and format
                newOrderRespType=Client.
                ORDER_RESP_TYPE_FULL  # Need the full details to get 'commission' (aka fees).
            )
        except Exception as e:
            error_msg = (f"LIMIT SELL ORDER: {market}" +
                         f" | quantized_qty: {quantized_qty}" +
                         f" | bid_price: {bid_price}" + f"{e}")
            if 'PERCENT_PRICE' in error_msg:
                cprint(
                    f"Attempted to set a price ({bid_price}) outside the exchange's {market} PERCENT_PRICE range",
                    "red")
                return None

            if 'MIN_NOTIONAL' in error_msg:
                cprint(
                    f"Attempted to set a notional value ({bid_price} * {quantized_qty}) outside the exchange's {market} MIN_NOTIONAL",
                    "red")
                return None

            if 'Account has insufficient balance for requested action.' in error_msg:
                cprint(
                    f"Insufficent balance for {market} LIMIT SELL {quantized_qty}"
                )
                return None

            cprint(error_msg, "red")

            # TODO: Email error notifications?
            raise e

        if config.verbose:
            print(f"LIMIT SELL ORDER: {response}")

        order_id = response["orderId"]
        timestamp = response["transactTime"] / 1000

        return {
            "order_id": order_id,
            "price": bid_price,
            "quantity": quantized_qty
        }

    def set_stop_loss(self, market, quantity, stop_loss_price):
        limit_price = stop_loss_price * config.params[
            "stop_loss_limit_percentage"]

        # Round prices to conform to price_tick_size for this market
        market_params = MarketParams.get_market(market)

        # Round the quantity to one less decimal place than specified
        #   e.g. lot_step_size = '0.001' but round 0.123 to 0.12
        #   see: https://redd.it/7ej5cn
        quantized_qty = quantity.quantize(market_params.lot_step_size)

        # Same for the price
        stop_loss_price = stop_loss_price.quantize(
            market_params.price_tick_size)
        limit_price = limit_price.quantize(market_params.price_tick_size)

        try:
            response = self.client.create_order(
                symbol=market,
                quantity=quantized_qty,
                price=limit_price,
                stopPrice=stop_loss_price,
                type=Client.ORDER_TYPE_STOP_LOSS_LIMIT,
                side=Client.SIDE_SELL,
                timeInForce=Client.TIME_IN_FORCE_GTC,
                newOrderRespType=Client.ORDER_RESP_TYPE_FULL)
        except binance.exceptions.BinanceAPIException as e:
            error_msg = (f"STOP LOSS LIMIT ORDER: {market}" +
                         f" | quantity: {quantity}" +
                         f" | quantized_qty: {quantized_qty}" +
                         f" | price: {limit_price}" +
                         f" | stopPrice: {stop_loss_price}\n" + f"{e}")
            cprint(error_msg, "red")
            return {"error_code": e.code}

        except Exception as e:
            error_msg = (f"STOP LOSS LIMIT ORDER: {market}" +
                         f" | quantity: {quantity}" +
                         f" | quantized_qty: {quantized_qty}" +
                         f" | price: {limit_price}" +
                         f" | stopPrice: {stop_loss_price}\n" + f"{e}")
            cprint(error_msg, "red")

            # TODO: Handle binance.exceptions.BinanceAPIException: APIError(code=-2010): Order would trigger immediately.
            #   Immediately submit it as a market sell order instead?

            # TODO: Email error notifications?
            raise e

            order_id = response["orderId"]
            timestamp = response["transactTime"] / 1000

        return {
            "order_id": order_id,
            "quantity": quantized_qty,
            "stop_loss_price": stop_loss_price,
            "limit_price": limit_price,
            "timestamp": timestamp
        }

    def cancel_order(self, market, order_id):
        """
            {
              "symbol": "LTCBTC",
              "orderId": 28,
              "origClientOrderId": "myOrder1",
              "clientOrderId": "cancelMyOrder1",
              "transactTime": 1507725176595,
              "price": "1.00000000",
              "origQty": "10.00000000",
              "executedQty": "8.00000000",
              "cummulativeQuoteQty": "8.00000000",
              "status": "CANCELED",
              "timeInForce": "GTC",
              "type": "LIMIT",
              "side": "SELL"
            }
        """
        result = self.client.cancel_order(symbol=market, orderId=order_id)
        return (result['status'] == 'CANCELED', result)

    def update_stop_loss(self, position, stop_loss_price):
        if config.is_test:
            return {
                "success": True,
                "timestamp": config.historical_timestamp,
                "order_id": 1
            }

        else:
            self.cancel_order(market=position.market,
                              order_id=position.sell_order_id)
            return self.set_stop_loss(market=position.market,
                                      quantity=position.sell_quantity,
                                      stop_loss_price=stop_loss_price)

    def get_sell_order(self, position):
        try:
            if not position.sell_order_id:
                # Can't look for nothing
                raise Exception(f"Position {position} has no sell_order_id")

            response = self.client.get_order(symbol=position.market,
                                             orderId=position.sell_order_id)
            """
                {
                    'symbol': 'BNBBTC',
                    'orderId': 58158667,
                    'clientOrderId': 'jFTEtmTTUTqspMi6Oq08R9',
                    'price': '0.00000000',
                    'origQty': '1.55000000',
                    'executedQty': '1.55000000',
                    'status': 'FILLED',
                    'timeInForce': 'GTC',
                    'type': 'MARKET',
                    'side': 'BUY',
                    'stopPrice': '0.00000000',
                    'icebergQty': '0.00000000',
                    'time': 1529546953007,
                    'isWorking': True
                }
            """
        except Exception as e:
            print(f"GET SELL ORDER STATUS:" + f" | symbol: {position.market}" +
                  f" | orderId: {position.sell_order_id}" + f"\n{e}")
            raise e

        return response

    def get_sell_order_status(self, position):
        response = self.get_sell_order(position)

        if response["status"] == 'FILLED':
            # print(f"ORDER STATUS: FILLED: {response}")

            price = Decimal(response["stopPrice"]) if Decimal(
                response["stopPrice"]) != Decimal('0.0') else Decimal(
                    response["price"])
            quantity = Decimal(response["executedQty"])

            # TODO: How to get the 'commission' fees?

            # Calculating unofficial fees for now
            # fees = self._calculate_fees(price, quantity)

            # Sell order is done!
            return {
                "status": response["status"],
                "sell_price": price,
                "quantity": quantity,
                # "fees": fees,
                "timestamp": response["time"] / 1000,
            }
        else:
            return {"status": response["status"]}

    def update_order_statuses(self, market, positions):
        """
            Batch update open positions by market.
        """
        if positions.count() == 0:
            return []

        market_params = MarketParams.get_market(
            market, exchange=MarketParams.EXCHANGE__BINANCE)
        first_open_position = next(p for p in positions
                                   if p.sell_order_id is not None)

        print(
            f"Retrieving order statuses for {market}, starting at orderId {first_open_position.sell_order_id}"
        )
        orders = self.client.get_all_orders(
            symbol=first_open_position.market,
            orderId=first_open_position.sell_order_id,
            limit=1000)
        """
            [{
                "symbol": "ONTBTC",
                "orderId": 95353124,
                "clientOrderId": "O3Ji1FvNiYt6rr9NvGEtC4",
                "price": "0.00020880",
                "origQty": "4.91000000",
                "executedQty": "0.00000000",
                "cummulativeQuoteQty": "0.00000000",
                "status": "NEW",
                "timeInForce": "GTC",
                "type": "LIMIT",
                "side": "SELL",
                "stopPrice": "0.00000000",
                "icebergQty": "0.00000000",
                "time": 1556814586405,
                "updateTime": 1556814586405,
                "isWorking": true
            }, {...}, {...}]
        """
        print(
            f"{market} orders retrieved: {len(orders)} | positions: {positions.count()}"
        )
        positions_sold = []
        orders_processed = []
        for position in positions:
            if position.sell_order_id is None:
                continue

            result = next(
                (r for r in orders if r['orderId'] == position.sell_order_id),
                None)

            if not result:
                cprint(
                    f"orderId {position.sell_order_id} not found for position {position.id}: {market}",
                    "red")

                # Assume the order can be found individually and proceed
                result = self.get_sell_order(position)
                print(result['status'])

            orders_processed.append(position.sell_order_id)

            if result['status'] == 'NEW':
                # Nothing to do. Still waiting for LIMIT SELL.
                continue

            elif result['status'] == 'FILLED':
                position.sell_price = Decimal(result['price']).quantize(
                    market_params.price_tick_size)
                position.sell_quantity = Decimal(
                    result['executedQty']).quantize(
                        market_params.lot_step_size)
                position.sell_timestamp = result['updateTime'] / 1000
                position.scalped_quantity = (position.buy_quantity -
                                             position.sell_quantity).quantize(
                                                 market_params.lot_step_size)
                position.save()

                positions_sold.append(position)

            elif result['status'] == 'CANCELED':
                # Somehow the management of this order's cancellation didn't make it into the DB.
                print(
                    f"CANCELED order not properly updated in DB: {market} {position.id}"
                )
                position.sell_order_id = None
                position.sell_price = None
                position.sell_quantity = None
                position.save()

            else:
                raise Exception(
                    f"Unimplemented order status: '{result['status']}'\n\n{json.dumps(result, sort_keys=True, indent=4)}"
                )

        # Cancel any 'NEW' orders that aren't connected to a position
        # for order in orders:
        #     if order['status'] == 'NEW' and order['orderId'] not in orders_processed:
        #         # Cancel this order!
        #         cprint(f"CANCELING {market} order {order['orderId']}", "red")
        #         result = self.cancel_order(market, order['orderId'])
        #         print(result)

        return positions_sold

    def get_buy_order_status(self, position):
        if config.is_test:
            # Have to simulate if the buy order would have filled at the current historical_timestamp
            candle = Candle.get_historical_candle(position.market,
                                                  config.interval,
                                                  config.historical_timestamp)

            if candle and position.purchase_price >= candle.low:
                return {
                    "status":
                    "FILLED",
                    "fees":
                    (position.buy_quantity * position.purchase_price *
                     Decimal('0.0005')).quantize(Decimal('0.00000001'),
                                                 rounding=decimal.ROUND_DOWN),
                    "timestamp":
                    candle.timestamp
                }
            else:
                return {"status": "OPEN", "timestamp": candle.timestamp}

        else:
            """
                {
                    'symbol': 'BNBBTC',
                    'orderId': 58158667,
                    'clientOrderId': 'jFTEtmTTUTqspMi6Oq08R9',
                    'price': '0.00000000',
                    'origQty': '1.55000000',
                    'executedQty': '1.55000000',
                    'status': 'FILLED',
                    'timeInForce': 'GTC',
                    'type': 'MARKET',
                    'side': 'BUY',
                    'stopPrice': '0.00000000',
                    'icebergQty': '0.00000000',
                    'time': 1529546953007,
                    'isWorking': True
                }
            """
            try:
                if not position.buy_order_id:
                    # Can't look for nothing
                    raise Exception(f"Position {position} has no buy_order_id")

                response = self.client.get_order(symbol=position.market,
                                                 orderId=position.buy_order_id)

            except Exception as e:
                print(f"GET BUY ORDER STATUS:" +
                      f" | symbol: {position.market}" +
                      f" | orderId: {position.buy_order_id}" + f"\n{e}")
                raise e

            if response["status"] == 'FILLED':
                print(f"ORDER STATUS: FILLED: {response}")

                # TODO: How to get the 'commission' fees?

                # Calculate unofficial fees for now
                fees = self._calculate_fees(position.purchase_price,
                                            position.buy_quantity)

                return {
                    "status": response["status"],
                    "fees": fees,
                    "timestamp": response["time"] / 1000,
                }
            else:
                return {"status": response["status"]}

    def _calculate_fees(self, price, quantity):
        fees = price * quantity / self.get_current_price(
            f"{self.exchange_token}BTC") * Decimal('0.0005')
        return fees.quantize(Decimal('0.00000001'),
                             rounding=decimal.ROUND_DOWN)

    def get_current_price(self, market):
        return Decimal(self.client.get_ticker(symbol=market)["lastPrice"])

    def get_current_ask(self, market):
        return Decimal(
            self.client.get_order_book(symbol=market).get('asks')[0][0])

    def get_market_depth(self, market):
        return self.client.get_order_book(symbol=market)

    def get_moving_average(self, market, interval, since):
        """
              [
                1499040000000,      // Open time
                "0.01634790",       // Open
                "0.80000000",       // High
                "0.01575800",       // Low
                "0.01577100",       // Close
                "148976.11427815",  // Volume
                1499644799999,      // Close time
                "2434.19055334",    // Quote asset volume
                308,                // Number of trades
                "1756.87402397",    // Taker buy base asset volume
                "28.46694368",      // Taker buy quote asset volume
                "17928899.62484339" // Ignore
              ]
        """
        self.candles = self.client.get_historical_klines(
            market, self.intervals[interval], since)
        ma = Decimal('0.0')
        for candle in self.candles:
            ma += (Decimal(candle[4]) + Decimal(candle[1])) / Decimal('2.0')

        return ma / Decimal(len(self.candles))
Beispiel #29
0
class Binance:
    client: Client = None
    __symbols: List[str] = None
    user: User = None

    def __init__(self, user: User):
        self.user = user
        self.client = Client(user.api_key, user.api_secret)

    def records(self) -> Generator[Tuple[Record, bool], None, None]:
        for symbol in self.symbols():
            for r in self.get_orders(symbol):
                yield r

    def symbols(self) -> Generator[str, None, None]:
        if self.__symbols is not None:
            for symbol in self.__symbols:
                yield symbol
            return
        symbols = []
        for v in all_symbols(self.assets()):
            if self.client.get_symbol_info(v.replace('/', '')) is not None:
                symbols.append(v)
                yield v
        self.__symbols = symbols

    def assets(self) -> List[str]:
        return [v['asset'] for v in self.client.get_account()['balances'] \
            if float(v['free']) + float(v['locked']) != 0]

    def get_orders(self, symbol: str) -> List[Tuple[Record, bool]]:
        data = self.client.get_all_orders(symbol=symbol.replace('/', ''))
        return [
            self.create_record(v, symbol) for v in data
            if v['status'] == 'FILLED'
        ]

    def create_record(self, table: Dict[str, str], symbol: str) -> Record:
        updates = {
            'is_sell':
            table['side'] == 'SELL',
            'symbol':
            symbol,
            'executed_qty':
            float(table['executedQty']),
            'cummulative_quote_qty':
            float(table['cummulativeQuoteQty']),
            'user':
            self.user,
            'time':
            datetime.fromtimestamp(int(table['time']) / 1000, tz=timezone.utc),
        }
        return Record.objects.get_or_create(
            id=int(table['orderId']),
            defaults=updates,
        )

    def price(self, symbol: str) -> float:
        print(symbol)
        try:
            data = self.client.get_avg_price(symbol=symbol + 'USDT')
            return float(data['price'])
        except:
            return 1
Beispiel #30
0
bm = BinanceSocketManager(client)
# start any sockets here, i.e a trade socket

#conn_key = bm.start_depth_socket('BNBBTC', process_message, depth=BinanceSocketManager.WEBSOCKET_DEPTH_5)
conn_key = bm.start_multiplex_socket(['bnbbtc@depth5','xrpbnb@depth5'], process_message)
# then start the socket manager
idx = conn_key.find('=')
keys = conn_key[idx+1:].split('/')
print keys
bm.start()
#bm.stop_socket('sds')#close with conn_key
#bm.close()#close all

'''
bnb_balance = client.get_asset_balance(asset='BNB')
print bnb_balance
if bnb_balance:
    bal = float(bnb_balance['free'])
    if bal > 1:
        #if first of pair is BNB then invert SIDE (ie from buy to sell)
        order = client.create_order(symbol='BNBBTC',
                                    side=SIDE_SELL,
                                    type=ORDER_TYPE_LIMIT,
                                    timeInForce=TIME_IN_FORCE_GTC,
                                    quantity=1,
                                    price='0.00377')
        print order

orders = client.get_all_orders(symbol='BNBBTC')
pprint.pprint(orders)