Ejemplo n.º 1
0
def validate_data_against(data: dict, model: FrozenBaseModel):
    try:
        validated = model(**data)  #type: ignore
        return Ok(validated)
    except ValidationError as e:
        return Err(e)
    except Exception as e:
        raise e
Ejemplo n.º 2
0
def validate_parsed(msg, parsed_msg):

    try:
        validated_msg = NoobitResponseTrades(trades=parsed_msg,
                                             rawJson=msg,
                                             exchange="BINANCE")
        return Ok(validated_msg)

    except ValidationError as e:
        return Err(e)
Ejemplo n.º 3
0
def validate_parsed(msg, parsed_msg):

    try:
        validated_msg = NoobitResponseSpread(spread=(parsed_msg, ),
                                             rawJson=msg,
                                             exchange="KRAKEN")
        return Ok(validated_msg)

    except ValidationError as e:
        print(e)
        return Err(e)
Ejemplo n.º 4
0
def validate_parsed(msg, parsed_msg):

    try:
        validated_msg = NoobitResponseOhlc(ohlc=parsed_msg,
                                           rawJson=msg,
                                           exchange="KRAKEN")
        return Ok(validated_msg)

    except ValidationError as e:
        # print(e)
        return Err(e)
Ejemplo n.º 5
0
def _validate_data(
    model: typing.Type[BaseModel],
    fields: pyrsistent.PMap  # PRecord sublasses PMap so its also acceptable
) -> Result:

    try:
        validated = model(**fields)  #type: ignore
        return Ok(validated)
    except ValidationError as e:
        return Err(e)
    except Exception as e:
        raise e
Ejemplo n.º 6
0
def validate_parsed(msg: BinanceBookMsg, parsed_msg: dict):

    try:
        validated_msg = NoobitResponseOrderBook(
            rawJson=msg,
            exchange="BINANCE",
            **parsed_msg
            )
        return Ok(validated_msg)

    except ValidationError as e:
        return Err(e)
Ejemplo n.º 7
0
async def result_or_err(resp_obj: httpx.Response) -> Result:

    content = await resp_json(resp_obj)

    errors: list = content.get("error", None)

    if errors:
        err_dict = {err: err.split(":")[1] for err in errors}
        return Err(err_dict)
    else:
        # no error
        return Ok(content["result"])
Ejemplo n.º 8
0
async def get_req_content(
    result_or_err: result_or_err_sig,
    parse_err_content: parse_err_content_sig,
    client: ntypes.CLIENT,
    method: str,
    url: pydantic.AnyHttpUrl,
    valid_req: FrozenBaseModel,
    headers: typing.Mapping,
) -> Result:
    """meant to be derived using functools.partial in `exchange`.rest.base.py
    """

    payload = {"method": method, "url": url, "headers": headers}

    query = valid_req.dict(exclude_none=True)

    if method in ["GET"]:
        payload["params"] = query

    elif method in ["POST", "DELETE"]:
        payload["data"] = query

    else:
        raise NotImplementedError(f"Unsupported method : {method}")

    # TODO handle timeout (httpx._exceptions.ConnectTimeout)
    try:
        resp = await client.request(**payload)  #type: ignore
    except Exception as e:
        req_url = urllib.parse.urljoin("url", urllib.parse.urlencode(payload))
        return Err(RequestTimeout(str(e), f"<{method} {req_url}>"))

    content = await result_or_err(resp)
    if content.is_err():
        parsed_err_content = parse_err_content(content.value,
                                               get_sent_request(resp))
        return Err(parsed_err_content)
    else:
        return content
Ejemplo n.º 9
0
def validate_parsed(msg, parsed_msg):

    try:
        validated_msg = NoobitResponseOrderBook(
            **parsed_msg,
            utcTime=time.time() * 10**3,
            rawJson=msg,
            exchange="KRAKEN"
        )
        return Ok(validated_msg)

    except ValidationError as e:
        return Err(e)
Ejemplo n.º 10
0
async def result_or_err(resp_obj: httpx.Response) -> Result:
    # example of ftx error response content:
    #  {"error":"Not logged in","success":false}

    # example of ftx orderbook response content
    # {"success": true, "result": {"asks": [[4114.25, 6.263]], "bids": [[4112.25, 49.]]}}

    content = await resp_json(resp_obj)

    if content["success"]:
        return Ok(content["result"])
    else:
        # needs to be a dict
        return Err({"error": content})
