def __init__(self, sandbox_mode=False): LIVE_URL = 'https://api.pro.coinbase.com/' SANDBOX_URL = 'https://api-public.sandbox.pro.coinbase.com/' base_url = SANDBOX_URL if sandbox_mode else LIVE_URL self.history = History(base_url) self.api = API(base_url) self.products = self.api.get('products').json() self.currencies = self.api.get('currencies').json()
def __init__(self, credentials, sandbox_mode=False): LIVE_URL = 'https://api.pro.coinbase.com/' SANDBOX_URL = 'https://api-public.sandbox.pro.coinbase.com/' base_url = SANDBOX_URL if sandbox_mode else LIVE_URL self.cb_public = CBProPublic(sandbox_mode=sandbox_mode) self.api = API(base_url) self.auth = Auth(**credentials) self.accounts = self.api.get('accounts', auth=self.auth).json()
def __init__(self, base_url): self.api = API(base_url) self.ONE_MINUTE = 60 self.MAX_CANDLES = 300 self.api_granularities = { 'minute': self.ONE_MINUTE, 'five_minute': self.ONE_MINUTE * 5, 'fifteen_minute': self.ONE_MINUTE * 15, 'hourly': self.ONE_MINUTE * 60, 'six_hour': self.ONE_MINUTE * 60 * 6, 'daily': self.ONE_MINUTE * 60 * 24 }
class History(): def __init__(self, base_url): self.api = API(base_url) self.ONE_MINUTE = 60 self.MAX_CANDLES = 300 self.api_granularities = { 'minute': self.ONE_MINUTE, 'five_minute': self.ONE_MINUTE * 5, 'fifteen_minute': self.ONE_MINUTE * 15, 'hourly': self.ONE_MINUTE * 60, 'six_hour': self.ONE_MINUTE * 60 * 6, 'daily': self.ONE_MINUTE * 60 * 24 } def build(self, product_id, window_start_datetime, window_end_datetime, candle_interval, debug): self._set_internal_variables(product_id, window_start_datetime, window_end_datetime, candle_interval, debug) if self.date_range_specified: request_array = np.arange(1, self.required_request_count + 1) request_timeline = list( ft.reduce(self._create_request_timeline, request_array, [])) # complete all requests in the request timeline candles = map(self._send_request, request_timeline) candles = list(map(self._format_candle, it.chain(*candles))) return candles else: candles = self._send_request((None, None, 0)) candles = list(map(self._format_candle, candles)) return candles[:-1] def _set_internal_variables(self, product_id, window_start_datetime, window_end_datetime, candle_interval, debug): self.debug = debug self.product_id = product_id.upper() self.endpoint = f'/products/{self.product_id}/candles' self.candle_length_seconds = self.api_granularities[candle_interval] self.candle_length_minutes = self.candle_length_seconds / self.ONE_MINUTE self.date_range_specified = window_start_datetime and window_end_datetime if self.date_range_specified: self.window_start_datetime = datetime.fromisoformat( window_start_datetime) self.window_end_datetime = datetime.fromisoformat( window_end_datetime) # exclusive else: return window_delta_seconds = (self.window_end_datetime - self.window_start_datetime).total_seconds() self.candles_in_window = int( window_delta_seconds / self.candle_length_seconds) - 1 self.required_request_count = math.ceil(self.candles_in_window / self.MAX_CANDLES) def _create_request_timeline(self, accumulator, request_number): is_first_request = request_number == 1 on_last_request = request_number == self.required_request_count one_candle_delta = timedelta(minutes=self.candle_length_minutes) request_delta = timedelta(minutes=self.candle_length_minutes * (self.MAX_CANDLES - 1)) previous_request_end_date = accumulator[-1][1] if len( accumulator) > 0 else None request_start_date = self.window_start_datetime if is_first_request else previous_request_end_date + one_candle_delta request_end_date = self.window_end_datetime - one_candle_delta if on_last_request else request_start_date + request_delta wait_time = 0 if is_first_request else self.api._random_float_between_zero_one( ) accumulator.append((request_start_date, request_end_date, wait_time)) return accumulator def _send_request(self, request_info): start_iso, end_iso, wait_time = request_info params = { 'granularity': self.candle_length_seconds, 'start': start_iso, 'end': end_iso, } time.sleep(wait_time) candles = self.api.get(self.endpoint, params=params).json() candles.reverse() if self.debug: candle_count = len(candles) print( f'Candles Returned: {candle_count}\nTotal Candles Needed: {self.candles_in_window}' ) oldest_candle_datetime = datetime.utcfromtimestamp( candles[0][0]).isoformat() most_recent_candle_datetime = datetime.utcfromtimestamp( candles[-1][0]).isoformat() print( f'\nStart Date: {oldest_candle_datetime}\nEnd Date: {most_recent_candle_datetime}\n\n' ) return candles @staticmethod def _format_candle(candle): ''' Parameters: candle (list): [ 'unix_timestamp', 'low (int or float)', 'high (int or float)', 'open (int or float)', 'close (int or float)', 'volume (int or float)' ] ''' candle_attributes = [ 'open_iso_datetime', 'low', 'high', 'open', 'close', 'volume' ] utc_datetime = datetime.utcfromtimestamp(candle[0]).isoformat() prices_and_volume = list(map(str, candle[1:])) candle = [utc_datetime, *prices_and_volume] candle = dict(zip(candle_attributes, candle)) return candle
class CBProPublic(): def __init__(self, sandbox_mode=False): LIVE_URL = 'https://api.pro.coinbase.com/' SANDBOX_URL = 'https://api-public.sandbox.pro.coinbase.com/' base_url = SANDBOX_URL if sandbox_mode else LIVE_URL self.history = History(base_url) self.api = API(base_url) self.products = self.api.get('products').json() self.currencies = self.api.get('currencies').json() def twenty_four_hour_stats(self, product_id): return self.api.get(f'products/{product_id}/stats').json() def usd_market_volume(self): '''get min $ volume of __/USD trading pairs in past 24 hrs''' usd_trading_pairs = [x for x in self.trading_pairs() if x.split('-')[1] == 'USD'] payload = [] for pair in usd_trading_pairs: stats = self.twenty_four_hour_stats(pair) volume = str(round(Decimal(stats['volume']) * Decimal(stats['low']), 2)) payload.append({'currency_pair': pair, 'usd_volume': volume}) time.sleep(0.4) sorted_payload = sorted(payload, key=lambda x: Decimal(x['usd_volume']), reverse=True) return sorted_payload def usd_price(self, currency, delay=False): '''Get the price in USD for a given asset''' endpoint = f'products/{currency.upper()}-USD/ticker' price = self.api.get(endpoint).json()['price'] if delay: time.sleep(0.4) return price def exchange_rate(self, currency_pair): '''Get the exchange_rate for a given asset''' endpoint = f'products/{currency_pair.upper()}/ticker' price = self.api.get(endpoint).json()['price'] return price def exchange_time(self): '''Return the exchange time in an iso formatted string''' endpoint = 'time' time_str = self.api.get(endpoint).json()['iso'] exchange_time = datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S.%fZ') return exchange_time.isoformat(sep=' ') def historical_prices(self, product_id, start=None, end=None, candle_interval='daily', debug=False): return self.history.build(product_id, start, end, candle_interval, debug) def trading_pairs(self): product_info = self.api.get('products').json() return [d['id'] for d in product_info]
def live_base_api(): return API('https://api.pro.coinbase.com/')
class CBProAuthenticated(): def __init__(self, credentials, sandbox_mode=False): LIVE_URL = 'https://api.pro.coinbase.com/' SANDBOX_URL = 'https://api-public.sandbox.pro.coinbase.com/' base_url = SANDBOX_URL if sandbox_mode else LIVE_URL self.cb_public = CBProPublic(sandbox_mode=sandbox_mode) self.api = API(base_url) self.auth = Auth(**credentials) self.accounts = self.api.get('accounts', auth=self.auth).json() def __getattr__(self, name): try: return getattr(self.cb_public, name) except AttributeError: raise AttributeError( f'The authenticated and public api objects do not have attribute {name}.' ) def refresh_accounts(self): self.accounts = self.api.get('accounts', auth=self.auth).json() def fill_history(self, product_id, order_id=None, start_date=None, end_date=None): '''Get all fills associated with a given product id''' end_point = 'fills' params = {'product_id': product_id.upper()} data = self.api.handle_page_nation(end_point, params=params, start_date=start_date, auth=self.auth) returned_value = data.copy().to_dict(orient='records') return returned_value if data is not None else None @staticmethod def _apply_unique_id_to_activity(entry): if entry['type'] == 'match': entry['unique_id'] = entry['details.order_id'] entry['unique_id_type'] = 'order_id' if entry['type'] == 'transfer': entry['unique_id'] = entry['details.transfer_id'] entry['unique_id_type'] = 'transfer_id' return entry def asset_activity(self, asset_symbol, start_date=None, end_date=None): '''Get all activity related to a given asset''' asset_symbol = asset_symbol.upper() account_id = [ account['id'] for account in self.accounts if account['currency'] == asset_symbol ][0] activity = self.api.handle_page_nation(f"accounts/{account_id}/ledger", start_date=start_date, auth=self.auth) no_activity = len(activity) == 0 if no_activity: return activity activity = map(self._apply_unique_id_to_activity, activity) activity = [{ **entry, 'created_at': entry['created_at'].strftime('%Y-%m-%d %H:%M:%S:%f'), 'symbol': asset_symbol, 'amount': str(entry['amount']), 'balance': str(entry['balance']) } for entry in activity] return activity def completed_orders(self, product_id=None): orders = self.api.handle_page_nation('orders', date_field='done_at', start_date='2019-01-01', auth=self.auth, params={'status': 'done'}) orders = list( filter(lambda order: order['done_reason'] == 'filled', orders)) return orders def market_buy(self, funds, product_id, delay=False): '''send order to api and handle errors''' order_payload = { 'side': 'buy', 'type': 'market', 'product_id': product_id.upper(), 'funds': str(funds), } r = self.api.post('orders', params={}, data=order_payload, auth=self.auth) if delay: time.sleep(0.4) return r def market_sell(self, size, product_id, delay=False): '''send order to api and handle errors''' order_payload = { 'side': 'sell', 'type': 'market', 'product_id': product_id.upper(), 'size': str(size), } r = self.api.post('orders', params={}, data=order_payload, auth=self.auth) if delay: time.sleep(0.4) return r