Exemplo n.º 1
0
    async def _cancel_order(self, command: CancelOrder) -> None:
        self._log.debug(f"Canceling order {command.client_order_id.value}.")

        self.generate_order_pending_cancel(
            strategy_id=command.strategy_id,
            instrument_id=command.instrument_id,
            client_order_id=command.client_order_id,
            venue_order_id=command.venue_order_id,
            ts_event=self._clock.timestamp_ns(),
        )

        try:
            if command.venue_order_id is not None:
                await self._http_account.cancel_order(
                    symbol=format_symbol(command.instrument_id.symbol.value),
                    order_id=command.venue_order_id.value,
                )
            else:
                await self._http_account.cancel_order(
                    symbol=format_symbol(command.instrument_id.symbol.value),
                    orig_client_order_id=command.client_order_id.value,
                )
        except BinanceError as ex:
            self._log.exception(
                f"Cannot cancel order "
                f"ClientOrderId({command.client_order_id}), "
                f"VenueOrderId{command.venue_order_id}: ",
                ex,
            )
Exemplo n.º 2
0
    async def avg_price(self, symbol: str) -> Dict[str, Any]:
        """
        Get the current average price for the given symbol.

        `GET /api/v3/avgPrice`

        Parameters
        ----------
        symbol : str
            The trading pair.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#current-average-price

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "avgPrice",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 3
0
    async def create_listen_key_isolated_margin(self, symbol: str) -> Dict[str, Any]:
        """
        Create a new listen key for the ISOLATED MARGIN API.

        Start a new user data stream. The stream will close after 60 minutes
        unless a keepalive is sent. If the account has an active listenKey,
        that listenKey will be returned and its validity will be extended for 60
        minutes.

        Create a ListenKey (USER_STREAM).
        `POST /api/v3/userDataStream `.

        Parameters
        ----------
        symbol : str
            The symbol for the listen key request.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin

        """
        raw: bytes = await self.client.send_request(
            http_method="POST",
            url_path="/sapi/v1/userDataStream/isolated",
            payload={"symbol": format_symbol(symbol)},
        )

        return orjson.loads(raw)
Exemplo n.º 4
0
    async def close_listen_key_isolated_margin(self, symbol: str, key: str) -> Dict[str, Any]:
        """
        Close a listen key for the ISOLATED MARGIN API.

        Close a ListenKey (USER_STREAM).
        `DELETE /sapi/v1/userDataStream`.

        Parameters
        ----------
        symbol : str
            The symbol for the listen key request.
        key : str
            The listen key for the request.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin

        """
        raw: bytes = await self.client.send_request(
            http_method="DELETE",
            url_path="/sapi/v1/userDataStream/isolated",
            payload={"listenKey": key, "symbol": format_symbol(symbol)},
        )

        return orjson.loads(raw)
Exemplo n.º 5
0
    async def ticker_24hr(self, symbol: str = None) -> Dict[str, Any]:
        """
        24hr Ticker Price Change Statistics.

        `GET /api/v3/ticker/24hr`

        Parameters
        ----------
        symbol : str, optional
            The trading pair.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#24hr-ticker-price-change-statistics

        """
        payload: Dict[str, str] = {}
        if symbol is not None:
            payload["symbol"] = format_symbol(symbol)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "ticker/24hr",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 6
0
    async def _submit_trailing_stop_market_order(
            self, order: TrailingStopMarketOrder) -> None:
        if order.trigger_type in (TriggerType.DEFAULT, TriggerType.LAST):
            working_type = "CONTRACT_PRICE"
        elif order.trigger_type == TriggerType.MARK:
            working_type = "MARK_PRICE"
        else:
            self._log.error(
                f"Cannot submit order: invalid `order.trigger_type`, was "
                f"{TriggerTypeParser.to_str_py(order.trigger_price)}. {order}",
            )
            return

        if order.offset_type not in (TrailingOffsetType.DEFAULT,
                                     TrailingOffsetType.BASIS_POINTS):
            self._log.error(
                f"Cannot submit order: invalid `order.offset_type`, was "
                f"{TrailingOffsetTypeParser.to_str_py(order.offset_type)} (use `BASIS_POINTS`). "
                f"{order}", )
            return

        await self._http_account.new_order(
            symbol=format_symbol(order.instrument_id.symbol.value),
            side=OrderSideParser.to_str_py(order.side),
            type=binance_order_type(order),
            time_in_force=TimeInForceParser.to_str_py(order.time_in_force),
            quantity=str(order.quantity),
            activation_price=str(order.trigger_price),
            callback_rate=str(order.trailing_offset / 100),
            working_type=working_type,
            reduce_only=order.
            is_reduce_only,  # Cannot be sent with Hedge-Mode or closePosition
            new_client_order_id=order.client_order_id.value,
            recv_window=5000,
        )
Exemplo n.º 7
0
    async def book_ticker(self, symbol: str = None) -> Dict[str, Any]:
        """
        Symbol Order Book Ticker.

        `GET /api/v3/ticker/bookTicker`

        Parameters
        ----------
        symbol : str, optional
            The trading pair.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#symbol-order-book-ticker

        """
        payload: Dict[str, str] = {}
        if symbol is not None:
            payload["symbol"] = format_symbol(symbol).upper()

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "ticker/bookTicker",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 8
0
    async def trades(self,
                     symbol: str,
                     limit: Optional[int] = None) -> List[Dict[str, Any]]:
        """
        Get recent market trades.

        Recent Trades List.
        `GET /api/v3/trades`

        Parameters
        ----------
        symbol : str
            The trading pair.
        limit : int, optional
            The limit for the response. Default 500; max 1000.

        Returns
        -------
        list[dict[str, Any]]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#recent-trades-list

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if limit is not None:
            payload["limit"] = str(limit)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "trades",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 9
