Skip to content

Commit 8e8df01

Browse files
committed
Address #16
1 parent 397f4d2 commit 8e8df01

File tree

4 files changed

+52
-33
lines changed

4 files changed

+52
-33
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ Duplicate transactions:
101101

102102
As far as I can test, PP will detect and skip duplicate transactions. So it is safe to import overlapping transactions in the future.
103103

104+
Dates:
105+
106+
If date is in "date1 as of date2" format, "date1" will be used and "as of date2" will be appended to the resulting "Note" column.
107+
104108
## License
105109

106110
MIT

convert.py

+44-29
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,14 @@
3636
# Prefix: "Transactions for account..."
3737
# Suffix: "Transactions Total"
3838
# They are ignored.
39-
df = pd.read_csv(args.schwab_csv, skiprows=1, skipfooter=1, engine="python")
40-
41-
# Convert dates to datetime objects
42-
df["Date"] = pd.to_datetime(df["Date"], format="%m/%d/%Y")
39+
dtype = {
40+
"Date" : str,
41+
"Symbol" : str,
42+
"Fees & Comm" : str, # must keep as string, in case of floating-point rounding errors.
43+
"Amount" : str, # must keep as string, in case of floating-point rounding errors.
44+
}
45+
df = pd.read_csv(args.schwab_csv, skiprows=1, skipfooter=1, dtype=dtype, engine="python")
46+
df["Symbol"] = df["Symbol"].fillna("")
4347

