36
36
# Prefix: "Transactions for account..."
37
37
# Suffix: "Transactions Total"
38
38
# 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 ("" )
43
47
44
48
# Rename column names
45
49
column_new_names = {
53
57
df .rename (columns = column_new_names , inplace = True )
54
58
55
59
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."""
58
62
import re
59
63
import locale
60
64
@@ -63,20 +67,25 @@ def remove_currency(text: str):
63
67
return clean
64
68
65
69
70
+ # Remove US dollar symbol
66
71
new_value = df ["Value" ].apply (remove_currency )
67
72
df ["Value" ] = new_value
68
73
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 )
72
77
73
- # Convert Action to Type
78
+ # Convert Action (Schwab) to Type (Portfolio Performance)
74
79
"""
75
80
"Deposit/Removal (or withdrawal): Depositing or withdrawing funds will
76
81
respectively increase or decrease the value of a deposit account."
77
82
Ref: https://help.portfolio-performance.info/en/reference/transaction/
78
83
79
84
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.
80
89
"""
81
90
action_to_type = {
82
91
"NRA Tax Adj" : "Taxes" ,
@@ -92,36 +101,42 @@ def remove_currency(text: str):
92
101
"Advisor Fee" : "Fees" ,
93
102
"Reinvest Dividend" : "Dividend" ,
94
103
"Reinvest Shares" : "Buy" ,
95
- "Bank Interest" : "Dividend " ,
104
+ "Bank Interest" : "Interest " ,
96
105
"Funds Received" : "Deposit" ,
97
106
"MoneyLink Transfer" : "Deposit" ,
98
107
}
99
108
new_type = [action_to_type [x ] for x in df ["Note" ]]
100
109
df ["Type" ] = new_type
101
110
102
- # Delete Price column
111
+ # Delete Price column because PP seems not to have this column for a
112
+ # transaction.
103
113
df .drop (columns = ["Price" ], inplace = True )
104
114
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" ]
119
123
else :
120
- return data
124
+ new_security_name .append (df .at [k , "Security Name" ])
125
+ df ["Security Name" ] = new_security_name
121
126
122
127
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" )
125
140
126
141
# Write to CSV file
127
142
df .to_csv (args .pp_csv , index = False , date_format = "%Y-%m-%d" )
0 commit comments