|
6 | 6 |
|
7 | 7 | try:
|
8 | 8 | import pandas as pd
|
9 |
| -except ImportError: |
10 |
| - raise ImportError('Is Pandas installed?') |
| 9 | +except ImportError as exc: |
| 10 | + raise ImportError("Is Pandas installed?") from exc |
11 | 11 |
|
12 | 12 |
|
13 | 13 | parser = argparse.ArgumentParser(
|
14 |
| - description=('Converts a Charles Schwab transaction CSV file to a' |
15 |
| - ' ready-to-import CSV file for Portfolio Performance.')) |
| 14 | + description=( |
| 15 | + "Converts a Charles Schwab transaction CSV file to a" |
| 16 | + " ready-to-import CSV file for Portfolio Performance." |
| 17 | + ) |
| 18 | +) |
| 19 | +parser.add_argument("schwab_csv", type=str, help="Input Charles Schwab CSV file") |
16 | 20 | parser.add_argument(
|
17 |
| - 'schwab_csv', type=str, |
18 |
| - help='Input Charles Schwab CSV file') |
19 |
| -parser.add_argument( |
20 |
| - '-p', '--pp_csv', type=str, |
21 |
| - default='pp.csv', |
22 |
| - help='Resulting CSV file for Portfolio Performance (default: pp.csv)') |
| 21 | + "-p", |
| 22 | + "--pp_csv", |
| 23 | + type=str, |
| 24 | + default="pp.csv", |
| 25 | + help="Resulting CSV file for Portfolio Performance (default: pp.csv)", |
| 26 | +) |
23 | 27 | args = parser.parse_args()
|
24 | 28 |
|
25 | 29 |
|
26 | 30 | if not os.path.isfile(args.schwab_csv):
|
27 |
| - print(f'{args.schwab_csv} not found') |
| 31 | + print(f"{args.schwab_csv} not found") |
28 | 32 | sys.exit(1)
|
29 | 33 |
|
30 | 34 |
|
31 | 35 | # A Charles Scwab CSV starts with a prefix and a suffix row
|
32 | 36 | # Prefix: "Transactions for account...
|
33 | 37 | # Suffix: "Transactions Total"
|
34 |
| -df = pd.read_csv(args.schwab_csv, |
35 |
| - skiprows=1, |
36 |
| - skipfooter=1, |
37 |
| - engine='python') |
| 38 | +df = pd.read_csv(args.schwab_csv, skiprows=1, skipfooter=1, engine="python") |
38 | 39 |
|
39 | 40 | # Convert dates to datetime objects
|
40 |
| -df['Date'] = pd.to_datetime(df['Date'], format='%m/%d/%Y') |
| 41 | +df["Date"] = pd.to_datetime(df["Date"], format="%m/%d/%Y") |
41 | 42 |
|
42 | 43 | # Rename column names
|
43 | 44 | column_new_names = {
|
44 |
| - 'Action': 'Note', |
45 |
| - 'Symbol': 'Ticker Symbol', |
46 |
| - 'Description': 'Security Name', |
47 |
| - 'Quantity': 'Shares', |
48 |
| - 'Fees & Comm': 'Fees', |
49 |
| - 'Amount': 'Value', |
| 45 | + "Action": "Note", |
| 46 | + "Symbol": "Ticker Symbol", |
| 47 | + "Description": "Security Name", |
| 48 | + "Quantity": "Shares", |
| 49 | + "Fees & Comm": "Fees", |
| 50 | + "Amount": "Value", |
50 | 51 | }
|
51 | 52 | df.rename(columns=column_new_names, inplace=True)
|
52 | 53 |
|
|
55 | 56 | def remove_currency(text: str):
|
56 | 57 | import re
|
57 | 58 | import locale
|
58 |
| - decimal_point_char = locale.localeconv()['decimal_point'] |
59 |
| - clean = re.sub(r'[^0-9'+decimal_point_char+'-'+r']+', '', text) |
| 59 | + |
| 60 | + decimal_point_char = locale.localeconv()["decimal_point"] |
| 61 | + clean = re.sub(r"[^0-9" + decimal_point_char + "-" + r"]+", "", text) |
60 | 62 | return clean
|
61 | 63 |
|
62 | 64 |
|
63 |
| -new_value = df['Value'].apply(remove_currency) |
64 |
| -df['Value'] = new_value |
| 65 | +new_value = df["Value"].apply(remove_currency) |
| 66 | +df["Value"] = new_value |
65 | 67 |
|
66 | 68 | # Add a new column with all USD: Transaction Currency
|
67 |
| -transaction_currency = ["USD" for x in df['Value']] |
68 |
| -df['Transaction Currency'] = transaction_currency |
| 69 | +transaction_currency = ["USD" for x in df["Value"]] |
| 70 | +df["Transaction Currency"] = transaction_currency |
69 | 71 |
|
70 | 72 | # Convert Action to Type
|
71 | 73 | action_to_type = {
|
72 |
| - 'NRA Tax Adj': 'Taxes', |
73 |
| - 'Credit Interest': 'Interest', |
74 |
| - 'NRA Withholding': 'Taxes', |
75 |
| - 'Short Term Cap Gain': 'Dividend', |
76 |
| - 'Long Term Cap Gain': 'Dividend', |
77 |
| - 'Cash Dividend': 'Dividend', |
78 |
| - 'Buy': 'Buy', |
79 |
| - 'Sell': 'Sell', |
80 |
| - 'Wire Received': 'Deposit', |
81 |
| - 'Advisor Fee': 'Fees', |
82 |
| - 'Reinvest Dividend': 'Dividend', |
83 |
| - 'Reinvest Shares': 'Buy', |
84 |
| - 'Bank Interest': 'Dividend', |
85 |
| - 'Funds Received': 'Deposit', |
86 |
| - 'MoneyLink Transfer': 'Deposit', |
| 74 | + "NRA Tax Adj": "Taxes", |
| 75 | + "Credit Interest": "Interest", |
| 76 | + "NRA Withholding": "Taxes", |
| 77 | + "Short Term Cap Gain": "Dividend", |
| 78 | + "Long Term Cap Gain": "Dividend", |
| 79 | + "Cash Dividend": "Dividend", |
| 80 | + "Buy": "Buy", |
| 81 | + "Sell": "Sell", |
| 82 | + "Wire Received": "Deposit", |
| 83 | + "Advisor Fee": "Fees", |
| 84 | + "Reinvest Dividend": "Dividend", |
| 85 | + "Reinvest Shares": "Buy", |
| 86 | + "Bank Interest": "Dividend", |
| 87 | + "Funds Received": "Deposit", |
| 88 | + "MoneyLink Transfer": "Deposit", |
87 | 89 | }
|
88 |
| -new_type = [action_to_type[x] for x in df['Note']] |
89 |
| -df['Type'] = new_type |
| 90 | +new_type = [action_to_type[x] for x in df["Note"]] |
| 91 | +df["Type"] = new_type |
90 | 92 |
|
91 | 93 | # Delete Price column
|
92 |
| -df.drop(columns=['Price'], inplace=True) |
| 94 | +df.drop(columns=["Price"], inplace=True) |
93 | 95 |
|
94 | 96 | # Add SCHWAB1 INT to Notes
|
95 |
| -for k, v in df['Security Name'].items(): |
96 |
| - if v.startswith('SCHWAB1 INT'): |
97 |
| - df.at[k, 'Note'] = df.at[k, 'Note'] + ' ' + v |
| 97 | +for k, v in df["Security Name"].items(): |
| 98 | + if v.startswith("SCHWAB1 INT"): |
| 99 | + df.at[k, "Note"] = df.at[k, "Note"] + " " + v |
98 | 100 |
|
99 | 101 |
|
100 | 102 | # Remove non-security names
|
101 | 103 | def convert_security_name(data: str):
|
102 |
| - if data.startswith('SCHWAB1 INT'): |
103 |
| - return '' |
104 |
| - elif data.startswith('WIRED FUNDS RECEIVED'): |
105 |
| - return '' |
| 104 | + if data.startswith("SCHWAB1 INT"): |
| 105 | + return "" |
| 106 | + elif data.startswith("WIRED FUNDS RECEIVED"): |
| 107 | + return "" |
106 | 108 | else:
|
107 | 109 | return data
|
108 | 110 |
|
109 | 111 |
|
110 |
| -new_security_name = [convert_security_name(v) for v in df['Security Name']] |
111 |
| -df['Security Name'] = new_security_name |
| 112 | +new_security_name = [convert_security_name(v) for v in df["Security Name"]] |
| 113 | +df["Security Name"] = new_security_name |
112 | 114 |
|
113 | 115 | # Write to CSV file
|
114 |
| -df.to_csv(args.pp_csv, index=False, date_format='%Y-%m-%d') |
| 116 | +df.to_csv(args.pp_csv, index=False, date_format="%Y-%m-%d") |
115 | 117 | print(args.pp_csv)
|
0 commit comments