Portoflio : add pa export command for Degiro (#2065)

* Portoflio : add pa export command for Degiro

* Update controller + tests

* Tests

* Degiro : update pa export format

* Fixing Premium

* Black

* Show index
This commit is contained in:
Chavithra
2022-07-12 19:38:34 +02:00
committed by GitHub
parent 4c0b1135a9
commit 0dfd53f28a
7 changed files with 192 additions and 1 deletions

1
i18n/en.yml vendored
View File

@@ -1014,6 +1014,7 @@ en:
portfolio/bro/degiro/companynews: view news about a company with it's isin
portfolio/bro/degiro/lastnews: view latest news
portfolio/bro/degiro/topnews: view top news preview
portfolio/bro/degiro/paexport: csv export for portfolio analysis
portfolio/bro/rh/login: login to robinhood
portfolio/bro/rh/holdings: show account holdings in stocks
portfolio/bro/rh/history: show equity history of your account

View File

@@ -1,5 +1,6 @@
# IMPORTATION STANDARD
import argparse
import datetime
import logging
from typing import List
@@ -9,6 +10,10 @@ from prompt_toolkit.completion import NestedCompleter
# IMPORTATION INTERNAL
from openbb_terminal import feature_flags as obbff
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import (
EXPORT_ONLY_RAW_DATA_ALLOWED,
valid_date,
)
from openbb_terminal.menu import session
from openbb_terminal.parent_classes import BaseController
from openbb_terminal.portfolio.brokers.degiro.degiro_view import DegiroView
@@ -31,6 +36,7 @@ class DegiroController(BaseController):
"pending",
"topnews",
"update",
"paexport",
]
PATH = "/portfolio/bro/degiro/"
@@ -307,3 +313,42 @@ class DegiroController(BaseController):
ns_parser = self.parse_known_args_and_warn(parser, other_args)
self.__degiro_view.update(ns_parser=ns_parser)
@log_start_end(log=logger)
def call_paexport(self, other_args: List[str]):
"""Export transactions for Portfolio Analysis Menu into CSV format."""
# PARSING ARGS
parser = argparse.ArgumentParser(
add_help=False,
prog="paexport",
)
parser.add_argument(
"-s",
"--start",
help="Start date.",
required=True,
type=valid_date,
)
parser.add_argument(
"-e",
"--end",
help="End date.",
type=valid_date,
default=datetime.datetime.now(),
)
parser.add_argument(
"-c",
"--currency",
help="Used currency.",
default="USD",
type=str,
)
ns_parser = self.parse_known_args_and_warn(
parser,
other_args,
export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED,
)
if ns_parser:
self.__degiro_view.transactions_export(ns_parser=ns_parser)

View File

