Example #1
0
def connect(ping_timeout=20, ping_interval=70):
    if cryptowatch.api_key:
        DSN = "{}?apikey={}&format=binary".format(cryptowatch.ws_endpoint,
                                                  cryptowatch.api_key)
    else:
        raise APIKeyError(
            "An API key is required to use the Cryptowatch Websocket API.\n"
            "You can create one at https://cryptowat.ch/account/api-access")
    log("DSN used: {}".format(DSN), is_debug=True)
    websocket.enableTrace(False)
    global _ws
    _ws = websocket.WebSocketApp(
        DSN,
        on_message=on_market_update,
        on_error=_on_error,
        on_close=_on_close,
        on_open=_on_open,
    )
    wst = threading.Thread(
        target=_ws.run_forever,
        kwargs={
            "ping_timeout": ping_timeout,
            "ping_interval": ping_interval
        },
    )
    wst.daemon = False
    wst.start()
    log(
        "Ping timeout used: {}. Ping interval used: {}".format(
            ping_timeout, ping_interval),
        is_debug=True,
    )
Example #2
0
 def __init__(self, api_endpoint, user_agent, opts={}):
     # Must have options
     self.user_agent = user_agent
     self.api_endpoint = api_endpoint
     if not api_endpoint.startswith("https"):
         log('Warning: API endpoint must start with "https".', is_error=True)
     if not user_agent:
         log("Warning: User-Agent header must be set.", is_error=True)
     # Options with defaults, overridden by kwargs
     self.verify_ssl = opts.get("verify_ssl", True)
     self.connect_timeout = opts.get("connect_timeout", 5)
     self.read_timeout = opts.get("read_timeout", 20)
     self.max_retries = opts.get("max_retries", 5)
     # Make all API calls share the same session
     self.api_client = requests.Session()
     # Apply a backoff for failing requests, up to self.max_retries
     # 1st waiting will be 0.1s, then 0.2s, 0.4s, etc, following this formula:
     # {backoff factor} * (2 ** ({number of retries so far} - 1))
     retries = Retry(
         total=self.max_retries,
         backoff_factor=0.1,
         status_forcelist=[500, 502, 503, 504],
     )
     a = requests.adapters.HTTPAdapter(max_retries=retries)
     self.api_client.mount("https://", a)
Example #3
0
def connect(ping_timeout=20, ping_interval=70):
    if cryptowatch.api_key:
        DSN = "{}?apikey={}".format(cryptowatch.ws_endpoint, cryptowatch.api_key)
    else:
        DSN = cryptowatch.ws_endpoint
    log("DSN used: {}".format(DSN), is_debug=True)
    websocket.enableTrace(True)
    global _ws
    _ws = websocket.WebSocketApp(
        DSN,
        on_message=on_market_update,
        on_error=_on_error,
        on_close=_on_close,
        on_open=_on_open,
    )
    wst = threading.Thread(
        target=_ws.run_forever,
        kwargs={"ping_timeout": ping_timeout, "ping_interval": ping_interval},
    )
    wst.daemon = False
    wst.start()
    log(
        "Ping timeout used: {}. Ping interval used: {}".format(
            ping_timeout, ping_interval
        ),
        is_debug=True,
    )
Example #4
0
def _on_open(ws):
    subs_payload = forge_stream_subscription_payload(subscriptions, client_pb2)
    log(
        "Connection established. Sending subscriptions payload: {}".format(
            subs_payload),
        is_debug=True,
    )
    ws.send(subs_payload)
Example #5
0
 def list(self):
     log("Getting all exchanges")
     data = self.client.get_resource("/exchanges")
     exchange_resp = json.loads(data)
     schema = ExchangeListAPIResponseSchema()
     exchanges_obj = schema.load(exchange_resp)
     log("API Allowance: cost={} remaining={}".format(
         exchanges_obj._allowance.cost, exchanges_obj._allowance.remaining))
     return exchanges_obj
Example #6
0
 def get(self, asset):
     log("Getting asset {}".format(asset))
     data, http_resp = self.client.get_resource("/assets/{}".format(asset))
     asset_resp = json.loads(data)
     schema = AssetAPIResponseSchema()
     asset_obj = schema.load(asset_resp)
     log("API Allowance: cost={} remaining={}".format(
         asset_obj._allowance.cost, asset_obj._allowance.remaining))
     asset_obj._http_response = http_resp
     return asset_obj