Ejemplo n.º 11
0
    async def fetch_trades(self, exchange: str, symbol: str, since: typing.Optional[int]=None):
        from noobit_markets.base.models.rest.response import NTrades

        self.log_field.log("CALLED fetch_trades")
        
        if not symbol: 
            if not settings.SYMBOL or settings.SYMBOL.isspace(): 
                return Err("Please set or pass <symbol> argument")
            else: symbol = settings.SYMBOL
        else: symbol=symbol.upper()
        
        interface = globals()[exchange]
        _res = await interface.rest.public.trades(self.client, symbol, self.symbols[exchange].value, since)
        _trd = NTrades(_res)
        return _trd
Ejemplo n.º 12
0
async def result_or_err(resp_obj: httpx.Response) -> Result:

    # Example of error content (note no key to indicate it is an error)
    # {"code":-1105,"msg":"Parameter \'startTime\' was empty."}

    content = await resp_json(resp_obj)

    if "code" in content:
        # we have an error message
        error_msg = content.get("msg", None)
        error_key = int(content["code"]) * -1
        return Err({error_key: error_msg})
    else:
        # no error
        return Ok(content)
Ejemplo n.º 13
0
def validate_nreq_orderbook(
        symbol: ntypes.SYMBOL, symbol_mapping: ntypes.SYMBOL_TO_EXCHANGE,
        depth: ntypes.DEPTH
) -> Result[NoobitRequestOrderBook, ValidationError]:

    try:
        valid_req = NoobitRequestOrderBook(symbol=symbol,
                                           symbol_mapping=symbol_mapping,
                                           depth=depth)
        return Ok(valid_req)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 14
0
def validate_nreq_trades(
    symbol: ntypes.SYMBOL, symbol_mapping: ntypes.SYMBOL_TO_EXCHANGE,
    since: typing.Optional[ntypes.TIMESTAMP]
) -> Result[NoobitRequestTrades, ValidationError]:

    try:
        valid_req = NoobitRequestTrades(symbol=symbol,
                                        symbol_mapping=symbol_mapping,
                                        since=since)
        return Ok(valid_req)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 15
0
    async def fetch_orderbook(self, exchange: str, symbol: str, depth: int):
        from noobit_markets.base.models.rest.response import NOrderBook

        self.log_field.log("CALLED fetch_orderbook")

        if not symbol:
            if not settings.SYMBOL or settings.SYMBOL.isspace(): 
                return Err("Please set or pass <symbol> argument")
            else:
                symbol = settings.SYMBOL
        else: symbol=symbol.upper()
        
        interface = globals()[exchange]
        _res = await interface.rest.public.orderbook(self.client, symbol.upper(), self.symbols[exchange].value, depth)
        _book = NOrderBook(_res)
        return _book
Ejemplo n.º 16
0
def validate_nreq_ohlc(
        symbol: ntypes.SYMBOL, symbol_mapping: ntypes.SYMBOL_TO_EXCHANGE,
        timeframe: ntypes.TIMEFRAME,
        since: ntypes.TIMESTAMP) -> Result[NoobitRequestOhlc, ValidationError]:

    try:
        valid_req = NoobitRequestOhlc(symbol=symbol,
                                      symbol_mapping=symbol_mapping,
                                      timeframe=timeframe,
                                      since=since)
        return Ok(valid_req)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 17
0
def validate_nreq_instrument(
    symbol: ntypes.SYMBOL,
    symbol_mapping: ntypes.SYMBOL_TO_EXCHANGE,
) -> Result[NoobitRequestInstrument, ValidationError]:

    try:
        valid_req = NoobitRequestInstrument(
            symbol=symbol,
            symbol_mapping=symbol_mapping,
        )
        return Ok(valid_req)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 18
