diff --git a/src/investir/cli.py b/src/investir/cli.py
index d167f6c..d1b9e6b 100644
--- a/src/investir/cli.py
+++ b/src/investir/cli.py
@@ -18,6 +18,7 @@
)
from investir.logging import configure_logger
from investir.parser import ParserFactory
+from investir.prettytable import OutputFormat
from investir.taxcalculator import TaxCalculator
from investir.transaction import Acquisition, Disposal, Transaction
from investir.trhistory import TrHistory
@@ -72,6 +73,12 @@ def __init__(self, opt1: str, opt2: str) -> None:
]
+OutputFormatOpt = Annotated[
+ OutputFormat,
+ typer.Option("--output", "-o", help="Output format."),
+]
+
+
def abort(message: str) -> None:
logger.critical(message)
raise typer.Exit(code=1)
@@ -230,7 +237,7 @@ def main_callback( # noqa: PLR0913
@app.command("orders")
-def orders_command(
+def orders_command( # noqa: PLR0913
files: FilesArg,
tax_year: TaxYearOpt = None,
ticker: TickerOpt = None,
@@ -240,6 +247,7 @@ def orders_command(
disposals_only: Annotated[
bool, typer.Option("--disposals", help="Show only disposals.")
] = False,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
) -> None:
"""
Show share buy/sell orders.
@@ -257,7 +265,7 @@ def orders_command(
filters = create_filters(tax_year=tax_year, ticker=ticker, tr_type=tr_type)
if table := tr_hist.get_orders_table(filters):
- print(table.to_string(leading_nl=config.logging_enabled))
+ print(table.to_string(output_format, leading_nl=config.logging_enabled))
@app.command("dividends")
@@ -265,6 +273,7 @@ def dividends_command(
files: FilesArg,
tax_year: TaxYearOpt = None,
ticker: TickerOpt = None,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
) -> None:
"""
Show share dividends paid out.
@@ -272,7 +281,7 @@ def dividends_command(
tr_hist, _ = parse(files)
filters = create_filters(tax_year=tax_year, ticker=ticker)
if table := tr_hist.get_dividends_table(filters):
- print(table.to_string(leading_nl=config.logging_enabled))
+ print(table.to_string(output_format, leading_nl=config.logging_enabled))
@app.command("transfers")
@@ -285,6 +294,7 @@ def transfers_command(
withdrawals_only: Annotated[
bool, typer.Option("--withdrawals", help="Show only withdrawals.")
] = False,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
) -> None:
"""
Show cash deposits and cash withdrawals.
@@ -303,22 +313,26 @@ def transfers_command(
filters = create_filters(tax_year=tax_year, amount_op=amount_op)
if table := tr_hist.get_transfers_table(filters):
- print(table.to_string(leading_nl=config.logging_enabled))
+ print(table.to_string(output_format, leading_nl=config.logging_enabled))
@app.command("interest")
-def interest_command(files: FilesArg, tax_year: TaxYearOpt = None) -> None:
+def interest_command(
+ files: FilesArg,
+ tax_year: TaxYearOpt = None,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
+) -> None:
"""
Show interest earned on cash.
"""
tr_hist, _ = parse(files)
filters = create_filters(tax_year=tax_year)
if table := tr_hist.get_interest_table(filters):
- print(table.to_string(leading_nl=config.logging_enabled))
+ print(table.to_string(output_format, leading_nl=config.logging_enabled))
@app.command("capital-gains")
-def capital_gains_command(
+def capital_gains_command( # noqa: PLR0913
files: FilesArg,
gains_only: Annotated[
bool, typer.Option("--gains", help="Show only capital gains.")
@@ -328,6 +342,7 @@ def capital_gains_command(
] = False,
tax_year: TaxYearOpt = None,
ticker: TickerOpt = None,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
) -> None:
"""
Show capital gains report.
@@ -335,6 +350,12 @@ def capital_gains_command(
if gains_only and losses_only:
raise MutuallyExclusiveOption("--gains", "--losses")
+ if output_format != OutputFormat.TEXT and tax_year is None:
+ raise click.exceptions.UsageError(
+ f"The {output_format.value} format requires the option "
+ f"--tax-year to be used"
+ )
+
_, tax_calculator = parse(files)
tax_year = Year(tax_year) if tax_year else None
ticker = Ticker(ticker) if ticker else None
@@ -354,10 +375,16 @@ def capital_gains_command(
if table:
print(end="\n" if tax_year_idx == 0 and config.logging_enabled else "")
- print(boldify(f"Capital Gains Tax Report {tax_year_short_date(tax_year)}"))
- print(tax_year_full_date(tax_year))
- print(table.to_string(leading_nl=True))
- print(summary)
+
+ if output_format == OutputFormat.TEXT:
+ print(
+ boldify(f"Capital Gains Tax Report {tax_year_short_date(tax_year)}")
+ )
+ print(tax_year_full_date(tax_year))
+ print(table.to_string(output_format))
+ print(summary)
+ else:
+ print(table.to_string(output_format, leading_nl=False))
@app.command("holdings")
@@ -367,6 +394,7 @@ def holdings_command(
show_gain_loss: Annotated[
bool, typer.Option("--show-gain-loss", help="Show unrealised gain/loss.")
] = False,
+ output_format: OutputFormatOpt = OutputFormat.TEXT,
) -> None:
"""
Show current holdings.
@@ -374,7 +402,7 @@ def holdings_command(
_, tax_calculator = parse(files)
ticker = Ticker(ticker) if ticker else None
if table := tax_calculator.get_holdings_table(ticker, show_gain_loss):
- print(table.to_string(leading_nl=config.logging_enabled))
+ print(table.to_string(output_format, leading_nl=config.logging_enabled))
def main() -> None:
diff --git a/src/investir/prettytable.py b/src/investir/prettytable.py
index 445529b..35eb883 100644
--- a/src/investir/prettytable.py
+++ b/src/investir/prettytable.py
@@ -1,6 +1,7 @@
from collections.abc import Callable
from datetime import date
from decimal import Decimal
+from enum import Enum
from typing import Any
import prettytable
@@ -8,6 +9,13 @@
from investir.utils import boldify, unboldify
+class OutputFormat(str, Enum):
+ TEXT = "text"
+ CSV = "csv"
+ JSON = "json"
+ HTML = "html"
+
+
def date_format(format: str) -> Callable[[str, Any], str]:
def _date_format(_field, val) -> str:
if isinstance(val, date):
@@ -31,12 +39,41 @@ def _decimal_format(_field, val) -> str:
class PrettyTable(prettytable.PrettyTable):
def __init__(self, *args, **kwargs) -> None:
- kwargs["field_names"] = list(map(lambda f: boldify(f), kwargs["field_names"]))
-
super().__init__(*args, **kwargs)
+ self.hrules = prettytable.HEADER
+ self.vrules = prettytable.NONE
+ self.invisible_fields: set[str] = set()
+
+ def hide_field(self, field_name: str) -> None:
+ self.invisible_fields.add(field_name)
+
+ def to_string(self, output_format: OutputFormat, leading_nl: bool = True) -> str:
+ self._apply_formatting(output_format == OutputFormat.TEXT)
+
+ leading = "\n" if leading_nl else ""
+ trailing = "\n" if output_format == OutputFormat.TEXT else ""
+
+ fields = [
+ f for f in self.field_names if unboldify(f) not in self.invisible_fields
+ ]
+
+ kwargs: dict[str, Any] = {"fields": fields}
+ if output_format == OutputFormat.JSON:
+ kwargs["default"] = str
+
+ table_str = self.get_formatted_string(output_format.value, **kwargs)
+
+ if output_format == OutputFormat.CSV:
+ table_str = table_str.rstrip()
+
+ return f"{leading}{table_str}{trailing}"
+
+ def _apply_formatting(self, bold_titles: bool) -> None:
+ if bold_titles:
+ self.field_names = list(map(lambda f: boldify(f), self.field_names))
for f in self.field_names:
- plain_f = unboldify(f)
+ plain_f = unboldify(f) if bold_titles else f
match plain_f.split()[0].strip(), plain_f.split()[-1]:
case ("Date", _) | (_, "Date"):
@@ -53,21 +90,5 @@ def __init__(self, *args, **kwargs) -> None:
case _:
self.align[f] = "l"
- self.hrules = prettytable.HEADER
- self.vrules = prettytable.NONE
- self.invisible_fields: set[str] = set()
-
- def hide_field(self, field_name: str) -> None:
- self.invisible_fields.add(field_name)
-
- def to_string(self, leading_nl: bool = True) -> str:
- nl = "\n" if leading_nl else ""
-
- fields = [
- f for f in self.field_names if unboldify(f) not in self.invisible_fields
- ]
-
- return f"{nl}{self.get_string(fields=fields)}\n"
-
def __bool__(self) -> bool:
return len(self.rows) > 0
diff --git a/tests/test_cli.py b/tests/test_cli.py
index cf05e2d..bc4bdfb 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -109,6 +109,31 @@ def _execute(
# Holdings
("holdings", "holdings"),
("holdings --ticker SWKS", "holdings_swks"),
+ # Output formats
+ ("orders --output text", "orders"),
+ ("orders --output csv", "orders_csv"),
+ ("orders --output json", "orders_json"),
+ ("orders --output html", "orders_html"),
+ ("dividends --output text", "dividends"),
+ ("dividends --output csv", "dividends_csv"),
+ ("dividends --output json", "dividends_json"),
+ ("dividends --output html", "dividends_html"),
+ ("interest --output text", "interest"),
+ ("interest --output csv", "interest_csv"),
+ ("interest --output json", "interest_json"),
+ ("interest --output html", "interest_html"),
+ ("transfers --output text", "transfers"),
+ ("transfers --output csv", "transfers_csv"),
+ ("transfers --output json", "transfers_json"),
+ ("transfers --output html", "transfers_html"),
+ ("capital-gains --output text", "capital_gains"),
+ ("capital-gains --tax-year 2022 --output csv", "capital_gains_csv"),
+ ("capital-gains --tax-year 2022 --output json", "capital_gains_json"),
+ ("capital-gains --tax-year 2022 --output html", "capital_gains_html"),
+ ("holdings --output text", "holdings"),
+ ("holdings --output csv", "holdings_csv"),
+ ("holdings --output json", "holdings_json"),
+ ("holdings --output html", "holdings_html"),
]
@@ -210,6 +235,13 @@ def test_capital_gains_command_mutually_exclusive_filters(execute):
assert result.exit_code != EX_OK
+def test_capital_gains_command_tax_year_required(execute):
+ result = execute(["capital-gains", "--output", "json", DATA_FILE])
+ assert not result.stdout
+ assert "Usage:" in result.stderr
+ assert result.exit_code != EX_OK
+
+
def test_invocation_without_any_argument(execute):
result = execute([], global_opts=[])
assert not result.stderr
diff --git a/tests/test_cli/capital_gains_csv b/tests/test_cli/capital_gains_csv
new file mode 100644
index 0000000..9e0d5b5
--- /dev/null
+++ b/tests/test_cli/capital_gains_csv
@@ -0,0 +1,5 @@
+Disposal Date,Identification,Security Name,ISIN,Quantity,Cost (£),Proceeds (£),Gain/loss (£)
+2022-09-20,Section 104,Amazon,US0231351067,48.31896981,3493.12,4941.53,1448.41
+2022-10-14,Section 104,Microsoft,US5949181045,1.32642,324.7926690016643403072609590,319.76,-5.0326690016643403072609590
+2022-12-16,Section 104,Skyworks,US83088M1027,8.30000000,1094.155192117222311059989321,979.69,-114.465192117222311059989321
+2023-03-03,Section 104,Skyworks,US83088M1027,2.10000000,277.2021570417068497862623581,312.95,35.7478429582931502137376419
diff --git a/tests/test_cli/capital_gains_html b/tests/test_cli/capital_gains_html
new file mode 100644
index 0000000..8fd1ea0
--- /dev/null
+++ b/tests/test_cli/capital_gains_html
@@ -0,0 +1,56 @@
+
+
+
+ Disposal Date |
+ Identification |
+ Security Name |
+ ISIN |
+ Quantity |
+ Cost (£) |
+ Proceeds (£) |
+ Gain/loss (£) |
+
+
+
+
+ 20/09/2022 |
+ Section 104 |
+ Amazon |
+ US0231351067 |
+ 48.31896981 |
+ 3493.12 |
+ 4941.53 |
+ 1448.41 |
+
+
+ 14/10/2022 |
+ Section 104 |
+ Microsoft |
+ US5949181045 |
+ 1.32642000 |
+ 324.79 |
+ 319.76 |
+ -5.03 |
+
+
+ 16/12/2022 |
+ Section 104 |
+ Skyworks |
+ US83088M1027 |
+ 8.30000000 |
+ 1094.16 |
+ 979.69 |
+ -114.47 |
+
+
+ 03/03/2023 |
+ Section 104 |
+ Skyworks |
+ US83088M1027 |
+ 2.10000000 |
+ 277.20 |
+ 312.95 |
+ 35.75 |
+
+
+
diff --git a/tests/test_cli/capital_gains_json b/tests/test_cli/capital_gains_json
new file mode 100644
index 0000000..686eaae
--- /dev/null
+++ b/tests/test_cli/capital_gains_json
@@ -0,0 +1,52 @@
+[
+ [
+ "Disposal Date",
+ "Identification",
+ "Security Name",
+ "ISIN",
+ "Quantity",
+ "Cost (\u00a3)",
+ "Proceeds (\u00a3)",
+ "Gain/loss (\u00a3)"
+ ],
+ {
+ "Cost (\u00a3)": "3493.12",
+ "Disposal Date": "2022-09-20",
+ "Gain/loss (\u00a3)": "1448.41",
+ "ISIN": "US0231351067",
+ "Identification": "Section 104",
+ "Proceeds (\u00a3)": "4941.53",
+ "Quantity": "48.31896981",
+ "Security Name": "Amazon"
+ },
+ {
+ "Cost (\u00a3)": "324.7926690016643403072609590",
+ "Disposal Date": "2022-10-14",
+ "Gain/loss (\u00a3)": "-5.0326690016643403072609590",
+ "ISIN": "US5949181045",
+ "Identification": "Section 104",
+ "Proceeds (\u00a3)": "319.76",
+ "Quantity": "1.32642",
+ "Security Name": "Microsoft"
+ },
+ {
+ "Cost (\u00a3)": "1094.155192117222311059989321",
+ "Disposal Date": "2022-12-16",
+ "Gain/loss (\u00a3)": "-114.465192117222311059989321",
+ "ISIN": "US83088M1027",
+ "Identification": "Section 104",
+ "Proceeds (\u00a3)": "979.69",
+ "Quantity": "8.30000000",
+ "Security Name": "Skyworks"
+ },
+ {
+ "Cost (\u00a3)": "277.2021570417068497862623581",
+ "Disposal Date": "2023-03-03",
+ "Gain/loss (\u00a3)": "35.7478429582931502137376419",
+ "ISIN": "US83088M1027",
+ "Identification": "Section 104",
+ "Proceeds (\u00a3)": "312.95",
+ "Quantity": "2.10000000",
+ "Security Name": "Skyworks"
+ }
+]
diff --git a/tests/test_cli/dividends_csv b/tests/test_cli/dividends_csv
new file mode 100644
index 0000000..c53dd45
--- /dev/null
+++ b/tests/test_cli/dividends_csv
@@ -0,0 +1,7 @@
+Date,Security Name,ISIN,Ticker,Net Amount (£),Widthheld Amount (£)
+2022-02-12,Apple,US0378331005,AAPL,1.37,0.2391180000
+2022-03-09,Microsoft,US5949181045,MSFT,3.44,0.6073200000
+2022-03-15,Skyworks,US83088M1027,SWKS,2.50,0.4430620000
+2022-05-13,Microsoft,US5949181045,MSFT,4.12,0.7230000000
+2022-06-08,Apple,US0378331005,AAPL,1.64,0.2825940000
+,,,,13.07,2.29
diff --git a/tests/test_cli/dividends_html b/tests/test_cli/dividends_html
new file mode 100644
index 0000000..ce7eedd
--- /dev/null
+++ b/tests/test_cli/dividends_html
@@ -0,0 +1,62 @@
+
+
+
+ Date |
+ Security Name |
+ ISIN |
+ Ticker |
+ Net Amount (£) |
+ Widthheld Amount (£) |
+
+
+
+
+ 12/02/2022 |
+ Apple |
+ US0378331005 |
+ AAPL |
+ 1.37 |
+ 0.24 |
+
+
+ 09/03/2022 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ 3.44 |
+ 0.61 |
+
+
+ 15/03/2022 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ 2.50 |
+ 0.44 |
+
+
+ 13/05/2022 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ 4.12 |
+ 0.72 |
+
+
+ 08/06/2022 |
+ Apple |
+ US0378331005 |
+ AAPL |
+ 1.64 |
+ 0.28 |
+
+
+ |
+ |
+ |
+ |
+ 13.07 |
+ 2.29 |
+
+
+
diff --git a/tests/test_cli/dividends_json b/tests/test_cli/dividends_json
new file mode 100644
index 0000000..38669de
--- /dev/null
+++ b/tests/test_cli/dividends_json
@@ -0,0 +1,58 @@
+[
+ [
+ "Date",
+ "Security Name",
+ "ISIN",
+ "Ticker",
+ "Net Amount (\u00a3)",
+ "Widthheld Amount (\u00a3)"
+ ],
+ {
+ "Date": "2022-02-12",
+ "ISIN": "US0378331005",
+ "Net Amount (\u00a3)": "1.37",
+ "Security Name": "Apple",
+ "Ticker": "AAPL",
+ "Widthheld Amount (\u00a3)": "0.2391180000"
+ },
+ {
+ "Date": "2022-03-09",
+ "ISIN": "US5949181045",
+ "Net Amount (\u00a3)": "3.44",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Widthheld Amount (\u00a3)": "0.6073200000"
+ },
+ {
+ "Date": "2022-03-15",
+ "ISIN": "US83088M1027",
+ "Net Amount (\u00a3)": "2.50",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Widthheld Amount (\u00a3)": "0.4430620000"
+ },
+ {
+ "Date": "2022-05-13",
+ "ISIN": "US5949181045",
+ "Net Amount (\u00a3)": "4.12",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Widthheld Amount (\u00a3)": "0.7230000000"
+ },
+ {
+ "Date": "2022-06-08",
+ "ISIN": "US0378331005",
+ "Net Amount (\u00a3)": "1.64",
+ "Security Name": "Apple",
+ "Ticker": "AAPL",
+ "Widthheld Amount (\u00a3)": "0.2825940000"
+ },
+ {
+ "Date": "",
+ "ISIN": "",
+ "Net Amount (\u00a3)": "13.07",
+ "Security Name": "",
+ "Ticker": "",
+ "Widthheld Amount (\u00a3)": "2.29"
+ }
+]
diff --git a/tests/test_cli/holdings_csv b/tests/test_cli/holdings_csv
new file mode 100644
index 0000000..f68eee7
--- /dev/null
+++ b/tests/test_cli/holdings_csv
@@ -0,0 +1,6 @@
+Security Name,ISIN,Cost (£),Quantity,Current Value (£),Gain/Loss (£),Weight (%)
+SMT,GB00BLDYK618,2196.812045454545454545454546,162.00000000,,n/a,n/a
+Microsoft,US5949181045,882.3464985164979278272490710,3.62439184,,n/a,n/a
+Apple,US0378331005,301.699341785252128650422842,3.00000000,,n/a,n/a
+Skyworks,US83088M1027,301.0770951964634031790966809,2.295943596,,n/a,n/a
+PayPal,US70450Y1038,249.59,4.13171759,,n/a,n/a
diff --git a/tests/test_cli/holdings_html b/tests/test_cli/holdings_html
new file mode 100644
index 0000000..10c5123
--- /dev/null
+++ b/tests/test_cli/holdings_html
@@ -0,0 +1,42 @@
+
+
+
+ Security Name |
+ ISIN |
+ Cost (£) |
+ Quantity |
+
+
+
+
+ SMT |
+ GB00BLDYK618 |
+ 2196.81 |
+ 162.00000000 |
+
+
+ Microsoft |
+ US5949181045 |
+ 882.35 |
+ 3.62439184 |
+
+
+ Apple |
+ US0378331005 |
+ 301.70 |
+ 3.00000000 |
+
+
+ Skyworks |
+ US83088M1027 |
+ 301.08 |
+ 2.29594360 |
+
+
+ PayPal |
+ US70450Y1038 |
+ 249.59 |
+ 4.13171759 |
+
+
+
diff --git a/tests/test_cli/holdings_json b/tests/test_cli/holdings_json
new file mode 100644
index 0000000..daa3368
--- /dev/null
+++ b/tests/test_cli/holdings_json
@@ -0,0 +1,56 @@
+[
+ [
+ "Security Name",
+ "ISIN",
+ "Cost (\u00a3)",
+ "Quantity",
+ "Current Value (\u00a3)",
+ "Gain/Loss (\u00a3)",
+ "Weight (%)"
+ ],
+ {
+ "Cost (\u00a3)": "2196.812045454545454545454546",
+ "Current Value (\u00a3)": null,
+ "Gain/Loss (\u00a3)": "n/a",
+ "ISIN": "GB00BLDYK618",
+ "Quantity": "162.00000000",
+ "Security Name": "SMT",
+ "Weight (%)": "n/a"
+ },
+ {
+ "Cost (\u00a3)": "882.3464985164979278272490710",
+ "Current Value (\u00a3)": null,
+ "Gain/Loss (\u00a3)": "n/a",
+ "ISIN": "US5949181045",
+ "Quantity": "3.62439184",
+ "Security Name": "Microsoft",
+ "Weight (%)": "n/a"
+ },
+ {
+ "Cost (\u00a3)": "301.699341785252128650422842",
+ "Current Value (\u00a3)": null,
+ "Gain/Loss (\u00a3)": "n/a",
+ "ISIN": "US0378331005",
+ "Quantity": "3.00000000",
+ "Security Name": "Apple",
+ "Weight (%)": "n/a"
+ },
+ {
+ "Cost (\u00a3)": "301.0770951964634031790966809",
+ "Current Value (\u00a3)": null,
+ "Gain/Loss (\u00a3)": "n/a",
+ "ISIN": "US83088M1027",
+ "Quantity": "2.295943596",
+ "Security Name": "Skyworks",
+ "Weight (%)": "n/a"
+ },
+ {
+ "Cost (\u00a3)": "249.59",
+ "Current Value (\u00a3)": null,
+ "Gain/Loss (\u00a3)": "n/a",
+ "ISIN": "US70450Y1038",
+ "Quantity": "4.13171759",
+ "Security Name": "PayPal",
+ "Weight (%)": "n/a"
+ }
+]
diff --git a/tests/test_cli/interest_csv b/tests/test_cli/interest_csv
new file mode 100644
index 0000000..70d1153
--- /dev/null
+++ b/tests/test_cli/interest_csv
@@ -0,0 +1,7 @@
+Date,Amount (£)
+2021-10-15,1.70
+2022-01-15,1.59
+2022-04-15,1.61
+2022-07-15,1.58
+2023-01-15,1.81
+,8.29
diff --git a/tests/test_cli/interest_html b/tests/test_cli/interest_html
new file mode 100644
index 0000000..d162844
--- /dev/null
+++ b/tests/test_cli/interest_html
@@ -0,0 +1,34 @@
+
+
+
+ Date |
+ Amount (£) |
+
+
+
+
+ 15/10/2021 |
+ 1.70 |
+
+
+ 15/01/2022 |
+ 1.59 |
+
+
+ 15/04/2022 |
+ 1.61 |
+
+
+ 15/07/2022 |
+ 1.58 |
+
+
+ 15/01/2023 |
+ 1.81 |
+
+
+ |
+ 8.29 |
+
+
+
diff --git a/tests/test_cli/interest_json b/tests/test_cli/interest_json
new file mode 100644
index 0000000..a45f38f
--- /dev/null
+++ b/tests/test_cli/interest_json
@@ -0,0 +1,30 @@
+[
+ [
+ "Date",
+ "Amount (\u00a3)"
+ ],
+ {
+ "Amount (\u00a3)": "1.70",
+ "Date": "2021-10-15"
+ },
+ {
+ "Amount (\u00a3)": "1.59",
+ "Date": "2022-01-15"
+ },
+ {
+ "Amount (\u00a3)": "1.61",
+ "Date": "2022-04-15"
+ },
+ {
+ "Amount (\u00a3)": "1.58",
+ "Date": "2022-07-15"
+ },
+ {
+ "Amount (\u00a3)": "1.81",
+ "Date": "2023-01-15"
+ },
+ {
+ "Amount (\u00a3)": "8.29",
+ "Date": ""
+ }
+]
diff --git a/tests/test_cli/orders_csv b/tests/test_cli/orders_csv
new file mode 100644
index 0000000..c6926cb
--- /dev/null
+++ b/tests/test_cli/orders_csv
@@ -0,0 +1,22 @@
+Date,Security Name,ISIN,Ticker,Total Cost (£),Net Proceeds (£),Quantity,Price (£),Fees (£)
+2021-04-07,Apple,US0378331005,AAPL,1940.99,,20.13713692,96.15219917767733984300683794,4.76
+2021-06-05,Apple,US0378331005,AAPL,998.48,,9.09199546,109.3280352341926928326908777,4.47
+2021-06-11,Microsoft,US5949181045,MSFT,2715.44,,15.00246544,180.1863840854146970126264793,12.20
+2021-08-12,Skyworks,US83088M1027,SWKS,1497.76,,11.21263989,132.9793888529135666373389612,6.71
+2021-08-25,Microsoft,US5949181045,MSFT,,2939.35,13.00246544,227.0707823546424284900848773,13.13
+2021-08-26,SMT,GB00BLDYK618,SMT,2386.66,,176.00000000,13.49295454545454545454545455,11.90
+2021-09-01,Skyworks,US83088M1027,SWKS,,152.47,1.245848877,122.9763921037751996946255625,0.74
+2021-09-13,SMT,GB00BLDYK618,SMT,,1228.97,88.00000000,13.96556818181818181818181818,0.00
+2021-09-13,SMT,GB00BLDYK618,SMT,443.65,,34.00000000,13.02558823529411764705882353,0.78
+2021-09-26,SMT,GB00BLDYK618,SMT,482.67,,40.00000000,12.05275,0.56
+2021-11-02,Apple,US0378331005,AAPL,,3643.81,26.22913238,139.2859644410395857706979174,9.54
+2022-01-27,Skyworks,US83088M1027,SWKS,,177.34,1.245848877,142.9788181283563495960032077,0.79
+2022-04-10,PayPal,US70450Y1038,PYPL,249.59,,4.13171759,60.05492742305264866856497808,1.46
+2022-05-12,Microsoft,US5949181045,MSFT,843.26,,2.95081184,284.0946984949064051471340172,4.95
+2022-07-09,Amazon,US0231351067,AMZN,3464.02,,48.31896981,71.26931748630341918293476961,20.36
+2022-09-20,Amazon,US0231351067,AMZN,,4912.43,48.31896981,102.2689436349967578085663660,29.10
+2022-09-28,Skyworks,US83088M1027,SWKS,499.95,,3.97500146,125.0339163397439355909066760,2.94
+2022-10-14,Microsoft,US5949181045,MSFT,,317.88,1.32642,241.0699476787141327784562959,1.88
+2022-12-16,Skyworks,US83088M1027,SWKS,,973.95,8.30000000,118.0349397590361445783132530,5.74
+2023-03-03,Skyworks,US83088M1027,SWKS,,311.13,2.10000000,149.0238095238095238095238095,1.82
+,,,,15522.47,14657.33,,,133.83
diff --git a/tests/test_cli/orders_html b/tests/test_cli/orders_html
new file mode 100644
index 0000000..1f60656
--- /dev/null
+++ b/tests/test_cli/orders_html
@@ -0,0 +1,248 @@
+
+
+
+ Date |
+ Security Name |
+ ISIN |
+ Ticker |
+ Total Cost (£) |
+ Net Proceeds (£) |
+ Quantity |
+ Price (£) |
+ Fees (£) |
+
+
+
+
+ 07/04/2021 |
+ Apple |
+ US0378331005 |
+ AAPL |
+ 1940.99 |
+ |
+ 20.13713692 |
+ 96.15 |
+ 4.76 |
+
+
+ 05/06/2021 |
+ Apple |
+ US0378331005 |
+ AAPL |
+ 998.48 |
+ |
+ 9.09199546 |
+ 109.33 |
+ 4.47 |
+
+
+ 11/06/2021 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ 2715.44 |
+ |
+ 15.00246544 |
+ 180.19 |
+ 12.20 |
+
+
+ 12/08/2021 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ 1497.76 |
+ |
+ 11.21263989 |
+ 132.98 |
+ 6.71 |
+
+
+ 25/08/2021 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ |
+ 2939.35 |
+ 13.00246544 |
+ 227.07 |
+ 13.13 |
+
+
+ 26/08/2021 |
+ SMT |
+ GB00BLDYK618 |
+ SMT |
+ 2386.66 |
+ |
+ 176.00000000 |
+ 13.49 |
+ 11.90 |
+
+
+ 01/09/2021 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ |
+ 152.47 |
+ 1.24584888 |
+ 122.98 |
+ 0.74 |
+
+
+ 13/09/2021 |
+ SMT |
+ GB00BLDYK618 |
+ SMT |
+ |
+ 1228.97 |
+ 88.00000000 |
+ 13.97 |
+ 0.00 |
+
+
+ 13/09/2021 |
+ SMT |
+ GB00BLDYK618 |
+ SMT |
+ 443.65 |
+ |
+ 34.00000000 |
+ 13.03 |
+ 0.78 |
+
+
+ 26/09/2021 |
+ SMT |
+ GB00BLDYK618 |
+ SMT |
+ 482.67 |
+ |
+ 40.00000000 |
+ 12.05 |
+ 0.56 |
+
+
+ 02/11/2021 |
+ Apple |
+ US0378331005 |
+ AAPL |
+ |
+ 3643.81 |
+ 26.22913238 |
+ 139.29 |
+ 9.54 |
+
+
+ 27/01/2022 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ |
+ 177.34 |
+ 1.24584888 |
+ 142.98 |
+ 0.79 |
+
+
+ 10/04/2022 |
+ PayPal |
+ US70450Y1038 |
+ PYPL |
+ 249.59 |
+ |
+ 4.13171759 |
+ 60.05 |
+ 1.46 |
+
+
+ 12/05/2022 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ 843.26 |
+ |
+ 2.95081184 |
+ 284.09 |
+ 4.95 |
+
+
+ 09/07/2022 |
+ Amazon |
+ US0231351067 |
+ AMZN |
+ 3464.02 |
+ |
+ 48.31896981 |
+ 71.27 |
+ 20.36 |
+
+
+ 20/09/2022 |
+ Amazon |
+ US0231351067 |
+ AMZN |
+ |
+ 4912.43 |
+ 48.31896981 |
+ 102.27 |
+ 29.10 |
+
+
+ 28/09/2022 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ 499.95 |
+ |
+ 3.97500146 |
+ 125.03 |
+ 2.94 |
+
+
+ 14/10/2022 |
+ Microsoft |
+ US5949181045 |
+ MSFT |
+ |
+ 317.88 |
+ 1.32642000 |
+ 241.07 |
+ 1.88 |
+
+
+ 16/12/2022 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ |
+ 973.95 |
+ 8.30000000 |
+ 118.03 |
+ 5.74 |
+
+
+ 03/03/2023 |
+ Skyworks |
+ US83088M1027 |
+ SWKS |
+ |
+ 311.13 |
+ 2.10000000 |
+ 149.02 |
+ 1.82 |
+
+
+ |
+ |
+ |
+ |
+ 15522.47 |
+ 14657.33 |
+ |
+ |
+ 133.83 |
+
+
+
diff --git a/tests/test_cli/orders_json b/tests/test_cli/orders_json
new file mode 100644
index 0000000..3f36a31
--- /dev/null
+++ b/tests/test_cli/orders_json
@@ -0,0 +1,244 @@
+[
+ [
+ "Date",
+ "Security Name",
+ "ISIN",
+ "Ticker",
+ "Total Cost (\u00a3)",
+ "Net Proceeds (\u00a3)",
+ "Quantity",
+ "Price (\u00a3)",
+ "Fees (\u00a3)"
+ ],
+ {
+ "Date": "2021-04-07",
+ "Fees (\u00a3)": "4.76",
+ "ISIN": "US0378331005",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "96.15219917767733984300683794",
+ "Quantity": "20.13713692",
+ "Security Name": "Apple",
+ "Ticker": "AAPL",
+ "Total Cost (\u00a3)": "1940.99"
+ },
+ {
+ "Date": "2021-06-05",
+ "Fees (\u00a3)": "4.47",
+ "ISIN": "US0378331005",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "109.3280352341926928326908777",
+ "Quantity": "9.09199546",
+ "Security Name": "Apple",
+ "Ticker": "AAPL",
+ "Total Cost (\u00a3)": "998.48"
+ },
+ {
+ "Date": "2021-06-11",
+ "Fees (\u00a3)": "12.20",
+ "ISIN": "US5949181045",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "180.1863840854146970126264793",
+ "Quantity": "15.00246544",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Total Cost (\u00a3)": "2715.44"
+ },
+ {
+ "Date": "2021-08-12",
+ "Fees (\u00a3)": "6.71",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "132.9793888529135666373389612",
+ "Quantity": "11.21263989",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": "1497.76"
+ },
+ {
+ "Date": "2021-08-25",
+ "Fees (\u00a3)": "13.13",
+ "ISIN": "US5949181045",
+ "Net Proceeds (\u00a3)": "2939.35",
+ "Price (\u00a3)": "227.0707823546424284900848773",
+ "Quantity": "13.00246544",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2021-08-26",
+ "Fees (\u00a3)": "11.90",
+ "ISIN": "GB00BLDYK618",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "13.49295454545454545454545455",
+ "Quantity": "176.00000000",
+ "Security Name": "SMT",
+ "Ticker": "SMT",
+ "Total Cost (\u00a3)": "2386.66"
+ },
+ {
+ "Date": "2021-09-01",
+ "Fees (\u00a3)": "0.74",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": "152.47",
+ "Price (\u00a3)": "122.9763921037751996946255625",
+ "Quantity": "1.245848877",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2021-09-13",
+ "Fees (\u00a3)": "0.00",
+ "ISIN": "GB00BLDYK618",
+ "Net Proceeds (\u00a3)": "1228.97",
+ "Price (\u00a3)": "13.96556818181818181818181818",
+ "Quantity": "88.00000000",
+ "Security Name": "SMT",
+ "Ticker": "SMT",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2021-09-13",
+ "Fees (\u00a3)": "0.78",
+ "ISIN": "GB00BLDYK618",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "13.02558823529411764705882353",
+ "Quantity": "34.00000000",
+ "Security Name": "SMT",
+ "Ticker": "SMT",
+ "Total Cost (\u00a3)": "443.65"
+ },
+ {
+ "Date": "2021-09-26",
+ "Fees (\u00a3)": "0.56",
+ "ISIN": "GB00BLDYK618",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "12.05275",
+ "Quantity": "40.00000000",
+ "Security Name": "SMT",
+ "Ticker": "SMT",
+ "Total Cost (\u00a3)": "482.67"
+ },
+ {
+ "Date": "2021-11-02",
+ "Fees (\u00a3)": "9.54",
+ "ISIN": "US0378331005",
+ "Net Proceeds (\u00a3)": "3643.81",
+ "Price (\u00a3)": "139.2859644410395857706979174",
+ "Quantity": "26.22913238",
+ "Security Name": "Apple",
+ "Ticker": "AAPL",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2022-01-27",
+ "Fees (\u00a3)": "0.79",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": "177.34",
+ "Price (\u00a3)": "142.9788181283563495960032077",
+ "Quantity": "1.245848877",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2022-04-10",
+ "Fees (\u00a3)": "1.46",
+ "ISIN": "US70450Y1038",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "60.05492742305264866856497808",
+ "Quantity": "4.13171759",
+ "Security Name": "PayPal",
+ "Ticker": "PYPL",
+ "Total Cost (\u00a3)": "249.59"
+ },
+ {
+ "Date": "2022-05-12",
+ "Fees (\u00a3)": "4.95",
+ "ISIN": "US5949181045",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "284.0946984949064051471340172",
+ "Quantity": "2.95081184",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Total Cost (\u00a3)": "843.26"
+ },
+ {
+ "Date": "2022-07-09",
+ "Fees (\u00a3)": "20.36",
+ "ISIN": "US0231351067",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "71.26931748630341918293476961",
+ "Quantity": "48.31896981",
+ "Security Name": "Amazon",
+ "Ticker": "AMZN",
+ "Total Cost (\u00a3)": "3464.02"
+ },
+ {
+ "Date": "2022-09-20",
+ "Fees (\u00a3)": "29.10",
+ "ISIN": "US0231351067",
+ "Net Proceeds (\u00a3)": "4912.43",
+ "Price (\u00a3)": "102.2689436349967578085663660",
+ "Quantity": "48.31896981",
+ "Security Name": "Amazon",
+ "Ticker": "AMZN",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2022-09-28",
+ "Fees (\u00a3)": "2.94",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": null,
+ "Price (\u00a3)": "125.0339163397439355909066760",
+ "Quantity": "3.97500146",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": "499.95"
+ },
+ {
+ "Date": "2022-10-14",
+ "Fees (\u00a3)": "1.88",
+ "ISIN": "US5949181045",
+ "Net Proceeds (\u00a3)": "317.88",
+ "Price (\u00a3)": "241.0699476787141327784562959",
+ "Quantity": "1.32642",
+ "Security Name": "Microsoft",
+ "Ticker": "MSFT",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2022-12-16",
+ "Fees (\u00a3)": "5.74",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": "973.95",
+ "Price (\u00a3)": "118.0349397590361445783132530",
+ "Quantity": "8.30000000",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "2023-03-03",
+ "Fees (\u00a3)": "1.82",
+ "ISIN": "US83088M1027",
+ "Net Proceeds (\u00a3)": "311.13",
+ "Price (\u00a3)": "149.0238095238095238095238095",
+ "Quantity": "2.10000000",
+ "Security Name": "Skyworks",
+ "Ticker": "SWKS",
+ "Total Cost (\u00a3)": null
+ },
+ {
+ "Date": "",
+ "Fees (\u00a3)": "133.83",
+ "ISIN": "",
+ "Net Proceeds (\u00a3)": "14657.33",
+ "Price (\u00a3)": "",
+ "Quantity": "",
+ "Security Name": "",
+ "Ticker": "",
+ "Total Cost (\u00a3)": "15522.47"
+ }
+]
diff --git a/tests/test_cli/transfers_csv b/tests/test_cli/transfers_csv
new file mode 100644
index 0000000..aab1f14
--- /dev/null
+++ b/tests/test_cli/transfers_csv
@@ -0,0 +1,7 @@
+Date,Deposit (£),Withdrawal (£)
+2021-03-02,6000.00,
+2021-07-28,4000.00,
+2022-02-24,,400.00
+2022-04-08,,100.00
+2023-01-03,2000.00,
+,12000.00,500.00
diff --git a/tests/test_cli/transfers_html b/tests/test_cli/transfers_html
new file mode 100644
index 0000000..6635d11
--- /dev/null
+++ b/tests/test_cli/transfers_html
@@ -0,0 +1,41 @@
+
+
+
+ Date |
+ Deposit (£) |
+ Withdrawal (£) |
+
+
+
+
+ 02/03/2021 |
+ 6000.00 |
+ |
+
+
+ 28/07/2021 |
+ 4000.00 |
+ |
+
+
+ 24/02/2022 |
+ |
+ 400.00 |
+
+
+ 08/04/2022 |
+ |
+ 100.00 |
+
+
+ 03/01/2023 |
+ 2000.00 |
+ |
+
+
+ |
+ 12000.00 |
+ 500.00 |
+
+
+
diff --git a/tests/test_cli/transfers_json b/tests/test_cli/transfers_json
new file mode 100644
index 0000000..48dd438
--- /dev/null
+++ b/tests/test_cli/transfers_json
@@ -0,0 +1,37 @@
+[
+ [
+ "Date",
+ "Deposit (\u00a3)",
+ "Withdrawal (\u00a3)"
+ ],
+ {
+ "Date": "2021-03-02",
+ "Deposit (\u00a3)": "6000.00",
+ "Withdrawal (\u00a3)": ""
+ },
+ {
+ "Date": "2021-07-28",
+ "Deposit (\u00a3)": "4000.00",
+ "Withdrawal (\u00a3)": ""
+ },
+ {
+ "Date": "2022-02-24",
+ "Deposit (\u00a3)": "",
+ "Withdrawal (\u00a3)": "400.00"
+ },
+ {
+ "Date": "2022-04-08",
+ "Deposit (\u00a3)": "",
+ "Withdrawal (\u00a3)": "100.00"
+ },
+ {
+ "Date": "2023-01-03",
+ "Deposit (\u00a3)": "2000.00",
+ "Withdrawal (\u00a3)": ""
+ },
+ {
+ "Date": "",
+ "Deposit (\u00a3)": "12000.00",
+ "Withdrawal (\u00a3)": "500.00"
+ }
+]