Example #7
0
 def list(self):
     log("Listing all assets")
     data, http_resp = self.client.get_resource("/assets")
     asset_resp = json.loads(data)
     schema = AssetListAPIResponseSchema()
     assets_obj = schema.load(asset_resp)
     log("API Allowance: cost={} remaining={}".format(
         assets_obj._allowance.cost, assets_obj._allowance.remaining))
     assets_obj._http_response = http_resp
     return assets_obj
Example #8
0
 def list(self):
     log("Getting instruments")
     data = self.client.get_resource("/pairs")
     instrument_resp = json.loads(data)
     schema = InstrumentListAPIResponseSchema()
     instruments_obj = schema.load(instrument_resp)
     log("API Allowance: cost={} remaining={}".format(
         instruments_obj._allowance.cost,
         instruments_obj._allowance.remaining))
     return instruments_obj
Example #9
0
 def get(self, instrument):
     log("Getting instrument {}".format(instrument))
     data, http_resp = self.client.get_resource(
         "/pairs/{}".format(instrument))
     instrument_resp = json.loads(data)
     schema = InstrumentAPIResponseSchema()
     instrument_obj = schema.load(instrument_resp)
     log("API Allowance: cost={} remaining={}".format(
         instrument_obj._allowance.cost,
         instrument_obj._allowance.remaining))
     instrument_obj._http_response = http_resp
     return instrument_obj
Example #10
0
 def get(self, exchange):
     log("Getting exchange {}".format(exchange))
     data, http_resp = self.client.get_resource(
         "/exchanges/{}".format(exchange))
     exchange_resp = json.loads(data)
     schema = ExchangeAPIResponseSchema()
     exchange_obj = schema.load(exchange_resp)
     if exchange_obj._allowance:
         log("API Allowance: cost={} remaining={}".format(
             exchange_obj._allowance.cost,
             exchange_obj._allowance.remaining))
     exchange_obj._http_response = http_resp
     return exchange_obj
Example #11
0
def on_market_update(ws, message):
    try:
        message = message.decode("utf-8")
        message = json.loads(message)
        if "marketUpdate" in message:
            if "intervalsUpdate" in message.get("marketUpdate", ""):
                schema = CandleMarketUpdateSchema()
                candle_obj = schema.load(message)
                on_intervals_update(candle_obj)
            elif "tradesUpdate" in message.get("marketUpdate", ""):
                schema = TradeMarketUpdateSchema()
                trade_obj = schema.load(message)
                on_trades_update(trade_obj)
            elif "orderBookUpdate" in message.get("marketUpdate", ""):
                schema = OrderbookSnapshotMarketUpdateSchema()
                orderbook_snapshot_obj = schema.load(message)
                on_orderbook_snapshot_update(orderbook_snapshot_obj)
            elif "orderBookDeltaUpdate" in message.get("marketUpdate", ""):
                schema = OrderbookDeltaMarketUpdateSchema()
                orderbook_delta_obj = schema.load(message)
                on_orderbook_delta_update(orderbook_delta_obj)
            elif "orderBookSpreadUpdate" in message.get("marketUpdate", ""):
                schema = OrderbookSpreadMarketUpdateSchema()
                orderbook_spread_obj = schema.load(message)
                on_orderbook_spread_update(orderbook_spread_obj)
            else:
                log(message, is_debug=True)
        else:
            log(message, is_debug=True)
    except Exception as ex:
        log(ex, is_error=True)
        log(traceback.format_exc(), is_error=True)
Example #12
0
def on_market_update(ws, message):
    try:
        stream_message = stream_pb2.StreamMessage()
        stream_message.ParseFromString(message)
        if str(stream_message.marketUpdate.intervalsUpdate):
            on_intervals_update(stream_message)
        elif str(stream_message.marketUpdate.tradesUpdate):
            on_trades_update(stream_message)
        elif str(stream_message.marketUpdate.orderBookUpdate):
            on_orderbook_snapshot_update(stream_message)
        elif str(stream_message.marketUpdate.orderBookDeltaUpdate):
            on_orderbook_delta_update(stream_message)
        elif str(stream_message.marketUpdate.orderBookSpreadUpdate):
            on_orderbook_spread_update(stream_message)
        else:
            log(stream_message, is_debug=True)
    except protobuf.message.DecodeError as ex:
        log("Could not decode this message: {}".format(message), is_error=True)
        log(traceback.format_exc(), is_error=True)
    except Exception as ex:
        log(traceback.format_exc(), is_error=True)