0
def validate_sub(symbol_to_exchange: SYMBOL_TO_EXCHANGE,
                 symbol: SYMBOL) -> Result[BinanceSubModel, ValidationError]:

    msg = {
        "id": 1,
        "method": "SUBSCRIBE",
        "params": (f"{symbol_to_exchange(symbol)}@aggTrade", )
    }

    try:
        submodel = BinanceSubModel(exchange="binance", feed="trade", msg=msg)
        return Ok(submodel)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 19
0
    async def fetch_openorders(self, exchange: str, symbol: str):
        from noobit_markets.base.models.rest.response import NOrders
    
        self.log_field.log("CALLED fetch_openorders") 
        
        if not symbol: 
            if not settings.SYMBOL or settings.SYMBOL.isspace(): 
                return Err("Please set or pass <symbol> argument")
            else: symbol = settings.SYMBOL
        else: symbol=symbol.upper()

        self.log_field.log(f"Requested Symbol : {symbol}")
        self.log_field.log(f"Requested Exchange : {exchange}")
        
        interface = globals()[exchange]
        _res = await interface.rest.private.open_orders(self.client, symbol, self.symbols[exchange].value)
        _opo = NOrders(_res)
        return _opo
Ejemplo n.º 20
0
def validate_sub(token) -> Result[KrakenSubModel, Exception]:
    msg = {
        "event": "subscribe", 
        "pair": None,
        "subscription": {"name": "openOrders", "token": token} 
    }
    try:
        submodel = KrakenSubModel(
            exchange="kraken",
            feed="user_orders",
            msg=msg
        )
        return Ok(submodel)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 21
0
def get_response_status_code(
        resp_obj: httpx.Response) -> Result[pydantic.PositiveInt, BaseError]:
    # status_code = response_json.status_code
    # err_msg = f"HTTP Status Error: {status_code}"
    # return Ok(status_code) if status_code == 200 else Err(err_msg)

    status_keys = [k for k in resp_obj.__dict__.keys() if "status" in k]

    if len(status_keys) > 1:
        raise KeyError(
            f"Found multiple <status> keys in {resp_obj.__dict__.keys()}")

    status = getattr(resp_obj, status_keys[0])

    if status == 200:
        return Ok(status)
    else:
        msg = f"Http Status Error: {status}"
        return Err(
            BadRequest(raw_error=msg, sent_request=get_sent_request(resp_obj)))
Ejemplo n.º 22
0
def validate_sub(symbol_to_exchange: SYMBOL_TO_EXCHANGE, symbol: SYMBOL, depth: DEPTH) -> Result[KrakenSubModel, ValidationError]:

    msg = {
        "event": "subscribe",
        "pair": [symbol_to_exchange(symbol), ],
        "subscription": {"name": "book", "depth": depth}
    }

    try:
        submodel = KrakenSubModel(
            exchange="kraken",
            feed="orderbook",
            msg=msg
        )
        return Ok(submodel)

    except ValidationError as e:
        return Err(e)

    except Exception as e:
        raise e
Ejemplo n.º 23
0
def validate_sub(
        symbol_to_exchange: SYMBOL_TO_EXCHANGE, symbol: SYMBOL,
        timeframe: TIMEFRAME) -> Result[KrakenSubModel, ValidationError]:

    msg = {
        "event": "subscribe",
        "pair": [
            symbol_to_exchange(symbol),
        ],
        "subscription": {
            "name": "ohlc",
            "interval": K_TIMEFRAME_FROM_N[timeframe]
        }
    }

    try:
        submodel = KrakenSubModel(exchange="kraken", feed="trade", msg=msg)
        return Ok(submodel)

    except ValidationError as e:
        return Err(e)
Ejemplo n.º 24
0
    async def confirm_subscription(self):

        msg = await self.client.recv()

        if not 'subscription' in msg:
            return Err()