0
    async def ping_listen_key_isolated_margin(self, symbol: str, key: str) -> Dict[str, Any]:
        """
        Ping/Keep-alive a listen key for the ISOLATED MARGIN API.

        Keep-alive a user data stream to prevent a time-out. User data streams
        will close after 60 minutes. It's recommended to send a ping about every
        30 minutes.

        Ping/Keep-alive a ListenKey (USER_STREAM).
        `PUT /api/v3/userDataStream`.

        Parameters
        ----------
        symbol : str
            The symbol for the listen key request.
        key : str
            The listen key for the request.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#listen-key-isolated-margin

        """
        raw: bytes = await self.client.send_request(
            http_method="PUT",
            url_path="/sapi/v1/userDataStream/isolated",
            payload={"listenKey": key, "symbol": format_symbol(symbol)},
        )

        return orjson.loads(raw)
Exemplo n.º 10
0
    async def depth(self,
                    symbol: str,
                    limit: Optional[int] = None) -> Dict[str, Any]:
        """
        Get orderbook.

        `GET /api/v3/depth`

        Parameters
        ----------
        symbol : str
            The trading pair.
        limit : int, optional, default 100
            The limit for the response. Default 100; max 5000.
            Valid limits:[5, 10, 20, 50, 100, 500, 1000, 5000].

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#order-book

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if limit is not None:
            payload["limit"] = str(limit)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "depth",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 11
0
    async def get_orders(
        self,
        symbol: str,
        order_id: Optional[str] = None,
        start_time: Optional[int] = None,
        end_time: Optional[int] = None,
        limit: Optional[int] = None,
        recv_window: Optional[int] = None,
    ) -> List[Dict[str, Any]]:
        """
        Get all account orders (open, or closed).

        All Orders (USER_DATA).

        Parameters
        ----------
        symbol : str
            The symbol for the request.
        order_id : str, optional
            The order ID for the request.
        start_time : int, optional
            The start time (UNIX milliseconds) filter for the request.
        end_time : int, optional
            The end time (UNIX milliseconds) filter for the request.
        limit : int, optional
            The limit for the response.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        list[dict[str, Any]]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#all-orders-user_data
        https://binance-docs.github.io/apidocs/futures/en/#all-orders-user_data

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if order_id is not None:
            payload["orderId"] = order_id
        if start_time is not None:
            payload["startTime"] = str(start_time)
        if end_time is not None:
            payload["endTime"] = str(end_time)
        if limit is not None:
            payload["limit"] = str(limit)
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "allOrders",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 12
0
 async def _submit_market_order(self, order: MarketOrder) -> None:
     await self._http_account.new_order(
         symbol=format_symbol(order.instrument_id.symbol.value),
         side=OrderSideParser.to_str_py(order.side),
         type="MARKET",
         quantity=str(order.quantity),
         new_client_order_id=order.client_order_id.value,
         recv_window=5000,
     )