Example #13
0
 def list(self, exchange=None):
     if exchange:
         resource = "/markets/{}".format(exchange)
         log("Getting all markets for {}".format(exchange))
     else:
         resource = "/markets"
         log("Getting all markets for all exchanges")
     data = self.client.get_resource(resource)
     market_resp = json.loads(data)
     schema = MarketListAPIResponseSchema()
     markets_obj = schema.load(market_resp)
     log("API Allowance: cost={} remaining={}".format(
         markets_obj._allowance.cost, markets_obj._allowance.remaining))
     return markets_obj
Example #14
0
def on_orderbook_snapshot_update(orderbook_snapshot_update):
    log(orderbook_snapshot_update, is_debug=True)
Example #15
0
 def get(self,
         market,
         liquidity=False,
         orderbook=False,
         trades=False,
         ohlc=False,
         periods=[],
         before=None,
         after=None):
     exchange, pair = market.split(":")
     if ohlc:
         log("Getting market OHLC candles {}".format(market))
         resource = "/markets/{}/{}/ohlc".format(exchange, pair)
         query = []
         if periods:
             sec_periods = translate_periods(periods)
             #resource += "?periods={}".format(",".join(sec_periods))
             query.append(f"periods={','.join(sec_periods)}")
         if before:
             query.append(f'before={before}')
         if after:
             query.append(f'after={after}')
         if len(query) > 0:
             resource += f"?{'&'.join(query)}"
         schema = MarketOHLCAPIResponseSchema()
     elif trades:
         log("Getting market trades {}".format(market))
         resource = "/markets/{}/{}/trades".format(exchange, pair)
         schema = MarketTradesAPIResponseSchema()
     elif orderbook:
         log("Getting market orderbook {}".format(market))
         resource = "/markets/{}/{}/orderbook".format(exchange, pair)
         schema = MarketOrderBookAPIResponseSchema()
     elif liquidity:
         log("Getting market liquidity {}".format(market))
         resource = "/markets/{}/{}/orderbook/liquidity".format(
             exchange, pair)
         schema = MarketLiquidityAPIResponseSchema()
     else:
         log("Getting market summary {}".format(market))
         resource = "/markets/{}/{}/summary".format(exchange, pair)
         schema = MarketSummaryAPIResponseSchema()
     data, http_resp = self.client.get_resource(resource)
     market_resp = json.loads(data)
     market_obj = schema.load(market_resp)
     if market_obj._allowance:
         log("API Allowance: cost={} remaining={}".format(
             market_obj._allowance.cost, market_obj._allowance.remaining))
     market_obj._http_response = http_resp
     return market_obj
Example #16
0
 def get_resource(self, resource):
     try:
         headers = {"User-Agent": self.user_agent, "Accept": "application/json"}
         if cryptowatch.api_key:
             headers["X-CW-API-Key"] = cryptowatch.api_key
         url = "{}{}".format(self.api_endpoint, resource)
         log("HTTP GET {}\n\twith headers: {}".format(url, headers), is_debug=True)
         resp = self.api_client.get(
             url,
             headers=headers,
             verify=self.verify_ssl,
             timeout=(self.connect_timeout, self.read_timeout),
             allow_redirects=True,
         )
         log(
             "Received HTTP Status {} for {}".format(resp.status_code, url),
             is_debug=True,
         )
         resp.raise_for_status()
     # Only catch API Errors, let other Exceptions bubble up
     except requests.exceptions.HTTPError as ex:
         # Resource not found
         if resp.status_code == 404:
             msg = resp.json().get("error", "No such resource at {}".format(url))
             raise cryptowatch.errors.APIResourceNotFoundError(
                 msg, resp.text, resp.status_code, resp.request.headers,
             )
         # Allowance exceeded
         elif resp.status_code == 429:
             msg = resp.json().get(
                 "error",
                 "You have exceeded your current API allowance. "
                 "Upgrade for a higher allowance at https://cryptowat.ch/pricing",
             )
             raise cryptowatch.errors.APIRateLimitError(
                 msg, resp.text, resp.status_code, resp.request.headers,
             )
         # Any HTTP 4XX Error
         elif str(resp.status_code).startswith("4"):
             raise cryptowatch.errors.APIRequestError(
                 "Your request failed. Please try again in a moment.",
                 resp.text,
                 resp.status_code,
                 resp.request.headers,
             )
         # Any HTTP 5XX Error
         elif str(resp.status_code).startswith("5"):
             raise cryptowatch.errors.APIServerError(
                 "The Cryptowatch API is having some issues. "
                 "Please try again in a moment.",
                 resp.text,
                 resp.status_code,
                 resp.request.headers,
             )
         # Any other HTTP Error
         else:
             raise cryptowatch.errors.APIError(
                 "Error connecting to the API. Please try again in a moment.",
                 resp.text,
                 resp.status_code,
                 resp.request.headers,
             )
     else:
         return resp.text, resp