Ejemplo n.º 25
0
async def cancel_openorder_kraken(
    client: ntypes.CLIENT,
    symbol: ntypes.SYMBOL,
    symbols_resp: NoobitResponseSymbols,
    orderID: str,
    # prevent unintentional passing of following args
    *,
    logger: typing.Optional[typing.Callable] = None,
    auth=KrakenAuth(),
    base_url: pydantic.AnyHttpUrl = endpoints.KRAKEN_ENDPOINTS.private.url,
    endpoint: str = endpoints.KRAKEN_ENDPOINTS.private.endpoints.remove_order,
) -> Result[NoobitResponseItemOrder, Exception]:

    symbol_to_exchange = lambda x: {
        k: v.exchange_pair
        for k, v in symbols_resp.asset_pairs.items()
    }[x]

    req_url = urljoin(base_url, endpoint)
    method = "POST"

    payload = {"txid": orderID}
    data = {"nonce": auth.nonce, **payload}

    valid_kraken_req = _validate_data(KrakenRequestCancelOpenOrder, pmap(data))
    if valid_kraken_req.is_err():
        return valid_kraken_req

    headers = auth.headers(endpoint, data)

    result_content = await get_result_content_from_req(client, method, req_url,
                                                       valid_kraken_req.value,
                                                       headers)
    if result_content.is_err():
        return result_content

    if logger:
        logger(f"Cancel Open Order - Result content : {result_content.value}")

    valid_result_content = _validate_data(KrakenResponseCancelOpenOrder,
                                          result_content.value)
    if valid_result_content.is_err():
        return valid_result_content

    cl_ord = await get_closedorders_kraken(client,
                                           symbol,
                                           symbols_resp,
                                           logger=logger,
                                           auth=auth)

    if isinstance(cl_ord, Ok):
        try:
            [order_info] = [
                order for order in cl_ord.value.orders
                if order.orderID == orderID
            ]
            return Ok(order_info)
        except ValueError as e:
            return Err(e)
        except Exception as e:
            return Err(e)
    else:
        return cl_ord
Ejemplo n.º 26
0
    async def cancel_order(
        self,
        exchange: str,
        symbol: str,
        slice: str,
        all: bool
    ):
        
        self.log_field.log("CALLED cancel_order") 

        # testlist = [x for x in range(0, 100)]
        # regex = re.compile(r"^\[[-]?[0-9]+:[-]?[0-9]+\]$")
        regex = "^\[[-]?[0-9]+:[-]?[0-9]+:[-]?[0-9]\]$"
        match = re.match(regex, slice)
        
        if not match:
            self.log(match)
            return Err(f"Argument position did not match regex - Given {slice}")
        else:
            # sliced = eval(f"testlist{position}")
            # self.log(sliced)
            # return Ok("SUCCESS")
        
            if not symbol: 
                if not settings.SYMBOL or settings.SYMBOL.isspace(): 
                    return Err("Please set or pass <symbol> argument")
                else: symbol = settings.SYMBOL
            else: symbol=symbol.upper()

            self.log_field.log(f"Requested Symbol : {symbol}")
            self.log_field.log(f"Requested Exchange : {exchange}")
            
            interface = globals()[exchange]
            _res = await interface.rest.private.open_orders(self.client, symbol, self.symbols[exchange].value)

            if _res.is_err():
                return _res.value
            else:
                _acc = []

                _all_orders = sorted([order for order in _res.value.orders], key=lambda x: getattr(x, "price"), reverse=False)
                _sliced_orders = eval(f"_all_orders{slice}") 

                for _order in _sliced_orders:

                    _ord = await interface.rest.private.remove_order(self.client, symbol, self.symbols[exchange].value, _order.orderID)

                    if _ord.is_ok():
                        _acc.append(_ord.value)
                    else:
                        return _ord

                    await asyncio.sleep(1)
                
                try:
                    _canceled_orders = NoobitResponseClosedOrders(
                        exchange="KRAKEN",
                        rawjson={},
                        orders=_acc
                    )
                    # request coros always return a result
                    # so we wrap the validated model in an OK container
                    _nords = NOrders(Ok(_canceled_orders))
                    return _nords
                except ValidationError as e:
                    return Err(e)