Exemplo n.º 13
0
    def test_format_symbol(self):
        # Arrange
        symbol = "ethusdt-perp"

        # Act
        result = format_symbol(symbol)

        # Assert
        assert result == "ETHUSDT"
Exemplo n.º 14
0
    async def cancel_oco_order(
        self,
        symbol: str,
        order_list_id: Optional[str] = None,
        list_client_order_id: Optional[str] = None,
        new_client_order_id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Cancel an entire Order List.

        Either `order_list_id` or `list_client_order_id` must be provided.

        Cancel OCO (TRADE).
        `DELETE /api/v3/orderList`.

        Parameters
        ----------
        symbol : str
            The symbol for the request.
        order_list_id : str, optional
            The order list ID for the request.
        list_client_order_id : str, optional
            The list client order ID for the request.
        new_client_order_id : str, optional
            The new client order ID to uniquely identify this request.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#cancel-oco-trade

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if order_list_id is not None:
            payload["orderListId"] = order_list_id
        if list_client_order_id is not None:
            payload["listClientOrderId"] = list_client_order_id
        if new_client_order_id is not None:
            payload["newClientOrderId"] = new_client_order_id
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="DELETE",
            url_path=self.BASE_ENDPOINT + "orderList",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 15
0
    async def klines(
        self,
        symbol: str,
        interval: str,
        start_time_ms: Optional[int] = None,
        end_time_ms: Optional[int] = None,
        limit: Optional[int] = None,
    ) -> List[List[Any]]:
        """
        Kline/Candlestick Data.

        `GET /api/v3/klines`

        Parameters
        ----------
        symbol : str
            The trading pair.
        interval : str
            The interval of kline, e.g 1m, 5m, 1h, 1d, etc.
        start_time_ms : int, optional
            The UNIX timestamp (milliseconds) to get aggregate trades from INCLUSIVE.
        end_time_ms: int, optional
            The UNIX timestamp (milliseconds) to get aggregate trades until INCLUSIVE.
        limit : int, optional
            The limit for the response. Default 500; max 1000.

        Returns
        -------
        list[list[Any]]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data

        """
        payload: Dict[str, str] = {
            "symbol": format_symbol(symbol),
            "interval": interval,
        }
        if start_time_ms is not None:
            payload["startTime"] = str(start_time_ms)
        if end_time_ms is not None:
            payload["endTime"] = str(end_time_ms)
        if limit is not None:
            payload["limit"] = str(limit)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "klines",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 16
0
    async def agg_trades(
        self,
        symbol: str,
        from_id: Optional[int] = None,
        start_time_ms: Optional[int] = None,
        end_time_ms: Optional[int] = None,
        limit: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Get recent aggregated market trades.

        Compressed/Aggregate Trades List.
        `GET /api/v3/aggTrades`

        Parameters
        ----------
        symbol : str
            The trading pair.
        from_id : int, optional
            The trade ID to fetch from. Default gets most recent trades.
        start_time_ms : int, optional
            The UNIX timestamp (milliseconds) to get aggregate trades from INCLUSIVE.
        end_time_ms: int, optional
            The UNIX timestamp (milliseconds) to get aggregate trades until INCLUSIVE.
        limit : int, optional
            The limit for the response. Default 500; max 1000.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if from_id is not None:
            payload["fromId"] = str(from_id)
        if start_time_ms is not None:
            payload["startTime"] = str(start_time_ms)
        if end_time_ms is not None:
            payload["endTime"] = str(end_time_ms)
        if limit is not None:
            payload["limit"] = str(limit)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "aggTrades",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 17
0
 async def _submit_stop_limit_order(self, order: StopLimitOrder) -> None:
     await self._http_account.new_order(
         symbol=format_symbol(order.instrument_id.symbol.value),
         side=OrderSideParser.to_str_py(order.side),
         type=binance_order_type(order),
         time_in_force=TimeInForceParser.to_str_py(order.time_in_force),
         quantity=str(order.quantity),
         price=str(order.price),
         stop_price=str(order.trigger_price),
         iceberg_qty=str(order.display_qty) if order.display_qty is not None else None,
         new_client_order_id=order.client_order_id.value,
         recv_window=5000,
     )
Exemplo n.º 18
0
    async def get_order(
        self,
        symbol: str,
        order_id: Optional[str] = None,
        orig_client_order_id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> Optional[BinanceFuturesOrder]:
        """
        Check an order's status.

        Query Order (USER_DATA).
        `GET TBD`.

        Parameters
        ----------
        symbol : str
            The symbol for the request.
        order_id : str, optional
            The order ID for the request.
        orig_client_order_id : str, optional
            The original client order ID for the request.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        BinanceFuturesOrderMsg or None

        References
        ----------
        TBD

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if order_id is not None:
            payload["orderId"] = order_id
        if orig_client_order_id is not None:
            payload["origClientOrderId"] = orig_client_order_id
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "order",
            payload=payload,
        )
        if raw is None:
            return None

        return msgspec.json.decode(raw, type=BinanceFuturesOrder)
Exemplo n.º 19
0
    async def get_order(
        self,
        symbol: str,
        order_id: Optional[str] = None,
        orig_client_order_id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Check an order's status.

        Query Order (USER_DATA).
        `GET /api/v3/order`.

        Parameters
        ----------
        symbol : str
            The symbol for the request.
        order_id : str, optional
            The order ID for the request.
        orig_client_order_id : str, optional
            The original client order ID for the request.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#query-order-user_data

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if order_id is not None:
            payload["orderId"] = order_id
        if orig_client_order_id is not None:
            payload["origClientOrderId"] = orig_client_order_id
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "order",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 20
0
    async def _submit_limit_order(self, order: LimitOrder) -> None:
        time_in_force = TimeInForceParser.to_str_py(order.time_in_force)
        if order.is_post_only:
            time_in_force = "GTX"

        await self._http_account.new_order(
            symbol=format_symbol(order.instrument_id.symbol.value),
            side=OrderSideParser.to_str_py(order.side),
            type=binance_order_type(order),
            time_in_force=time_in_force,
            quantity=str(order.quantity),
            price=str(order.price),
            reduce_only=order.
            is_reduce_only,  # Cannot be sent with Hedge-Mode or closePosition
            new_client_order_id=order.client_order_id.value,
            recv_window=5000,
        )
Exemplo n.º 21
0
    async def historical_trades(
        self,
        symbol: str,
        from_id: Optional[int] = None,
        limit: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Get older market trades.

        Old Trade Lookup.
        `GET /api/v3/historicalTrades`

        Parameters
        ----------
        symbol : str
            The trading pair.
        from_id : int, optional
            The trade ID to fetch from. Default gets most recent trades.
        limit : int, optional
            The limit for the response. Default 500; max 1000.

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#old-trade-lookup

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if limit is not None:
            payload["limit"] = str(limit)
        if from_id is not None:
            payload["fromId"] = str(from_id)

        raw: bytes = await self.client.limit_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "historicalTrades",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 22
0
    async def exchange_info(
        self,
        symbol: str = None,
        symbols: List[str] = None,
    ) -> BinanceFuturesExchangeInfo:
        """
        Get current exchange trading rules and symbol information.
        Only either `symbol` or `symbols` should be passed.

        Exchange Information.
        `GET /api/v3/exchangeinfo`

        Parameters
        ----------
        symbol : str, optional
            The trading pair.
        symbols : List[str], optional
            The list of trading pairs.

        Returns
        -------
        BinanceFuturesExchangeInfo

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#exchange-information

        """
        if symbol and symbols:
            raise ValueError("`symbol` and `symbols` cannot be sent together")

        payload: Dict[str, str] = {}
        if symbol is not None:
            payload["symbol"] = format_symbol(symbol)
        if symbols is not None:
            payload["symbols"] = convert_symbols_list_to_json_array(symbols)

        raw: bytes = await self.client.query(
            url_path=self.BASE_ENDPOINT + "exchangeInfo",
            payload=payload,
        )

        return self._decoder_exchange_info.decode(raw)
Exemplo n.º 23
0
    async def get_position_risk(
        self,
        symbol: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> List[BinanceFuturesPositionRisk]:
        """
        Get current position information.

        Position Information V2 (USER_DATA)**

        `GET /fapi/v2/positionRisk`

        Parameters
        ----------
        symbol : str, optional
            The trading pair. If None then queries for all symbols.
        recv_window : int, optional
            The acceptable receive window for the response.

        Returns
        -------
        List[BinanceFuturesPositionRisk]

        References
        ----------
        https://binance-docs.github.io/apidocs/futures/en/#position-information-v2-user_data

        """
        payload: Dict[str, str] = {}
        if symbol is not None:
            payload["symbol"] = format_symbol(symbol)
        if recv_window is not None:
            payload["recv_window"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "positionRisk",
            payload=payload,
        )

        return self._decoder_position.decode(raw)
Exemplo n.º 24
0
    async def get_open_orders(
        self,
        symbol: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> List[Dict[str, Any]]:
        """
        Get all open orders for a symbol.

        Query Current Open Orders (USER_DATA).

        Parameters
        ----------
        symbol : str, optional
            The symbol for the request.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data
        https://binance-docs.github.io/apidocs/futures/en/#current-open-orders-user_data

        """
        payload: Dict[str, str] = {}
        if symbol is not None:
            payload["symbol"] = format_symbol(symbol)
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="GET",
            url_path=self.BASE_ENDPOINT + "openOrders",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 25
0
    async def cancel_open_orders(
        self,
        symbol: str,
        recv_window: Optional[int] = None,
    ) -> Dict[str, Any]:
        """
        Cancel all open orders for a symbol. This includes OCO orders.

        Cancel all Open Orders for a Symbol (TRADE).
        `DELETE /fapi/v1/allOpenOrders (HMAC SHA256)`.

        Parameters
        ----------
        symbol : str
            The symbol for the request.
        recv_window : int, optional
            The response receive window for the request (cannot be greater than 60000).

        Returns
        -------
        dict[str, Any]

        References
        ----------
        https://binance-docs.github.io/apidocs/spot/en/#cancel-all-open-orders-on-a-symbol-trade

        """
        payload: Dict[str, str] = {"symbol": format_symbol(symbol)}
        if recv_window is not None:
            payload["recvWindow"] = str(recv_window)

        raw: bytes = await self.client.sign_request(
            http_method="DELETE",
            url_path=self.BASE_ENDPOINT + "allOpenOrders",
            payload=payload,
        )

        return orjson.loads(raw)
Exemplo n.º 26
0
    async def _cancel_all_orders(self, command: CancelAllOrders) -> None:
        self._log.debug(f"Canceling all orders for {command.instrument_id.value}.")

        # Cancel all in-flight orders
        inflight_orders = self._cache.orders_inflight(
            instrument_id=command.instrument_id,
            strategy_id=command.strategy_id,
        )
        for order in inflight_orders:
            self.generate_order_pending_cancel(
                strategy_id=order.strategy_id,
                instrument_id=order.instrument_id,
                client_order_id=order.client_order_id,
                venue_order_id=order.venue_order_id,
                ts_event=self._clock.timestamp_ns(),
            )

        # Cancel all open orders
        open_orders = self._cache.orders_open(
            instrument_id=command.instrument_id,
            strategy_id=command.strategy_id,
        )
        for order in open_orders:
            self.generate_order_pending_cancel(
                strategy_id=order.strategy_id,
                instrument_id=order.instrument_id,
                client_order_id=order.client_order_id,
                venue_order_id=order.venue_order_id,
                ts_event=self._clock.timestamp_ns(),
            )

        try:
            await self._http_account.cancel_open_orders(
                symbol=format_symbol(command.instrument_id.symbol.value),
            )
        except BinanceError as ex:
            self._log.exception("Cannot cancel open orders: ", ex)
Exemplo n.º 27
0
    async def generate_trade_reports(  # noqa (C901 too complex)
        self,
        instrument_id: InstrumentId = None,
        venue_order_id: VenueOrderId = None,
        start: datetime = None,
        end: datetime = None,
    ) -> List[TradeReport]:
        """
        Generate a list of trade reports with optional query filters.

        The returned list may be empty if no trades match the given parameters.

        Parameters
        ----------
        instrument_id : InstrumentId, optional
            The instrument ID query filter.
        venue_order_id : VenueOrderId, optional
            The venue order ID (assigned by the venue) query filter.
        start : datetime, optional
            The start datetime query filter.
        end : datetime, optional
            The end datetime query filter.

        Returns
        -------
        list[TradeReport]

        """
        self._log.info(f"Generating TradeReports for {self.id}...")

        open_orders = self._cache.orders_open(venue=self.venue)
        active_symbols: Set[str] = {
            format_symbol(o.instrument_id.symbol.value) for o in open_orders
        }

        reports_raw: List[Dict[str, Any]] = []
        reports: List[TradeReport] = []

        try:
            for symbol in active_symbols:
                response = await self._http_account.get_account_trades(
                    symbol=symbol,
                    start_time=int(start.timestamp() * 1000) if start is not None else None,
                    end_time=int(end.timestamp() * 1000) if end is not None else None,
                )
                reports_raw.extend(response)
        except BinanceError as ex:
            self._log.exception("Cannot generate trade report: ", ex)
            return []

        for data in reports_raw:
            # Apply filter
            # TODO(cs): Time filter is WIP
            # timestamp = pd.to_datetime(data["time"], utc=True)
            # if start is not None and timestamp < start:
            #     continue
            # if end is not None and timestamp > end:
            #     continue

            report: TradeReport = parse_trade_report_http(
                account_id=self.account_id,
                instrument_id=self._get_cached_instrument_id(data["symbol"]),
                data=data,
                report_id=self._uuid_factory.generate(),
                ts_init=self._clock.timestamp_ns(),
            )

            self._log.debug(f"Received {report}.")
            reports.append(report)

        # Sort in ascending order
        reports = sorted(reports, key=lambda x: x.trade_id)

        len_reports = len(reports)
        plural = "" if len_reports == 1 else "s"
        self._log.info(f"Generated {len(reports)} TradeReport{plural}.")

        return reports
Exemplo n.º 28
0
    async def generate_order_status_reports(  # noqa (C901 too complex)
        self,
        instrument_id: InstrumentId = None,
        start: datetime = None,
        end: datetime = None,
        open_only: bool = False,
    ) -> List[OrderStatusReport]:
        """
        Generate a list of order status reports with optional query filters.

        The returned list may be empty if no orders match the given parameters.

        Parameters
        ----------
        instrument_id : InstrumentId, optional
            The instrument ID query filter.
        start : datetime, optional
            The start datetime query filter.
        end : datetime, optional
            The end datetime query filter.
        open_only : bool, default False
            If the query is for open orders only.

        Returns
        -------
        list[OrderStatusReport]

        """
        self._log.info(f"Generating OrderStatusReports for {self.id}...")

        open_orders = self._cache.orders_open(venue=self.venue)
        active_symbols: Set[str] = {
            format_symbol(o.instrument_id.symbol.value) for o in open_orders
        }

        order_msgs = []
        reports: Dict[VenueOrderId, OrderStatusReport] = {}

        try:
            open_order_msgs: List[Dict[str, Any]] = await self._http_account.get_open_orders(
                symbol=instrument_id.symbol.value if instrument_id is not None else None,
            )
            if open_order_msgs:
                order_msgs.extend(open_order_msgs)
                # Add to active symbols
                for o in open_order_msgs:
                    active_symbols.add(o["symbol"])

            for symbol in active_symbols:
                response = await self._http_account.get_orders(
                    symbol=symbol,
                    start_time=int(start.timestamp() * 1000) if start is not None else None,
                    end_time=int(end.timestamp() * 1000) if end is not None else None,
                )
                order_msgs.extend(response)
        except BinanceError as ex:
            self._log.exception("Cannot generate order status report: ", ex)
            return []

        for msg in order_msgs:
            # Apply filter (always report open orders regardless of start, end filter)
            # TODO(cs): Time filter is WIP
            # timestamp = pd.to_datetime(data["time"], utc=True)
            # if data["status"] not in ("NEW", "PARTIALLY_FILLED", "PENDING_CANCEL"):
            #     if start is not None and timestamp < start:
            #         continue
            #     if end is not None and timestamp > end:
            #         continue

            report: OrderStatusReport = parse_order_report_http(
                account_id=self.account_id,
                instrument_id=self._get_cached_instrument_id(msg["symbol"]),
                data=msg,
                report_id=self._uuid_factory.generate(),
                ts_init=self._clock.timestamp_ns(),
            )

            self._log.debug(f"Received {report}.")
            reports[report.venue_order_id] = report  # One report per order

        len_reports = len(reports)
        plural = "" if len_reports == 1 else "s"
        self._log.info(f"Generated {len(reports)} OrderStatusReport{plural}.")

        return list(reports.values())
Exemplo n.º 29
0
    async def generate_trade_reports(  # noqa (C901 too complex)
        self,
        instrument_id: InstrumentId = None,
        venue_order_id: VenueOrderId = None,
        start: datetime = None,
        end: datetime = None,
    ) -> List[TradeReport]:
        """
        Generate a list of trade reports with optional query filters.

        The returned list may be empty if no trades match the given parameters.

        Parameters
        ----------
        instrument_id : InstrumentId, optional
            The instrument ID query filter.
        venue_order_id : VenueOrderId, optional
            The venue order ID (assigned by the venue) query filter.
        start : datetime, optional
            The start datetime query filter.
        end : datetime, optional
            The end datetime query filter.

        Returns
        -------
        list[TradeReport]

        """
        self._log.info(f"Generating TradeReports for {self.id}...")

        # Check cache for all active symbols
        open_orders: List[Order] = self._cache.orders_open(venue=self.venue)
        open_positions: List[Position] = self._cache.positions_open(
            venue=self.venue)

        active_symbols: Set[str] = set()
        for o in open_orders:
            active_symbols.add(format_symbol(o.instrument_id.symbol.value))
        for p in open_positions:
            active_symbols.add(format_symbol(p.instrument_id.symbol.value))

        binance_trades: List[BinanceFuturesAccountTrade] = []
        reports: List[TradeReport] = []

        try:
            # Check Binance for all active positions
            binance_positions: List[BinanceFuturesPositionRisk]
            binance_positions = await self._http_account.get_position_risk()
            for data in binance_positions:
                if Decimal(data.positionAmt) == 0:
                    continue  # Flat position
                # Add active symbol
                active_symbols.add(data.symbol)

            # Check Binance for trades on all active symbols
            for symbol in active_symbols:
                symbol_trades = await self._http_account.get_account_trades(
                    symbol=symbol,
                    start_time=int(start.timestamp() *
                                   1000) if start is not None else None,
                    end_time=int(end.timestamp() *
                                 1000) if end is not None else None,
                )
                binance_trades.extend(symbol_trades)
        except BinanceError as ex:
            self._log.exception("Cannot generate trade report: ", ex)
            return []

        # Parse all Binance trades
        for data in binance_trades:
            report = parse_trade_report_http(
                account_id=self.account_id,
                instrument_id=self._get_cached_instrument_id(data.symbol),
                data=data,
                report_id=self._uuid_factory.generate(),
                ts_init=self._clock.timestamp_ns(),
            )

            self._log.debug(f"Received {report}.")
            reports.append(report)

        # Confirm sorting in ascending order
        reports = sorted(reports, key=lambda x: x.trade_id)

        len_reports = len(reports)
        plural = "" if len_reports == 1 else "s"
        self._log.info(f"Generated {len(reports)} TradeReport{plural}.")

        return reports
Exemplo n.º 30
0
    async def generate_order_status_reports(  # noqa (C901 too complex)
        self,
        instrument_id: InstrumentId = None,
        start: datetime = None,
        end: datetime = None,
        open_only: bool = False,
    ) -> List[OrderStatusReport]:
        """
        Generate a list of order status reports with optional query filters.

        The returned list may be empty if no orders match the given parameters.

        Parameters
        ----------
        instrument_id : InstrumentId, optional
            The instrument ID query filter.
        start : datetime, optional
            The start datetime query filter.
        end : datetime, optional
            The end datetime query filter.
        open_only : bool, default False
            If the query is for open orders only.

        Returns
        -------
        list[OrderStatusReport]

        """
        self._log.info(f"Generating OrderStatusReports for {self.id}...")

        # Check cache for all active symbols
        open_orders: List[Order] = self._cache.orders_open(venue=self.venue)
        open_positions: List[Position] = self._cache.positions_open(
            venue=self.venue)

        active_symbols: Set[str] = set()
        for o in open_orders:
            active_symbols.add(format_symbol(o.instrument_id.symbol.value))
        for p in open_positions:
            active_symbols.add(format_symbol(p.instrument_id.symbol.value))

        binance_orders: List[BinanceFuturesOrder] = []
        reports: Dict[VenueOrderId, OrderStatusReport] = {}

        try:
            # Check Binance for all active positions
            binance_positions: List[BinanceFuturesPositionRisk]
            binance_positions = await self._http_account.get_position_risk()
            for data in binance_positions:
                if Decimal(data.positionAmt) == 0:
                    continue  # Flat position
                # Add active symbol
                active_symbols.add(data.symbol)

            # Check Binance for all open orders
            binance_open_orders: List[BinanceFuturesOrder]
            binance_open_orders = await self._http_account.get_open_orders(
                symbol=instrument_id.symbol.value
                if instrument_id is not None else None, )
            binance_orders.extend(binance_open_orders)
            # Add active symbol
            for data in binance_orders:
                active_symbols.add(data.symbol)

            # Check Binance for all orders for active symbols
            for symbol in active_symbols:
                response = await self._http_account.get_orders(
                    symbol=symbol,
                    start_time=int(start.timestamp() *
                                   1000) if start is not None else None,
                    end_time=int(end.timestamp() *
                                 1000) if end is not None else None,
                )
                binance_orders.extend(response)
        except BinanceError as ex:
            self._log.exception("Cannot generate order status report: ", ex)
            return []

        # Parse all Binance orders
        for data in binance_orders:
            report = parse_order_report_http(
                account_id=self.account_id,
                instrument_id=self._get_cached_instrument_id(data.symbol),
                data=data,
                report_id=self._uuid_factory.generate(),
                ts_init=self._clock.timestamp_ns(),
            )

            self._log.debug(f"Received {report}.")
            reports[report.venue_order_id] = report  # One report per order

        len_reports = len(reports)
        plural = "" if len_reports == 1 else "s"
        self._log.info(f"Generated {len(reports)} OrderStatusReport{plural}.")

        return list(reports.values())