Example #17
0
def _on_error(ws, error):
    log(str(error), is_error=True)
Example #18
0
def _on_close(ws):
    log("Connection closed.", is_debug=True)
Example #19
0
 def get(
     self,
     market,
     liquidity=False,
     orderbook=False,
     trades=False,
     ohlc=False,
     periods=[],
     before=False,
     after=False
 ):
     exchange, pair = market.split(":")
     if ohlc:
         log("Getting market OHLC candles {}".format(market))
         resource = "/markets/{}/{}/ohlc".format(exchange, pair)
         if periods:
             sec_periods = translate_periods(periods)
             resource += "?periods={}".format(",".join(sec_periods))
         if before:
             sep = "&" if "?" in resource else "?"
             resource += "{}before={}".format(sep, before)
         if after:
             sep = "&" if "?" in resource else "?"
             resource += "{}after={}".format(sep, after)
         schema = MarketOHLCAPIResponseSchema()
     elif trades:
         log("Getting market trades {}".format(market))
         resource = "/markets/{}/{}/trades".format(exchange, pair)
         schema = MarketTradesAPIResponseSchema()
     elif orderbook:
         log("Getting market orderbook {}".format(market))
         resource = "/markets/{}/{}/orderbook".format(exchange, pair)
         schema = MarketOrderBookAPIResponseSchema()
     elif liquidity:
         log("Getting market liquidity {}".format(market))
         resource = "/markets/{}/{}/orderbook/liquidity".format(exchange, pair)
         schema = MarketLiquidityAPIResponseSchema()
     else:
         log("Getting market summary {}".format(market))
         resource = "/markets/{}/{}/summary".format(exchange, pair)
         schema = MarketSummaryAPIResponseSchema()
     data, http_resp = self.client.get_resource(resource)
     market_resp = json.loads(data)
     market_obj = schema.load(market_resp)
     if market_obj._allowance:
         log(
             "API Allowance: cost={} remaining={}".format(
                 market_obj._allowance.cost, market_obj._allowance.remaining
             )
         )
     market_obj._http_response = http_resp
     return market_obj
Example #20
0
def read_config():
    user_home_dir = os.environ.get("HOME")
    filepath = "{}/.cw/credentials.yml".format(user_home_dir)
    api_key = None
    rest_url = None
    stream_url = None
    try:
        with open(filepath, "r") as config_file:
            config = yaml.safe_load(config_file)
            # A config_file empty or with all lines commented out will return None
            if not config:
                log("Your configuration file at {} is empty".format(filepath), is_debug=True)
            else:
                # Look for the (public) API Key
                if not config.get("apikey") and not config.get("api_key"):
                    log("No API key seen in credential file", is_debug=True)
                else:
                    api_key = config.get("apikey")
                    if api_key is None:
                        api_key = config.get("api_key")
                # Look for a stream (websocket) URL
                if not config.get("stream_url"):
                    log("No stream URL seen in credential file", is_debug=True)
                else:
                    stream_url = config.get("stream_url")
                # Look for a REST API URL
                if not config.get("rest_url"):
                    log("No rest URL seen in credential file", is_debug=True)
                else:
                    rest_url = config.get("rest_url")
    except FileNotFoundError as ex:
        log("No credential file found", is_debug=True)
    except yaml.YAMLError as ex:
        log("Credential is not a valid YAML file", is_error=True)
        raise error.CredentialsFileError(
            "Your Cryptowatch credentials file at "
            "{} is not properly formatted.".format(filepath)
        )
    except Exception as ex:
        log(traceback.format_exc(), is_error=True)
    finally:
        return api_key, rest_url, stream_url
Example #21
0
def on_trades_update(trades_update):
    log(trades_update, is_debug=True)
Example #22
0
def on_intervals_update(intervals_update):
    log(intervals_update, is_debug=True)
Example #23
0
def on_orderbook_spread_update(orderbook_spread_update):
    log(orderbook_spread_update, is_debug=True)
Example #24
0
def on_orderbook_delta_update(orderbook_delta_update):
    log(orderbook_delta_update, is_debug=True)
Example #25
0
def _on_close(ws, close_status_code, close_reason):
    log("Connection closed.", is_debug=True)