4448
# Rename column names
4549
column_new_names = {
@@ -53,8 +57,8 @@
5357
df.rename(columns=column_new_names, inplace=True)
5458

5559

56-
# Remove US dollar sign from Value column
57-
def remove_currency(text: str):
60+
def remove_currency(text: str) -> str:
61+
"""Removes currency symbol from string. Works for negative values."""
5862
import re
5963
import locale
6064

@@ -63,20 +67,25 @@ def remove_currency(text: str):
6367
return clean
6468

6569

70+
# Remove US dollar symbol
6671
new_value = df["Value"].apply(remove_currency)
6772
df["Value"] = new_value
6873

69-
# Add a new column with all USD: Transaction Currency
70-
transaction_currency = ["USD" for x in df["Value"]]
71-
df["Transaction Currency"] = transaction_currency
74+
# Hard-coding. Assume all transcations are in USD.
75+
# Add a new column: Transaction Currency
76+
df["Transaction Currency"] = ["USD"] * len(df.index)
7277

73-
# Convert Action to Type
78+
# Convert Action (Schwab) to Type (Portfolio Performance)
7479
"""
7580
"Deposit/Removal (or withdrawal): Depositing or withdrawing funds will
7681
respectively increase or decrease the value of a deposit account."
7782
Ref: https://help.portfolio-performance.info/en/reference/transaction/
7883
7984
So a Schwab "Wire Sent" is a PP "Removal".
85+
86+
Bank Interest as Dividend was introduced in commit
87+
297f429979d4588f8871ad6d23d70f0557de9420 by @sdtom. After review, as Interest
88+
is probably more appropriate.
8089
"""
8190
action_to_type = {
8291
"NRA Tax Adj": "Taxes",
@@ -92,36 +101,42 @@ def remove_currency(text: str):
92101
"Advisor Fee": "Fees",
93102
"Reinvest Dividend": "Dividend",
94103
"Reinvest Shares": "Buy",
95-
"Bank Interest": "Dividend",
104+
"Bank Interest": "Interest",
96105
"Funds Received": "Deposit",
97106
"MoneyLink Transfer": "Deposit",
98107
}
99108
new_type = [action_to_type[x] for x in df["Note"]]
100109
df["Type"] = new_type
101110

102-
# Delete Price column
111+
# Delete Price column because PP seems not to have this column for a
112+
# transaction.
103113
df.drop(columns=["Price"], inplace=True)
104114

105-
# Add SCHWAB1 INT to Notes
106-
for k, v in df["Security Name"].items():
107-
if v.startswith("SCHWAB1 INT"):
108-
df.at[k, "Note"] = df.at[k, "Note"] + " " + v
109-
110-
111-
# Remove non-security names
112-
def convert_security_name(data: str):
113-
if data.startswith("SCHWAB1 INT"):
114-
return ""
115-
elif data.startswith("WIRED FUNDS RECEIVED"):
116-
return ""
117-
elif data.startswith("WIRED FUNDS DISBURSED"):
118-
return ""
115+
# If "Ticker Symbol" column is not empty, then "Security Name" column
116+
# contains the name of the security. Otherwise it's a description.
117+
# If latter, append to "Note" column.
118+
new_security_name = []
119+
for k, v in df["Ticker Symbol"].items():
120+
if len(v) == 0:
121+
new_security_name.append("")
122+
df.at[k, "Note"] = df.at[k, "Note"] + " " + df.at[k, "Security Name"]
119123
else:
120-
return data
124+
new_security_name.append(df.at[k, "Security Name"])
125+
df["Security Name"] = new_security_name
121126

122127

123-
new_security_name = [convert_security_name(v) for v in df["Security Name"]]
124-
df["Security Name"] = new_security_name
128+
# Convert dates to datetime objects
129+
new_date = []
130+
for k, v in df["Date"].items():
131+
multiple = v.split(" as of ", 1)
132+
new_date.append(multiple[0])
133+
if len(multiple) > 1:
134+
if len(df.at[k, "Note"]):
135+
df.at[k, "Note"] = df.at[k, "Note"] + " as of " + multiple[1]
136+
else:
137+
df.at[k, "Note"] = "as of " + multiple[1]
138+
139+
df["Date"] = pd.to_datetime(new_date, format="%m/%d/%Y")
125140

126141
# Write to CSV file
127142
df.to_csv(args.pp_csv, index=False, date_format="%Y-%m-%d")

example.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"03/04/2021","NRA Tax Adj","BNDX","VANGUARD TOTAL INTERNATIONAL BND ETF","","","","-$1.10"
88
"03/04/2021","Cash Dividend","BNDX","VANGUARD TOTAL INTERNATIONAL BND ETF","","","","$3.65"
99
"02/25/2021","NRA Tax Adj","","SCHWAB1 INT 01/28-02/24","","","","-$0.02"
10-
"02/25/2021","Credit Interest","","SCHWAB1 INT 01/28-02/24","","","","$0.09"
10+
"02/25/2021 as of 02/21/2021","Credit Interest","","SCHWAB1 INT 01/28-02/24","","","","$0.09"
1111
"02/09/2021","Buy","BNDX","VANGUARD TOTAL INTERNATIONAL BND ETF","81","$57.9999","","-$4697.99"
1212
"02/02/2021","Wire Received","","WIRED FUNDS RECEIVED","","","","$5000.00"
1313
"Transactions Total","","","","","","","$94.33",

example_out.csv

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Date,Note,Ticker Symbol,Security Name,Shares,Fees,Value,Transaction Currency,Type
2-
2024-01-01,Wire Sent,,,,,-100.00,USD,Removal
2+
2024-01-01,Wire Sent WIRED FUNDS DISBURSED,,,,,-100.00,USD,Removal
33
2021-12-29,NRA Withholding,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,,,-0.14,USD,Taxes
44
2021-12-29,Short Term Cap Gain,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,,,0.48,USD,Dividend
55
2021-12-29,Long Term Cap Gain,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,,,29.21,USD,Dividend
66
2021-03-04,NRA Tax Adj,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,,,-1.10,USD,Taxes
77
2021-03-04,Cash Dividend,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,,,3.65,USD,Dividend
88
2021-02-25,NRA Tax Adj SCHWAB1 INT 01/28-02/24,,,,,-0.02,USD,Taxes
9-
2021-02-25,Credit Interest SCHWAB1 INT 01/28-02/24,,,,,0.09,USD,Interest
9+
2021-02-25,Credit Interest SCHWAB1 INT 01/28-02/24 as of 02/21/2021,,,,,0.09,USD,Interest
1010
2021-02-09,Buy,BNDX,VANGUARD TOTAL INTERNATIONAL BND ETF,81.0,,-4697.99,USD,Buy
11-
2021-02-02,Wire Received,,,,,5000.00,USD,Deposit
11+
2021-02-02,Wire Received WIRED FUNDS RECEIVED,,,,,5000.00,USD,Deposit

0 commit comments

Comments
 (0)