Skip to content

Commit 3745811

Browse files
committed
support for parsing scheme valuation (#2)
1 parent 8e7f63a commit 3745811

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

casparser/cli.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from decimal import Decimal
12
import json
23
import re
34
import sys
@@ -40,37 +41,53 @@ def print_summary(data):
4041
fmt_value = fmt_value[:37] + "..."
4142
click.echo(f"{key:>40s}: {fmt_value}")
4243
click.echo("")
43-
table = texttable.Texttable(max_width=100)
44-
table.set_cols_align(["l", "r", "r", "r", "r", "c"])
45-
table.set_cols_valign(["m", "m", "m", "m", "m", "m"])
46-
table.add_row(
47-
["Scheme", "Open", "Close\nReported", "Close\nCalculated", "Transactions", "Status"]
48-
)
44+
table = texttable.Texttable(max_width=120)
45+
header = [
46+
"Scheme",
47+
"Open",
48+
"Close\nReported",
49+
"Close\nCalculated",
50+
f"Value\n({data['statement_period']['to']})",
51+
"Transactions",
52+
"Status",
53+
]
54+
table.add_row(header)
55+
table.set_cols_align(["l"] + ["r"] * (len(header) - 2) + ["c"])
56+
table.set_cols_valign(["m"] * len(header))
4957
current_amc = None
58+
value = Decimal(0)
5059
for folio in data["folios"]:
5160
if current_amc != folio.get("amc", ""):
5261
current_amc = folio["amc"]
53-
table.add_row([current_amc] + [""] * 5)
62+
table.add_row([current_amc] + [""] * 6)
5463
for scheme in folio["schemes"]:
5564
calc_close = scheme["open"] + sum([x["units"] for x in scheme["transactions"]])
65+
valuation = scheme["valuation"]
5666
if calc_close != scheme["close"]:
5767
err += 1
5868
status = "❗️"
5969
else:
6070
status = "️✅"
6171
scheme_name = f"{scheme['scheme']}\nFolio: {folio['folio']}"
72+
value += valuation["value"]
6273
table.add_row(
6374
[
6475
scheme_name,
6576
scheme["open"],
6677
scheme["close"],
6778
calc_close,
79+
f"₹{valuation['value']:,.2f}",
6880
len(scheme["transactions"]),
6981
status,
7082
]
7183
)
7284
count += 1
7385
click.echo(table.draw())
86+
click.echo(
87+
"Portfolio Valuation : "
88+
+ click.style(f"₹{value:,.2f}", fg="green", bold=True)
89+
+ f" [As of {data['statement_period']['to']}]"
90+
)
7491
click.secho("Summary", bold=True)
7592
click.echo("Total : " + click.style(f"{count:4d}", fg="white", bold=True) + " schemes")
7693
click.echo("Matched : " + click.style(f"{count - err:4d}", fg="green", bold=True) + " schemes")

casparser/process.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from .exceptions import HeaderParseError, CASParseError
77
from .regex import FOLIO_RE, HEADER_RE, SCHEME_RE
8-
from .regex import CLOSE_UNITS_RE, OPEN_UNITS_RE, TRANSACTION_RE
8+
from .regex import CLOSE_UNITS_RE, OPEN_UNITS_RE, VALUATION_RE, TRANSACTION_RE
99

1010

1111
def parse_header(text):
@@ -64,6 +64,7 @@ def process_cas_text(text):
6464
"rta": m.group(4).strip(),
6565
"open": Decimal(0.0),
6666
"close": Decimal(0.0),
67+
"valuation": {"date": None, "value": 0},
6768
"transactions": [],
6869
}
6970
if not curr_scheme_data:
@@ -73,6 +74,11 @@ def process_cas_text(text):
7374
continue
7475
if m := re.search(CLOSE_UNITS_RE, line):
7576
curr_scheme_data["close"] = Decimal(m.group(1).replace(",", "_"))
77+
if m := re.search(VALUATION_RE, line, re.I):
78+
curr_scheme_data["valuation"].update(
79+
date=date_parser.parse(m.group(1)).date(),
80+
value=Decimal(m.group(2).replace(",", "_")),
81+
)
7682
continue
7783
if m := re.search(TRANSACTION_RE, line, re.DOTALL):
7884
date = date_parser.parse(m.group(1)).date()

casparser/regex.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
SCHEME_RE = r"([\s\w]+)-\s*\d*\s*(.+?)\s*\(Advisor\s*:\s*(.+?)\)\s+Registrar\s*:\s*(.*)\s*$"
99
OPEN_UNITS_RE = r"Opening\s+Unit\s+Balance.+?([\d,.]+)"
1010
CLOSE_UNITS_RE = r"Closing\s+Unit\s+Balance.+?([\d,.]+)"
11+
VALUATION_RE = r"Valuation\s+on\s+(\d{2}-[A-Za-z]{3}-\d{4})\s*:\s*INR\s*([\d,.]+)"
1112

1213
TRANSACTION_RE = (
1314
r"(\d{2}-[A-Za-z]{3}-\d{4})\t\t([^\t]+?)\t\t([(\d,.]+)\)*\t\t"

casparser/types.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ class TransactionType(TypedDict):
2727
balance: Union[Decimal, float]
2828

2929

30+
class SchemeValuation(TypedDict):
31+
date: Union[date, str]
32+
value: Union[Decimal, float]
33+
34+
3035
class SchemeType(TypedDict, total=False):
3136
"""Mutual Fund Scheme data structure."""
3237

@@ -37,6 +42,7 @@ class SchemeType(TypedDict, total=False):
3742
rta: str
3843
open: Union[Decimal, float]
3944
close: Union[Decimal, float]
45+
valuation: str
4046
transactions: List[TransactionType]
4147

4248

tests/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def setup_class(cls):
2020
cls.kfintech_password = os.getenv("KFINTECH_CAS_PASSWORD")
2121

2222
def read_pdf(self, filename, password, output="dict"):
23-
use_pdfminer = (self.mode == "pdfminer")
23+
use_pdfminer = self.mode == "pdfminer"
2424
return read_cas_pdf(filename, password, output=output, force_pdfminer=use_pdfminer)
2525

2626
def test_read_dict(self):

0 commit comments

Comments
 (0)