class DegiroModel:
    def __init__(self):
        self.__default_credentials = Credentials(
            int_account=None,
            username=config.DG_USERNAME,
            password=config.DG_PASSWORD,
            one_time_password=None,
            totp_secret_key=config.DG_TOTP_SECRET,
        )
        self.__trading_api = TradingAPI(
            credentials=self.__default_credentials, )

    def __hold_fetch_additional_information(
        self,
        positions: pd.DataFrame,
    ) -> pd.DataFrame:
        """Fetch extra information about the positions like :
            - name
            - isin
            - symbol
            - ...

        Parameters
        ----------
        positions : pd.DataFrame
            Positions from which we want extra fields.

        Returns
        -------
        pd.DataFrame
            Positions with additional data.
        """

        # GET ATTRIBUTES
        trading_api = self.__trading_api

        # EXTRACT POSITIONS IDS
        positions_ids = positions["id"].astype("int32").tolist()

        # FETCH EXTRA DATA
        request = ProductsInfo.Request()
        request.products.extend(positions_ids)
        products_info_pb = trading_api.get_products_info(
            request=request,
            raw=False,
        )

        # CONVERT TO DICT
        products_info_dict = payload_handler.message_to_dict(
            message=products_info_pb, )

        # CONVERT TO DATAFRAME
        products_info = pd.DataFrame(products_info_dict["values"].values())

        # MERGE DATA WITH POSITIONS
        positions_full = pd.merge(positions, products_info, on="id")

        return positions_full

    def __hold_fetch_current_positions(self) -> pd.DataFrame:
        # GET ATTRIBUTES
        trading_api = self.__trading_api

        # FETCH HELD PRODUCTS
        request_list = Update.RequestList()
        request_list.values.extend([
            Update.Request(
                option=Update.Option.PORTFOLIO,
                last_updated=0,
            ),
        ])

        update_pb = trading_api.get_update(
            request_list=request_list,
            raw=False,
        )

        # CHECK EMPTINESS
        if len(update_pb.portfolio.values) == 0:
            return pd.DataFrame()
        else:
            positions_partial = self.__hold_filter_current_positions(
                portfolio=update_pb.portfolio, )

            # FETCH ADDITIONAL DATA ON PRODUCTS
            positions = self.__hold_fetch_additional_information(
                positions=positions_partial, )

            return positions

    @staticmethod
    def __hold_filter_current_positions(
        portfolio: Update.Portfolio, ) -> pd.DataFrame:
        """Filter the positions in order to keep only held ones.

        Parameters
        ----------
        portfolio : Update.Portfolio
            Portfolio returned from the API.

        Returns
        -------
        pd.DataFrame
            Filtered portfolio.
        """

        # CONVERT TO DATAFRAME
        portfolio_dict = payload_handler.message_to_dict(message=portfolio)
        positions = pd.DataFrame(portfolio_dict["values"])

        # SETUP MASK
        mask_product = positions["positionType"] == "PRODUCT"
        mask_not_empty = positions["size"] > 0
        mask_current_position = mask_product & mask_not_empty

        # FILTER
        positions = positions[mask_current_position]

        return positions

    def __setup_extra_credentials(self):
        trading_api = self.__trading_api
        client_details_table = trading_api.get_client_details()
        int_account = client_details_table["data"]["intAccount"]
        trading_api.credentials.int_account = int_account

    def cancel(self, order_id: str) -> bool:
        return self.__trading_api.delete_order(order_id=order_id)

    def companynews(self, isin: str) -> NewsByCompany:
        trading_api = self.__trading_api
        request = NewsByCompany.Request(
            isin=isin,
            limit=10,
            offset=0,
            languages="en,fr",
        )

        # FETCH DATA
        news = trading_api.get_news_by_company(
            request=request,
            raw=False,
        )

        return news

    def create_calculate_product_id(
        self,
        product: int,
        symbol: str,
    ) -> Union[int, None]:
        trading_api = self.__trading_api

        if product is None:
            request_lookup = ProductSearch.RequestLookup(
                search_text=symbol,
                limit=1,
                offset=0,
                product_type_id=1,
            )

            products_lookup = trading_api.product_search(
                request=request_lookup,
                raw=False,
            )
            products_lookup_dict = payload_handler.message_to_dict(
                message=products_lookup, )
            product = products_lookup_dict["products"][0]

            if len(products_lookup.products
                   ) <= 0 or product["symbol"] != symbol:
                return None
            else:
                return int(product["id"])
        else:
            return product

    def create_calculate_size(
        self,
        price: float,
        size: int,
        up_to: float,
    ):
        if size is None:
            return math.floor(up_to / price)
        else:
            return size

    def create_check(self,
                     order: Order) -> Union[Order.CheckingResponse, bool]:
        return self.__trading_api.check_order(order=order)

    def create_confirm(
        self,
        confirmation_id: str,
        order: Order,
    ) -> Union[Order.ConfirmationResponse, bool]:
        return self.__trading_api.confirm_order(
            confirmation_id=confirmation_id,
            order=order,
        )

    def hold_positions(self) -> pd.DataFrame:
        return self.__hold_fetch_current_positions()

    def lastnews(self, limit: int) -> LatestNews:
        trading_api = self.__trading_api
        request = LatestNews.Request(
            offset=0,
            languages="en,fr",
            limit=limit,
        )
        news = trading_api.get_latest_news(request=request, raw=False)

        return news

    def login(self, credentials: Credentials):
        self.__trading_api = TradingAPI(credentials=credentials)
        self.__trading_api.connect()
        self.__setup_extra_credentials()

    def login_default_credentials(self):
        return self.__default_credentials

    def logout(self) -> bool:
        return self.__trading_api.logout()

    def lookup(
        self,
        limit: int,
        offset: int,
        search_text: str,
    ) -> ProductSearch:
        trading_api = self.__trading_api
        request_lookup = ProductSearch.RequestLookup(
            search_text=search_text,
            limit=limit,
            offset=offset,
        )
        product_search = trading_api.product_search(
            request=request_lookup,
            raw=False,
        )

        return product_search

    def pending(self) -> Update.Orders:
        trading_api = self.__trading_api
        request_list = Update.RequestList()
        request_list.values.extend([
            Update.Request(option=Update.Option.ORDERS, last_updated=0),
        ])
        update = trading_api.get_update(request_list=request_list)

        return update.orders

    def topnews(self) -> TopNewsPreview:
        return self.__trading_api.get_top_news_preview(raw=False)

    def update(self, order: Order) -> Update.Orders:
        return self.__trading_api.update_order(order=order)

    def update_pending_order(self, order_id: str) -> Union[None, Order]:
        trading_api = self.__trading_api
        request_list = Update.RequestList()
        request_list.values.extend([
            Update.Request(option=Update.Option.ORDERS, last_updated=0),
        ])
        update = trading_api.get_update(request_list=request_list)

        if len(update.orders.values) > 0:
            for order in update.orders.values:
                if order.id == order_id:
                    return order
            return None
        else:
            return None
Beispiel #2
0
# SETUP CREDENTIALS
int_account = config_dict['int_account']
username = config_dict['username']
password = config_dict['password']
credentials = Credentials(
    int_account=int_account,
    username=username,
    password=password,
)

# SETUP TRADING API
trading_api = TradingAPI(credentials=credentials)

# CONNECT
trading_api.connect()

# SETUP REQUEST
today = datetime.date.today()
from_date = CashAccountReport.Request.Date(
    year=2020,
    month=1,
    day=1,
)
to_date = CashAccountReport.Request.Date(
    year=today.year,
    month=today.month,
    day=today.day,
)
request = CashAccountReport.Request(
    format=CashAccountReport.Format.CSV,
def trading_api(credentials) -> TradingAPI:
    trading_api = TradingAPI(credentials=credentials)
    trading_api.connect()

    return trading_api