@@ -1,7 +1,8 @@
# IMPORTATION STANDARD
import datetime
import logging
import math
from typing import Union
from typing import List, Union
# IMPORTATION THIRDPARTY
import pandas as pd
@@ -15,6 +16,7 @@ from degiro_connector.trading.models.trading_pb2 import (
ProductSearch,
ProductsInfo,
TopNewsPreview,
TransactionsHistory,
Update,
)
@@ -336,3 +338,103 @@ class DegiroModel:
return None
else:
return None
@log_start_end(log=logger)
def get_transactions(
self, start: datetime.date, end: datetime.date
) -> pd.DataFrame:
trading_api = self.__trading_api
from_date = TransactionsHistory.Request.Date(
year=start.year,
month=start.month,
day=start.day,
)
to_date = TransactionsHistory.Request.Date(
year=end.year,
month=end.month,
day=end.day,
)
request = TransactionsHistory.Request(
from_date=from_date,
to_date=to_date,
)
transactions_dict = trading_api.get_transactions_history(
request=request,
raw=True,
)
transactions_df = pd.DataFrame(transactions_dict["data"])
transactions_df["productId"] = transactions_df["productId"].astype("int")
return transactions_df
@log_start_end(log=logger)
def get_products_details(self, product_id_list: List[int]) -> pd.DataFrame:
trading_api = self.__trading_api
product_id_list = list(set(product_id_list))
request = ProductsInfo.Request()
request.products.extend(product_id_list)
products_info = trading_api.get_products_info(
request=request,
raw=True,
)
products_df = pd.DataFrame(products_info["data"].values())
return products_df
@log_start_end(log=logger)
def get_transactions_export(
self, start: datetime.date, end: datetime.date, currency: str
) -> pd.DataFrame:
transactions_df = self.get_transactions(start=start, end=end)
product_id_list = list(transactions_df.productId)
products_df = self.get_products_details(product_id_list=product_id_list)
products_df["productId"] = products_df["id"]
transactions_df["productId"] = transactions_df["productId"].astype("int")
products_df["productId"] = products_df["productId"].astype("int")
transactions_full_df = pd.merge(
transactions_df,
products_df[{"productId", "symbol", "productType"}],
on="productId",
)
portfolio_df = transactions_full_df.rename(
columns={
"date": "Date",
"symbol": "Ticker",
"productType": "Type", # STOCK or ETF
"price": "Price",
"quantity": "Quantity",
"buysell": "Side", # BUY or SELL
"totalFeesInBaseCurrency": "Fees",
}
)
portfolio_df["Premium"] = 0
portfolio_df["Currency"] = currency
portfolio_df["Side"] = portfolio_df["Side"].replace({"S": "SELL", "B": "BUY"})
portfolio_df["Date"] = pd.to_datetime(
portfolio_df["Date"].str.slice(0, 10)
).dt.date
columns = [
"Date",
"Ticker",
"Type",
"Price",
"Quantity",
"Fees",
"Premium",
"Side",
"Currency",
]
portfolio_df = portfolio_df[columns]
portfolio_df = portfolio_df.set_index("Date")
return portfolio_df

View File

@@ -1,6 +1,7 @@
# IMPORTATION THIRDPARTY
import logging
from argparse import Namespace
from pathlib import Path
# IMPORTATION THIRDPARTY
import pandas as pd
@@ -19,6 +20,10 @@ from openbb_terminal.decorators import log_start_end
from openbb_terminal.decorators import check_api_key
# IMPORTATION INTERNAL
from openbb_terminal.helper_funcs import (
export_data,
print_rich_table,
)
from openbb_terminal.portfolio.brokers.degiro.degiro_model import DegiroModel
from openbb_terminal.rich_config import console, MenuText
@@ -68,6 +73,7 @@ class DegiroView:
mt.add_cmd("companynews")
mt.add_cmd("lastnews")
mt.add_cmd("topnews")
mt.add_cmd("paexport")
console.print(text=mt.menu_text, menu="Portfolio - Brokers - Degiro")
@log_start_end(log=logger)
@@ -489,3 +495,29 @@ class DegiroView:
@log_start_end(log=logger)
def __update_display_success():
console.print("`Order` updated .")
@log_start_end(log=logger)
def transactions_export(self, ns_parser: Namespace):
degiro_model = self.__degiro_model
portfolio_df = degiro_model.get_transactions_export(
start=ns_parser.start.date(),
end=ns_parser.end.date(),
currency=ns_parser.currency,
)
if portfolio_df is not None:
print_rich_table(
df=portfolio_df,
headers=list(portfolio_df.columns),
show_index=True,
title="Degiro Transactions",
)
export_data(
export_type=ns_parser.export,
dir_path=str(Path(__file__).parent.parent.parent.absolute()),
func_name="paexport",
df=portfolio_df,
)
else:
console.print("Error while fetching or processing Transactions.")

View File

@@ -289,6 +289,15 @@ def test_call_func_expect_queue(expected_queue, func, queue):
[],
dict(),
),
(
"call_paexport",
[
"--start=2022-01-01",
],
"DegiroView.transactions_export",
[],
dict(),
),
],
)
def test_call_func(

View File

@@ -12,4 +12,5 @@
companynews view news about a company with it's isin
lastnews view latest news
topnews view top news preview
paexport csv export for portfolio analysis

View File

@@ -12,4 +12,5 @@
companynews view news about a company with it's isin
lastnews view latest news
topnews view top news preview
paexport csv export for portfolio analysis