def getBalances(self): bf = BtfxWss(key=self.key, secret=self.secret) bf.start() while not bf.conn.connected.is_set(): time.sleep(1) bf.authenticate() time.sleep(1) resp = bf.wallets timeout = time.time() + 10 while resp.qsize == 0 or time.time() <= timeout: time.sleep(1) bf.stop() l = list() while resp.qsize() > 0: l.append(resp.get()) logging.debug(l) #logging.info(l[0][0][1]) balance = dict() if len(l) == 0: return balance for entry in l[0][0][1]: #[['funding', 'IOT', 0.00471435, 0, None], ['exchange', 'ETH', 0, 0, None], ['exchange', 'IOT', 408.54209381, 0, None], ['exchange', 'BTC', 0, 0, None]] cur = entry[1] value = entry[2] if cur not in balance: balance[cur] = 0.0 balance[cur] += value return balance
class Trader(_Account): """ Class interface for trading on the Bitfinex Exchange :param key: str: Bitfinex api-key :param secret: str: Bitfinex api-secret """ _sleep_time = 0.01 _min_order_value = 35. _max_order_history = 100 _trade_types = {'market', 'limit'} _sources = ('Orders', 'Order New', 'Order Update', 'Order Cancel', 'Wallets') def __init__(self, key, secret): super(Trader, self).__init__() self.symbols = [] self.symbols_gen = get_symbols_as_updated() self.wss = BtfxWss(key=key, secret=secret, log_level='CRITICAL') self._disconnect_event = Event() self._receiver = None def cancel(self, _id): """ Cancel an order :param _id: int: order id :return: None """ self.wss.cancel_order(multi=False, id=_id) def cancel_all(self, older_than=0): """ Cancel all orders older than a certain time :param older_than: int/float: age of order that should be cancelled (in seconds) :return: None """ now = time.time() for _id, order in self._orders.copy().items(): if now - order['timestamp'] > older_than: self.cancel(_id) def connect(self): """Open a connection to a Bitfinex websocket""" self.wss.start() while not self.wss.conn.connected.is_set(): time.sleep(1e-4) self.wss.authenticate() # This thread will wait for 99.999% of its life subscriber_thread = Thread(target=self._subscribe) subscriber_thread.setDaemon(True) subscriber_thread.start() # This thread should be working and is therefore joined self._receiver = Thread(target=self._receive) self._receiver.start() def close(self): """Close the connection to the Bitfinex websocket""" self._disconnect_event.set() for symbol in self.symbols: self.wss.unsubscribe_from_ticker(symbol) self.wss.stop() self._receiver.join() def order(self, symbol, price, *, dollar_amount=None, ratio=None, value_ratio=None, trade_type='limit', pad_price=None, return_id=True): """ Make an exchange order :param symbol: str: ticker symbol to order (e.g. 'BTCUSD', 'ETHUSD'...) :param price: float: Price at which to submit order You can also pass "market" as an argument for price to order at current market value e.g. Trader.order('BTCUSD', 'market', dollar_amount=5) :param dollar_amount: float: Dollar equivalent value of trade amount (negative for selling) e.g. ordering 10 BTCUSD at $5 per coin -> Trader.order('BTCUSD', 5, dollar_amount=50) :param ratio: float: Ratio of available balance for requested symbol (negative for sell) e.g. With $1000 USD in wallet, ordering 100 BTCUSD at $5 per coin -> Trader.order('BTCUSD', 5, ratio=0.5) :param value_ratio: float: Ratio of Trader.value (negative for selling) e.g. With $500 in USD and $500 in BTCUSD (at $5) in wallet, ordering 100 BTCUSD at $5 per coin -> Trader.order('BTCUSD', 5, value_ratio=0.5) :param trade_type: str: (optional) Bitfinex api trade type - one of {'market', 'limit'} see https://www.bitfinex.com/features for details :param pad_price: float: (optional) Ratio based price padding - used to undercut or overshoot price If buying then pad_price * price is added to submitted price If selling then pad_price * price is subtracted from price :param return_id: bool: (optional) If true, Trader.order blocks until order_id is returned from Bitfinex, otherwise returns immediately :return: int: If return_id is True, then order id is returned, otherwise None :raises: AssertionError: If values passed are non-consistent """ assert dollar_amount or ratio or value_ratio, \ 'Must provide either `dollar_amount`, `ratio` or `value_ratio`' assert sum(bool(i) for i in [dollar_amount, ratio, value_ratio]) == 1,\ 'Must provide only 1 of `dollar_amount`, `ratio` or `value_ratio`' assert trade_type.lower() in self._trade_types, \ 'Unknown trade type, try one of these: %s' % str(self._trade_types) symbol_lower = symbol.lower().replace('usd', '') symbol = symbol.upper().split('USD')[0] + 'USD' buying = (dollar_amount or ratio or value_ratio) > 0 if price == 'market' or trade_type == 'market': trade_type = 'market' price = self._prices[symbol] if pad_price: delta = price * pad_price price += max(delta, 0.01) if buying else min(-delta, -0.01) assert price >= 0.01, 'Price cannot be less than $0.01' if buying: max_amount = self.available_balances['usd'] / price else: max_amount = self.available_balances[symbol_lower] if dollar_amount: amount = dollar_amount / price elif ratio: amount = max_amount * ratio else: amount = min(max(-max_amount, self.value * value_ratio / price), max_amount) amount, max_amount = round(amount, 8), round(max_amount, 8) assertion_msg = 'Trade value (${:.2f}) is %s available trade value ' \ '($%.2f)'.format(abs(amount * price)) assert abs(amount) >= self._min_order_value / price, \ assertion_msg % ('below minimum', self._min_order_value) assert abs(amount) <= max_amount, \ assertion_msg % ('above maximum', max_amount * price) current_order_ids = set(self._orders.keys()) if len(self._executed_orders) == 0: last_executed_id = None else: last_executed_id = self._executed_orders[-1][0] self.wss.new_order( cid=int(time.time()), type="EXCHANGE %s" % trade_type.upper(), symbol="t%s" % symbol, amount="%.8f" % amount, price="%.2f" % price, ) while return_id: for _id in self._orders.copy().keys(): # new order arrives in _orders if _id not in current_order_ids: return _id else: # new order is executed immediately if len(self._executed_orders) > 0 \ and self._executed_orders[-1][0] != last_executed_id: return self._executed_orders[-1][0] time.sleep(self._sleep_time) def subscribe(self, symbol): """ Subscribe to a symbol for price watching :param symbol: str: symbol to subscribe to (e.g. 'BTCUSD', 'ETHUSD'...) """ self.symbols.append(symbol) self.wss.subscribe_to_ticker(symbol) def wait_execution(self, _id, seconds=1e9): """ Waits for an order to execute :param _id: int: id of order to wait for :param seconds: int/float: time to wait before raising error :return: dict: order in json format :raises: TimeoutError (if order is not executed in given time) """ start_time = time.time() while time.time() - start_time < seconds: try: ids, trades = tuple(zip(*self._executed_orders)) return trades[ids.index(_id)] except ValueError: time.sleep(self._sleep_time) raise TimeoutError('Waiting for execution of order ' '%d timed out after %d seconds' % (_id, seconds)) def _receive(self): while not self._disconnect_event.is_set(): for source in self._sources: with suppress(Empty): q = self.wss.queue_processor.account[source] cmd, data = q.get_nowait()[0] self._update(cmd, data) for symbol in self.symbols: with suppress(Empty): q = self.wss.queue_processor.tickers[('ticker', symbol)] data = q.get_nowait()[0] self._update('t' + symbol, data) def _subscribe(self): for symbol in self.symbols_gen: self.subscribe(symbol)
current_dict[key] = definition break return current_dict secStr = btfAccount() loginName = str(secStr['APIK']) passName = str(secStr['APIS']) wss = BtfxWss(key=loginName, secret=passName) wss.start() while not wss.conn.connected.is_set(): time.sleep(1) wss.authenticate() #Success ############################################################################## # Subscribe to some channels wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_order_book('BTCUSD') wss.subscribe_to_trades('BTCUSD') time.sleep(5) #Accessing data stored in BtfxWss: ticker_q = wss.tickers('BTCUSD') while not ticker_q.empty(): print(ticker_q.get()[0][0][0]) break ##################################################################################
class RateMonitor(object): def __init__(self, symbols): self.DEBUG = True self._rest_client = bitfinex_v1_rest.FullApi() self._wss = None self._symbols = symbols self._funding = {} self._credits = {} self._offers = {} self._wss = BtfxWss(key=config.BFX_API_KEY, secret=config.BFX_API_SECRET) self._wss.start() def reset(self): self._funding = {} self._credits = {} self._offers = {} def connect(self): log("Server connected") self._wss.authenticate() for symbol in self._symbols: self._wss.subscribe_to_trades(symbol) self._funding['latest_ts'] = 0 self._funding['latest_rate'] = 0.0 def run(self): while True: self.check_system() self.check_account_info() self.check_trades() time.sleep(0.5) def check_system(self): try: server_q = self._wss.opened while not server_q.empty(): server_q.get() self.reset() self.connect() except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def check_account_info(self): try: wallets_q = self._wss.wallets while not wallets_q.empty(): self.received_wallets(wallets_q.get()) wallet_update_q = self._wss.wallet_update while not wallet_update_q.empty(): self.received_wallet_update(wallet_update_q.get()) credits_q = self._wss.credits while not credits_q.empty(): self.received_credits(credits_q.get()) offer_new_q = self._wss.offer_new while not offer_new_q.empty(): self.received_offer_new(offer_new_q.get()) offer_cancel_q = self._wss.offer_cancel while not offer_cancel_q.empty(): self.received_offer_cancel(offer_cancel_q.get()) credit_close_q = self._wss.credit_close while not credit_close_q.empty(): self.received_credit_close(credit_close_q.get()) credit_update_q = self._wss.credit_update while not credit_update_q.empty(): self.received_credit_update(credit_update_q.get()) q = self._wss.offer_update while not q.empty(): print(q.get()) except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def check_trades(self): for symbol in self._symbols: try: trades_q = self._wss.trades(symbol) while not trades_q.empty(): self.received_trades(symbol, trades_q.get()) except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def received_wallets(self, message): # pylint: disable=W0612 data, ts = message for wallet in data[1]: self.process_wallet(wallet) def received_wallet_update(self, message): # pylint: disable=W0612 data, ts = message self.process_wallet(data[1]) def received_credits(self, message): # pylint: disable=W0612 data, ts = message self._funding['lent'] = 0 for credit in data[1]: self._funding['lent'] += self.process_credit(credit) log("Funding usd lent: %f" % self._funding['lent']) def received_offer_new(self, message): # pylint: disable=W0612 data, ts = message self.process_offer(data[1]) def received_offer_cancel(self, message): # pylint: disable=W0612 data, ts = message self.process_offer(data[1]) def received_credit_close(self, message): # pylint: disable=W0612 data, ts = message self.process_credit(data[1]) def received_credit_update(self, message): # pylint: disable=W0612 data, ts = message self.process_credit(data[1]) def received_trades(self, symbol, message): # pylint: disable=W0612 data, ts = message if isinstance(data[0], list): for transaction in data[0]: self.process_public_trade(symbol, transaction) elif data[0] == 'fte': self.process_public_trade(symbol, data[1]) self.lend_strategy() def process_wallet(self, data): if self.DEBUG: print(data) wallet = bitfinex_v2_rest.Wallet(data) if wallet.wallet_type == 'funding' and wallet.currency == 'USD': self._funding['total'] = wallet.balance log("Funding usd: %f" % self._funding['total']) def process_credit(self, data): if self.DEBUG: print(data) credit = bitfinex_v2_rest.Credit(data) if credit.symbol == 'fUSD': if credit.status == 'ACTIVE': self._credits[credit.id] = credit.amount return credit.amount elif credit.status.startswith('CLOSED'): del self._credits[credit.id] self._funding['lent'] -= credit.amount log('Close a credit, amount: %f' % credit.amount) self.lend_strategy() return 0 def process_offer(self, data): if self.DEBUG: print(data) offer = bitfinex_v2_rest.FundingOffer(data) if offer.symbol == 'fUSD': if offer.status == 'ACTIVE': if offer.id not in self._offers: self._offers[offer.id] = offer.amount_orig self._funding['lent'] += offer.amount_orig log('Create an offer, amount: %f' % offer.amount_orig) elif offer.status == 'CANCEL': self._funding['lent'] -= offer.amount log('Cancel an offer, amount: %f' % offer.amount) del self._offers[offer.id] elif offer.status.startswith('EXECUTED'): if offer.id not in self._offers: self._funding['lent'] += offer.amount_orig log('Create an offer, amount: %f' % offer.amount_orig) else: del self._offers[offer.id] def process_public_trade(self, symbol, data): trade = bitfinex_v2_rest.Trade(data) log("%s: Timestamp: %s, Rate: %f, Period: %d, Amount: %f" % (symbol, time.strftime("%H:%M:%S", time.localtime(trade.time)), trade.rate * 100, trade.period, abs(trade.amount))) if trade.time > self._funding['latest_ts']: self._funding['latest_ts'] = trade.time self._funding['latest_rate'] = trade.rate def lend_strategy(self): if 'total' in self._funding and 'lent' in self._funding: available = self._funding['total'] - self._funding['lent'] else: return if 'available' not in self._funding or (available != self._funding['available']): log('total: %f, lent: %f, available: %f' % (self._funding['total'], self._funding['lent'], available)) self._funding['available'] = available # Re-write the strategy by yourself if available > 50: # rate 0 means FRR self.new_offer('USD', available - Decimal(0.000001), 0, 2) def new_offer(self, currency, amount, rate, period): """Create an new offer :param rate: Rate per day """ try: result = self._rest_client.new_offer(currency, amount, rate, period) except BitfinexClientError as e: log(e.value) raise log('Create an new %s offer with amount: %f, rate: %f, ' % (currency, amount, rate) + 'period: %d' % period) self._offers[result['offer_id']] = amount self._funding['lent'] += amount return result['offer_id'] def cancel_offer(self, offer_id): """Cancel an offer""" try: self._rest_client.cancel_offer(offer_id) except BitfinexClientError as e: log(e.value) raise log('Cancel an offer with id: %d' % offer_id)
def worker_function(quit_flag, launch_flag, globalz): counter = 0 established = False wss = None qq = None first = True order = False OCHLVlast = 0 OCHLVcur = 0 while not quit_flag.value: if launch_flag.value == 5: if established == False: wss = BtfxWss(key=API_KEY, secret=API_SECRET) wss.start() while not wss.conn.connected.is_set(): time.sleep(1) established = True wss.authenticate() # Subscribe to some channels wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_candles('BTCUSD', '15m') wss.subscribe_to_candles('BTCUSD', '1m') wss.subscribe_to_order_book('BTCUSD') # Do something else t = time.time() while time.time() - t < 2: pass # Accessing data stored in BtfxWss: ticker_q = wss.candles( 'BTCUSD', '1m') # returns a Queue object for the pair. wallet = wss.wallets while not ticker_q.empty(): qq = np.asarray(ticker_q.get()) #globalz[0] = int(np.asarray(qq)[1]) if type(qq[0][0][0]) == list: first = True if first: globalz[0] = int(((qq)[0][0][0][0]) / 1000) #globalz[1] = logging.debug(((qq)[0][0][0][0]) / 1000) #loggin.debug() #logging.debug(type((qq)[0][0][0][0])) #logging.debug(type((qq)[0][0][0])) #logging.debug(type((qq)[0][0])) #logging.debug(type((qq)[0])) #logging.debug(type((qq))) with open('my.ts', 'w') as file: for i in range(len(qq[0][0])): stri = (str(qq[0][0][i])) file.write((stri)) file.write("\n") first = False else: globalz[30] = int(((qq)[1])) globalz[0] = int(((qq)[0][0][0]) / 1000) globalz[5] = int(((qq)[0][0][5]) * 1000) globalz[6] = int(((qq)[0][0][5]) * 1000) #globalz[0] = for i in range(1, 5): globalz[i] = int((np.asarray(qq)[0][0][i])) #logging.debug(counter) logging.debug((np.asarray(qq)[0][0])) #logging.debug((np.asarray(qq)[0][0][1])) if wallet.empty() == False: logging.debug(wallet.get()) #ticker_q = wss.candles('BTCUSD') # returns a Queue object for the pair. counter += 1 logging.debug("Tick # %s" % counter) #var.set() #time.sleep(0.01) elif launch_flag.value == -1: if established == True: logging.info("Stopping kekush at # %s" % counter) time.sleep(0.01) wss.unsubscribe_from_ticker('BTCUSD') wss.unsubscribe_from_candles('BTCUSD') wss.unsubscribe_from_order_book('BTCUSD') # Shutting down the client: wss.stop() wss = None counter = 0 established = False first = True elif launch_flag.value == 6: if order == False: logging.info("Ordering some shit at # %s" % counter) order = { "cid": 373617, #change to the API_Key Number "type": "LIMIT", "symbol": "tEOSUSD", "amount": "2", "price": "14", "hidden": 0, "postonly": 1 } wss.new_order(**order) launch_flag.value = 7 order = True time.sleep(3) logging.info(wss.orders.get())
wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) # Subscribe to some channels wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_order_book('BTCUSD') # Do something else t = time.time() while time.time() - t < 10: pass # Accessing data stored in BtfxWss: ticker_q = wss.tickers('BTCUSD') # returns a Queue object for the pair. wss.authenticate() wss.notifications wss.authenticate() while not ticker_q.empty(): print(ticker_q.get()) # Unsubscribing from channels: wss.unsubscribe_from_ticker('BTCUSD') wss.unsubscribe_from_order_book('BTCUSD') # Shutting down the client: wss.stop()
class WebSocketApi(object): """ Wrapper to use BtfxWss. """ def __init__(self, symbols=None, callbacks=None): """ Args: symbols: A list used to subscribe tickers. callbacks: A list of functions to handle events: 'reset', 'process_wallet', 'process_order', 'process_tick', 'process_notification' """ required_callbacks = [ 'reset', 'process_wallet', 'process_order', 'process_tick', 'process_notification' ] if not symbols or not callbacks: log(LOG_ERROR, 'Require parameters symbols and callbacks') return for callback in required_callbacks: if callback not in callbacks: log(LOG_ERROR, 'Require %s callback function' % callback) return self._tick_symbols = symbols self._callbacks = callbacks self._received_order_snapshot = False self._received_wallet_snapshot = False self._wss = BtfxWss( key=config.BFX_API_KEY, secret=config.BFX_API_SECRET) self._wss.start() def __connect(self): """ Reset data and subscribe tick data after connect to server. """ log(LOG_INFO, "Server connected") self._received_order_snapshot = False self._received_wallet_snapshot = False self._wss.authenticate() for pair in self._tick_symbols: symbol = 't' + pair self._wss.subscribe_to_ticker(symbol) def __check_system(self): """ Check the connection is established or not. """ try: server_q = self._wss.opened while not server_q.empty(): server_q.get() self._callbacks['reset']() self.__connect() except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def __check_account_info(self): """ Check account information. """ try: wallets_q = self._wss.wallets while not wallets_q.empty(): self.__received_wallets(wallets_q.get()[0][1]) wallet_update_q = self._wss.wallet_update while not wallet_update_q.empty(): self.__received_wallet_update( wallet_update_q.get()[0][1]) orders_q = self._wss.orders while not orders_q.empty(): self.__received_orders(orders_q.get()[0][1]) order_new_q = self._wss.order_new while not order_new_q.empty(): self.__received_order(order_new_q.get()[0][1]) order_cancel_q = self._wss.order_cancel while not order_cancel_q.empty(): self.__received_order(order_cancel_q.get()[0][1]) notification_q = self._wss.notifications while not notification_q.empty(): self.__received_notification(notification_q.get()[0][1]) except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def __check_tickers(self): """ Check tick data. """ for symbol in self._tick_symbols: try: trades_q = self._wss.tickers(symbol) while not trades_q.empty(): self.__received_tickers(symbol, trades_q.get()[0]) except KeyError: # KeyError means Btfxwss doesn't get related information # yet. It's fine to pass and check in the next time. pass def __check_unused_info(self): """ Websocket may have many events which are not used. Just pop it and ignore it. Otherwise, the queue may use too many memories. """ def pop_queue(queue): """ pop unused queue """ while not queue.empty(): queue.get() try: queues = [ self._wss.credits, self._wss.offer_new, self._wss.offer_cancel, self._wss.credit_new, self._wss.credit_close, self._wss.credit_update, self._wss.positions, self._wss.offer_update, self._wss.order_update, self._wss.position_update, self._wss.position_close, self._wss.loan_new, self._wss.loan_close, self._wss.loan_update, self._wss.unknown] for queue in queues: pop_queue(queue) except KeyError: # KeyError means Btfxwss doesn't get related information yet. # It's fine to pass and check in the next time. pass def __received_wallets(self, wallets): """ Handle wallet snapshot. Args: wallets: balance of all currencies """ for wallet in wallets: self._callbacks['process_wallet'](bitfinex_v2_rest.Wallet(wallet)) self._received_wallet_snapshot = True def __received_wallet_update(self, wallet): """ Handle wallet update. Args: wallets: balance of one currency """ self._callbacks['process_wallet'](bitfinex_v2_rest.Wallet(wallet)) def __received_orders(self, orders): """ Handle order snapshot. Args: orders: current orders snapshot """ for order in orders: self._callbacks['process_order'](bitfinex_v2_rest.Order(order)) self._received_order_snapshot = True def __received_order(self, order): """ Handle one order Args: order: order status """ self._callbacks['process_order'](bitfinex_v2_rest.Order(order)) def __received_tickers(self, pair, tickers): """ Handle ticks Args: pair: ex BTCUSD tickers: tickers of the pair """ if isinstance(tickers, list): for tick in tickers: self._callbacks['process_tick']( bitfinex_v2_rest.TradingTicker([pair] + tick)) def __received_notification(self, message): """ Handle notification Args: message: notification from web socket """ self._callbacks['process_notification']( bitfinex_v2_rest.Notifications(message)) def new_order(self, pair, price, amount): """ Create an new order. Args: pair: ex BTCUSD. price: 0 means the market order. amount: Positive number means buy order. Negative number means sell order. """ symbol = 't' + pair cid = int(round(time.time() * 1000)) if price > 0: order = { 'cid': cid, 'type': "EXCHANGE LIMIT", 'symbol': symbol, 'amount': str(amount), 'price': str(price), 'hidden': 0 } else: order = { 'cid': cid, 'type': "EXCHANGE MARKET", 'symbol': symbol, 'amount': str(amount), 'hidden': 0 } self._wss.new_order(**order) def cancel_order(self, order_id): """ Cancel an order. Args: order_id: The id of the order. """ value = {'id': order_id} self._wss.cancel_order(False, **value) def check_events(self): """ Check all events from web socket """ self.__check_system() self.__check_account_info() self.__check_tickers() self.__check_unused_info() def is_received_order_snapshot(self): """ Return True if recevied order snapshot """ return self._received_order_snapshot def is_received_wallet_snapshot(self): """ Return True if recevied wallet snapshot """ return self._received_wallet_snapshot