Ejemplo n.º 27
0
    async def create_neworder(
        self,
        exchange: str,
        symbol: str,
        ordType: str,
        clOrdID,
        orderQty: float,
        price: float,
        timeInForce: str = "GOOD-TIL-CANCEL",
        quoteOrderQty: typing.Optional[float] = None,
        stopPrice: typing.Optional[float] = None,
        *,
        side: str,
        blind: bool,
        split: typing.Optional[int] = None,
        delay: typing.Optional[int] = None,
        step: typing.Optional[float] = None,
    ):
        from noobit_markets.base.models.rest.response import NSingleOrder

        self.log_field.log("CALLED create_neworder") 

        if not symbol: 
            if not settings.SYMBOL or settings.SYMBOL.isspace(): 
                return Err("Please set or pass <symbol> argument")
            else: symbol = settings.SYMBOL
        else: symbol=symbol.upper()

        if not ordType:
            if not settings.ORDTYPE or settings.ORDTYPE.isspace(): 
                return Err("Please set or pass <ordType> argument")
            else: ordType = settings.ORDTYPE
        # TODO be consistent: either all noobit types in capital or in lowercase
        else: ordType = ordType.upper()

        if not orderQty:
            if not settings.ORDQTY: 
                return Err("Please set or pass <orderQty> argument")
            else: orderQty = settings.ORDQTY

        if not timeInForce and ordType in ["LIMIT", "STOP-LOSS-LIMIT", "TAKE-PROFIT-LIMIT"]:
            self.log("WARNING : <timeInForce> not provided, defaulting to <GOOD-TIL-CANCEL>")
            timeInForce = "GOOD-TIL-CANCEL"

        
        interface = globals()[exchange]

        if split:
            # step is only for limit orders
            if step:
                if not ordType in ["LIMIT", "STOP_LIMIT", "TAKE_PROFIT"]:
                    return Err(f"Argument <step>: Ordertype can not be {ordType}")
            
            # only one of delay or step
            if not any([delay, step]) or all([delay, step]):
                return Err("Please set only one of <delay> or <step> argument to split orders")
            else: 
                _acc = []
                acc_price = price

                for i in range(split):
                    _res = await interface.rest.private.new_order(
                        client=self.client,
                        symbol=symbol, 
                        symbols_resp=self.symbols[exchange].value, 
                        side=side, 
                        ordType=ordType, 
                        clOrdID=clOrdID, 
                        # orderQty=round(orderQty/split, self.symbols[exchange].value.asset_pairs[symbol].volume_decimals), # TODO atm we limit to 2 decimal places, could check max decimals for pair, ALSO this can lead to keyerror if symbol is not on exchange
                        orderQty=round(orderQty/split, 2), # TODO atm we limit to 2 decimal places, could check max decimals for pair, ALSO this can lead to keyerror if symbol is not on exchange
                        price=acc_price, 
                        timeInForce=timeInForce, 
                        quoteOrderQty=quoteOrderQty, 
                        stopPrice=stopPrice
                        )
                    if _res.is_ok():
                        if blind:
                            _res.value.price = None
                        _acc.append(_res.value)
                        self.log_field.log(f"Successful order, count {len(_acc)}")
                    else:
                        self.log_field.log(f"Failed order")
                        return _res
                    
                    if step:
                        acc_price = round(float(acc_price + step), 2) # FIXME this will create decimal place precision errors sometimes, we need to round somehow (use context ??) 
                        await asyncio.sleep(1)
                    else:
                        await asyncio.sleep(delay)  # avoid rate limiting


                try:
                    
                    if blind:
                        self.log("Argument <blind>: Setting Order Price to <None>")
                    
                    _splitorders = NoobitResponseClosedOrders(
                        exchange="KRAKEN",
                        rawjson={},
                        orders=_acc
                    )
                    # request coros always return a result
                    # so we wrap the validated model in an OK container
                    
                    _nords = NOrders(Ok(_splitorders))
                    return _nords
                except ValidationError as e:
                    return Err(e)


        else:

            if any([delay, step]):
                self.log_field.log("Argument <delay> or <step> require <split>")    
                return Err("Argument <delay> or <step> require <split>")    

            _res = await interface.rest.private.new_order(
                client=self.client,
                symbol=symbol, 
                symbols_resp=self.symbols[exchange].value, 
                side=side, 
                ordType=ordType, 
                clOrdID=clOrdID, 
                orderQty=orderQty, 
                price=price, 
                timeInForce=timeInForce, 
                quoteOrderQty=quoteOrderQty, 
                stopPrice=stopPrice
                )

            if blind:
                self.log("Argument <blind>: Setting Order Price to <None>")
                if _res.is_ok():
                    _res.value.price = None

            _nord = NSingleOrder(_res)
        
            return _nord