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 __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 __init__(self): self.bids = dict() self.asks = dict() self.bid_depth = 0 self.bid_ma_slow = 0 self.bid_ma_fast = 0 self.ask_depth = 0 self.ask_ma_slow = 0 self.ask_ma_fast = 0 self.wss = BtfxWss()
class Connection: # def __init__(self, key=None, secret=None, log_level=None, **wss_kwargs): def __init__(self, symbol): self.wss = BtfxWss(key=None, secret=None, addr='wss://api.bitfinex.com/ws/2') self.wss.start() self.symbol = symbol while not self.wss.conn.connected.is_set(): time.sleep(1) self.wss.subscribe_to_ticker(symbol) self.wss.subscribe_to_order_book(symbol) def stop(self): # Unsubscribing from channels: # self.wss.unsubscribe_from_ticker('BTCUSD') # self.wss.unsubscribe_from_order_book('BTCUSD') # Shutting down the client: self.wss.stop() def get_bitfinex_price(self): ticker_q = self.wss.tickers(self.symbol) # returns a Queue object for the pair. return ticker_q
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 __init__(self, symbol): self.wss = BtfxWss(key=None, secret=None, addr='wss://api.bitfinex.com/ws/2') self.wss.start() self.symbol = symbol while not self.wss.conn.connected.is_set(): time.sleep(1) self.wss.subscribe_to_ticker(symbol) self.wss.subscribe_to_order_book(symbol)
def test_is_connected_decorator_works_as_expected(self): wss = BtfxWss(log_level=logging.CRITICAL) time.sleep(1) wss.start() try: wss.subscribe_to_candles('BTCUSD') except WebSocketConnectionClosedException: self.fail("Decorator did not work!") wss.stop()
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
def get_candle_q(symbol): """ candle_format: ([[1515066900000, 3.1354, 3.1457, 3.1459, 3.1261, 41373.42748331]], 1515066939.756591) ([[candle_time, O, H, L, C]], timestamp) """ wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) valid_candles = [ '1m', '5m', '15m', '30m', '1h', '3h', '6h', '12h', '1D', '7D', '14D', '1M' ] wss.subscribe_to_candles(symbol, '1m') time.sleep(15) candles_q = wss.candles(symbol, '1m') return candles_q
def run(): bq = BigQuery(table="BTCUSD_trade_data", dataset="bitfinex", schema=schema) logger = setup_logger() wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): sleep(1) wss.subscribe_to_trades('BTCUSD') t = time.time() while time.time() - t < 10: pass # access queue object books_q = wss.trades('BTCUSD') while wss.conn.connected.is_set(): rows_to_insert = books_q.get() rows = [] if depth(rows_to_insert[0]) == 3: continue if rows_to_insert[0][0] == 'te': continue side = "Sell" if rows_to_insert[0][1][2] < 0 else "Buy" r = { "ts": rows_to_insert[1], "price": rows_to_insert[0][1][3], "id": rows_to_insert[0][1][1], "side": side, "size": abs(rows_to_insert[0][1][2]) } rows.append(r) errors = bq.client.insert_rows(bq.tbl, rows) if errors != []: print(errors)
def store_data(symbol): file_dir = TRADE_FILE_LOCATION.format(symbol=symbol) if not os.path.exists(file_dir): os.makedirs(file_dir) wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) wss.subscribe_to_trades(symbol) time.sleep(15) trade_q = wss.trades(symbol) while 1: if trade_q.empty(): time.sleep(1) else: trade = trade_q.get() with open( file_dir + datetime.datetime.now().strftime("%Y%m%d") + '.txt', 'a') as outfile: outfile.write(str(trade)) outfile.write('\n') print(trade)
def main(): wss = BtfxWss() wss.start() macd_obj = macd.MACD() rsi_obj = rsi.RSI() long_position = LongPosition() while not wss.conn.connected.is_set(): time.sleep(1) # wss.subscribe_to_ticker('XRPUSD') wss.subscribe_to_trades('XRPUSD') time.sleep(15) # ticker_q = wss.tickers('XRPUSD') # returns a Queue object for the pair. ticker_q = wss.trades('XRPUSD') while 1: if ticker_q.empty(): time.sleep(1) else: ticker = ticker_q.get() print(ticker) # price = ticker[0][-1][6] # timestamp = ticker[1] timestamp = ticker[1] price = ticker[0][-1][-1] if isinstance(price, list): continue macd_obj.update_macd(timestamp, price) # print(macd_obj.macds) rsi_obj.update_rsi(timestamp, price) # print(rsi_obj.rsi) long_position.update_position(macd_obj.macds['present_macd'], macd_obj.macds['present_signal'], rsi_obj.rsi['rsi'], price, timestamp)
'https://api.bitfinex.com/v1/symbols').text.upper().replace( '"', '')[1:-1].split(',') # Setting the BtfxWss Library log = logging.getLogger(__name__) fh = logging.FileHandler('test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) for ticket in tickets: wss.subscribe_to_ticker(ticket) t = time.time() while time.time() - t < 0.5: pass try: ticker = wss.tickers(ticket).get() except KeyError:
# -*- coding: utf-8 -*- """ Created on Tue Sep 26 16:00:36 2017 @author: vince """ from btfxwss import BtfxWss wss = BtfxWss()
def replace_value_with_definition(current_dict, key_to_find, definition): for key in current_dict.keys(): if key == key_to_find: 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():
class BitfinexBookWatcher: def __init__(self): self.bids = dict() self.asks = dict() self.bid_depth = 0 self.bid_ma_slow = 0 self.bid_ma_fast = 0 self.ask_depth = 0 self.ask_ma_slow = 0 self.ask_ma_fast = 0 self.wss = BtfxWss() def start(self): if not self.wss.conn.connected.is_set(): logger.info("Starting Bitfinex websocket client") self.wss.start() while not self.wss.conn.connected.is_set(): time.sleep(1) # for P1 precision usual width of order book is ~100 USD (for BTC/USD price ~6500) # for wider range (about 1500 USD) use P2 precision. But the price will be rounded to tens self.wss.subscribe_to_order_book('BTCUSD', prec="P1", len=100) logger.info("Subscribed to Order Book WSS channel") # waiting for a bit to receive the book snapshot time.sleep(2) # call get_updates regularly to clear the queue!! Otherwise you may get OutOfMemory errors def get_updates(self): book_q = self.wss.books( 'BTCUSD') # returns a Queue object for the pair. # result = [] while not book_q.empty(): get = book_q.get() # print(get) # result.append(get) book_item, tag = get self.fill_the_book(book_item) self.bid_depth = sum(self.bids.values()) self.bid_ma_fast = update_ma(self.bid_depth, self.bid_ma_fast, 5) self.bid_ma_slow = update_ma(self.bid_depth, self.bid_ma_slow, 90) self.ask_depth = sum(self.asks.values()) self.ask_ma_fast = update_ma(self.ask_depth, self.ask_ma_fast, 5) self.ask_ma_slow = update_ma(self.ask_depth, self.ask_ma_slow, 90) # logger.debug("Market depth: bids: {0}, ma5: {1} ma90: {2} | asks: {3}, ma5: {4} ma90: {5}".format( # round(self.bid_depth), # round(self.bid_ma_fast), # round(self.bid_ma_slow), # round(self.ask_depth), # round(self.ask_ma_fast), # round(self.ask_ma_slow) # )) # return result # better call stop() at the end of the program (and on TERM signal) def stop(self): if self.wss.conn.connected.is_set() and self.wss.channel_configs: logger.debug("unsubscribe") self.wss.unsubscribe_from_order_book('BTCUSD') if self.wss.conn.connected.is_set(): logger.debug("stopping the socket") self.wss.stop() logger.debug("stopped.") def fill_the_book(self, input_list): for row in input_list: if isinstance(row[0], list): self.fill_the_book(row) else: price = str(row[0]) count = row[1] amt = row[2] if count != 0: if amt > 0: self.bids[price] = amt else: self.asks[price] = abs(amt) else: if amt > 0: if price in self.bids.keys(): del (self.bids[price]) elif amt < 0: if price in self.asks.keys(): del (self.asks[price])
#!/usr/bin/env python import time import uuid import ujson from btfxwss import BtfxWss from classes.tasks import save_ticker, save_trade from classes.utils import get_time, get_timestamp, get_hour, get_date if __name__ == '__main__': wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) cryptos = [] with open('config.json', 'r') as handler: cryptos = ujson.load(handler) if cryptos: for crypto in cryptos: currency = crypto['symbol'].upper() # Subscribe to some channels wss.subscribe_to_ticker(currency) wss.subscribe_to_trades(currency) time.sleep(1) try: print("Starting...") while True:
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())
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)
from btfxwss import BtfxWss import time # config log = logging.getLogger(__name__) fh = logging.FileHandler('../test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) # 国内设置代理 wss = BtfxWss(http_proxy_host='127.0.0.1', http_proxy_port='1080') # wss = BtfxWss() # 订阅websocket def subscribe(): 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') wss.subscribe_to_candles('BTCUSD', '1h') wss.subscribe_to_candles('BTCUSD', '1D') wss.subscribe_to_trades('BTCUSD') wss.subscribe_to_raw_order_book('BTCUSD')
import sys from btfxwss import BtfxWss log = logging.getLogger(__name__) fh = logging.FileHandler('test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_ticker('ETHUSD') wss.subscribe_to_ticker('EOSUSD') wss.subscribe_to_ticker('ETHBTC') wss.subscribe_to_ticker('EOSBTC') wss.subscribe_to_ticker('EOSETH') while (1): q1 = wss.tickers('BTCUSD') q2 = wss.tickers('ETHBTC')
def __init__(self, **kwargs): self.exchange = 'Bitfinex' self.pair_btc = 'BTCUSD' self.pair_eth = 'ETHUSD' self.pair_etc = 'ETCUSD' self.pair_ltc = 'LTCUSD' self.pair_dsh = 'DSHUSD' self.pair_bch = 'BCHUSD' self.pair_btg = 'BTGUSD' self.pair_eos = 'EOSUSD' self.pair_trx = 'TRXUSD' self.pair_xmr = 'XMRUSD' self.pair_vet = 'VETUSD' self.pair_iot = 'IOTUSD' self.pair_zec = 'ZECUSD' self.pair_neo = 'NEOUSD' self.cnx = mysql.connector.connect(**kwargs) self.cursor = self.cnx.cursor() wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) wss.subscribe_to_trades(self.pair_btc) wss.subscribe_to_trades(self.pair_eth) wss.subscribe_to_trades(self.pair_etc) wss.subscribe_to_trades(self.pair_ltc) wss.subscribe_to_trades(self.pair_dsh) wss.subscribe_to_trades(self.pair_bch) wss.subscribe_to_trades(self.pair_btg) wss.subscribe_to_trades(self.pair_eos) wss.subscribe_to_trades(self.pair_trx) wss.subscribe_to_trades(self.pair_xmr) wss.subscribe_to_trades(self.pair_vet) wss.subscribe_to_trades(self.pair_iot) wss.subscribe_to_trades(self.pair_zec) wss.subscribe_to_trades(self.pair_neo) t = time.time() while time.time() - t < 10: pass self.ticker_btc = wss.trades(self.pair_btc) self.ticker_eth = wss.trades(self.pair_eth) self.ticker_etc = wss.trades(self.pair_etc) self.ticker_ltc = wss.trades(self.pair_ltc) self.ticker_dsh = wss.trades(self.pair_dsh) self.ticker_bch = wss.trades(self.pair_bch) self.ticker_btg = wss.trades(self.pair_btg) self.ticker_eos = wss.trades(self.pair_eos) self.ticker_trx = wss.trades(self.pair_trx) self.ticker_xmr = wss.trades(self.pair_xmr) self.ticker_vet = wss.trades(self.pair_vet) self.ticker_iot = wss.trades(self.pair_iot) self.ticker_zec = wss.trades(self.pair_zec) self.ticker_neo = wss.trades(self.pair_neo)
def test_subscribing_to_data_works(self): wss = BtfxWss(log_level=logging.DEBUG) wss.start() time.sleep(1) wss.subscribe_to_ticker('BTCUSD') wss.subscribe_to_candles('BTCUSD') wss.subscribe_to_order_book('BTCUSD') wss.subscribe_to_raw_order_book('BTCUSD') wss.subscribe_to_trades('BTCUSD') time.sleep(10) try: wss.tickers('BTCUSD').get(block=False) except Empty: self.fail("No ticker data arrived!") try: wss.candles('BTCUSD', '1m').get(block=False) except Empty: self.fail("No candles data arrived!") except KeyError: self.fail("No candles data arrived, key not found! %s" % list(wss.queue_processor.candles.keys())) try: wss.books('BTCUSD').get(block=False) except Empty: self.fail("No book data arrived!") try: wss.raw_books('BTCUSD').get(block=False) except Empty: self.fail("No war book data arrived!") try: wss.trades('BTCUSD').get(block=False) except Empty: self.fail("No trades data arrived!") wss.stop()
class Market(object): """ This is the market of the cryptocurrency given symbol. Data source is Bitfinex Websocket API. """ def __init__(self, symbol='BTCUSD'): self.symbol = symbol self.wss = BtfxWss() self.wss.start() def check_connection(self, pat=60): """ Check connection with Bitfinex API. If consecutively failing to connect, the program will send an alert message :param pat: the maximum patience time before sending an alert notification of disrupted connection. """ init = time.time() # Wait until either connected or exceeding patience while not self.wss.conn.connected.is_set() or time.time() > init + pat: time.sleep(1) # If connection is not set, send a note if self.wss.conn.connected.is_set(): pass else: message(txt_msg='The connection is disrupted.') logger.error('Connection failed.') exit() def initialize_api(self): """ Initialize the API for the crypto market and subscribe to trades and order books. Data is stored as Queues. """ self.check_connection() # Subscribe to some channels self.wss.subscribe_to_trades(self.symbol) self.wss.subscribe_to_order_book(pair=self.symbol, len=100) # Initialize a DataBase object self.db = DataBase(symbol=self.symbol) logger.info('API connection initialized.') def create_database(self): """ This function will build connection with Bitfinex Websocket API and AWS MySQL DB. Then initialize the csv files and sql databases for trades and orderbook. """ # Check connection self.check_connection() # Prepare csv databases for trades and quotes self.db.initialize_trade_csv() self.db.initialize_quote_csv() # Prepare sql database and tables self.db.initialize_sql_db() self.db.initialize_trade_sql() self.db.initialize_quote_sql() # Access data from BtfxWss and return a Queue object for the pair: self.trade_q = self.wss.trades(self.symbol) self.quote_q = self.wss.books(self.symbol) # Take a snapshot of the orderbook quote_snapshot = self.quote_q.get() # Input the snapshot to database self.db.create_order_book(quote_snapshot) self.db.create_quote_csv(quote_snapshot) self.db.create_quote_sql(quote_snapshot) logger.info('Databases created.') def stream_data(self): """ This function access the live data with established Bitfinex API, and keep streaming new trade and quote data. Then update the csv files and sql databases accordingly. """ # Check connection self.check_connection() # Update trade info new_trade = self.trade_q.get() self.db.update_trade_csv(new_trade) self.db.update_trade_sql(new_trade) # Update order book quote_change = self.quote_q.get() self.db.update_quote_csv(quote_change) self.db.update_quote_sql(quote_change) logger.info('New trade and quote updated.')
self.state = "unavailable" time.sleep(self.reconnect_interval) self.log.debug("_connect(): ReConnection..") self.socket = websocket.WebSocketApp( self.url, on_open=self._on_open, on_message=self._on_message, on_error=self._on_error, on_close=self._on_close) # We need to set this flag since closing the socket will # set it to False self.socket.keep_running = True self.socket.run_forever(sslopt=self.sslopt) wss = BtfxWss() wss.conn._connect = types.MethodType(_connect, wss.conn) wss.start() while not wss.conn.connected.is_set(): time.sleep(1) # Subscribe to some channels wss.subscribe_to_ticker(coin_type) # wss.subscribe_to_order_book('BTCUSD') # Do something else t = time.time() while time.time() - t < 10: pass
def __init__(self, symbol='BTCUSD'): self.symbol = symbol self.wss = BtfxWss() self.wss.start()
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)
def main(logger): # Fetch available pairs & timeframes from DB pairs_timeframes = Pair_Timeframe.objects.all() if pairs_timeframes.exists() is False: logger.error("No pairs in a database.") return None wss = BtfxWss() wss.start() time.sleep(1) # give the client some prep time to set itself up last_mts = dict() pairs_timeframes_tuples = pairs_timeframes.values_list( "id", "pair", "timeframe") for pairs_timeframes_id, pair, timeframe in pairs_timeframes_tuples: wss.subscribe_to_candles(pair, timeframe=timeframe) last_mts.update({pairs_timeframes_id: None}) time.sleep(5) candles_queue = {} for pairs_timeframes_id, pair, timeframe in pairs_timeframes_tuples: candles_queue.update( {pair + timeframe: wss.candles(pair=pair, timeframe=timeframe)}) logger.info( "Collecting CANDLES of pair '%s' with timeframe '%s' has been started" % (pair, timeframe)) try: while True: for pairs_timeframes_id, pair, timeframe in pairs_timeframes_tuples: if not candles_queue[pair + timeframe].empty(): q_candles = candles_queue[pair + timeframe].get() """ ([ [4345.5, 16.7770791, 4345.6, 12.74414776, 77.6, 0.0182, 4345.6, 15220.55529737, 4397.5, 4248.4] ], 1503992628.42302) # MTS int millisecond time stamp # OPEN float First execution during the time frame # CLOSE float Last execution during the time frame # HIGH integer Highest execution during the time frame # LOW float Lowest execution during the timeframe # VOLUME float Quantity of symbol traded within the timeframe """ data = [] if isinstance(q_candles[0][0][0], list): mass = sorted(q_candles[0][0], key=lambda x: x[0]) for c in mass: mts = datetime.datetime.utcfromtimestamp( float(str(c[0])[:-3])) if should_update(mts, last_mts, pairs_timeframes_id): data.append({ "mts": mts, "open": c[1], "close": c[2], "high": c[3], "low": c[4], "volume": c[5] }) else: mts = datetime.datetime.utcfromtimestamp( float(str(q_candles[0][0][0])[:-3])) if should_update(mts, last_mts, pairs_timeframes_id): data.append({ "mts": mts, "open": q_candles[0][0][1], "close": q_candles[0][0][2], "high": q_candles[0][0][3], "low": q_candles[0][0][4], "volume": q_candles[0][0][5] }) # Important: # UPSERT works well. # If you have missed rows -> check volume upsert(data=data, pairs_timeframes_id=pairs_timeframes_id) except Exception: logger.error(str(traceback.format_exc())) for pairs_timeframes_id, pair, timeframe in pairs_timeframes_tuples: wss.unsubscribe_from_candles(pair, timeframe=timeframe) # Shutting down the client wss.stop() logger.info("Process terminated")
import sys from btfxwss import BtfxWss log = logging.getLogger(__name__) fh = logging.FileHandler('test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) 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:
log = logging.getLogger(__name__) fh = logging.FileHandler('test.log') fh.setLevel(logging.DEBUG) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG) log.addHandler(sh) log.addHandler(fh) logging.basicConfig(level=logging.DEBUG, handlers=[fh, sh]) client = MongoClient('mongodb://localhost:27017/iotatracker') db = client.iotatracker collection = db['trades'] wss = BtfxWss() wss.start() while not wss.conn.connected.is_set(): time.sleep(1) # Subscribe to some channels wss.subscribe_to_trades('IOTUSD') # Do something else t = time.time() while time.time() - t < 10: pass # Accessing data stored in BtfxWss: while True: