1- """
2- Personal Finance Tracker - Manage your money smartly
3- Features: Expense tracking, budgets, reports, and insights
4- """
5-
61import json
72from datetime import datetime , timedelta
83from pathlib import Path
127
138
149class FinanceTracker :
15- """Track expenses, income, and budgets."""
1610
1711 CATEGORIES = [
1812 "Food & Dining" ,
@@ -36,7 +30,6 @@ def __init__(self):
3630 self .load_data ()
3731
3832 def load_data (self ):
39- """Load financial data from JSON file."""
4033 if self .data_file .exists ():
4134 try :
4235 with open (self .data_file , "r" ) as f :
@@ -48,7 +41,6 @@ def load_data(self):
4841 print (f"β οΈ Error loading data: { e } " )
4942
5043 def save_data (self ):
51- """Save financial data to JSON file."""
5244 try :
5345 with open (self .data_file , "w" ) as f :
5446 json .dump (
@@ -72,7 +64,6 @@ def add_transaction(
7264 transaction_type : str = "expense" ,
7365 date : Optional [str ] = None ,
7466 ):
75- """Add a new transaction."""
7667 if date is None :
7768 date = datetime .now ().isoformat ()
7869
@@ -91,16 +82,13 @@ def add_transaction(
9182 symbol = "π°" if transaction_type == "income" else "πΈ"
9283 print (f"\n { symbol } Transaction added: ${ amount :.2f} - { description } " )
9384
94- # Check budget warnings
9585 if transaction_type == "expense" :
9686 self ._check_budget_warning (category )
9787
9888 def _check_budget_warning (self , category : str ):
99- """Check if category is approaching or over budget."""
10089 if category not in self .budgets :
10190 return
10291
103- # Get current month spending
10492 current_month = datetime .now ().strftime ("%Y-%m" )
10593 month_spending = sum (
10694 t ["amount" ]
@@ -123,19 +111,16 @@ def _check_budget_warning(self, category: str):
123111 )
124112
125113 def set_budget (self , category : str , amount : float ):
126- """Set monthly budget for a category."""
127114 self .budgets [category ] = amount
128115 self .save_data ()
129116 print (f"β
Budget set: { category } = ${ amount :.2f} /month" )
130117
131118 def set_income (self , amount : float ):
132- """Set monthly income."""
133119 self .monthly_income = amount
134120 self .save_data ()
135121 print (f"β
Monthly income set: ${ amount :.2f} " )
136122
137123 def view_transactions (self , limit : int = 10 , category : Optional [str ] = None ):
138- """View recent transactions."""
139124 filtered = self .transactions
140125
141126 if category :
@@ -148,9 +133,7 @@ def view_transactions(self, limit: int = 10, category: Optional[str] = None):
148133 print ("\n π RECENT TRANSACTIONS" )
149134 print ("=" * 70 )
150135
151- # Sort by date, most recent first
152136 sorted_transactions = sorted (filtered , key = lambda x : x ["date" ], reverse = True )
153-
154137 for transaction in sorted_transactions [:limit ]:
155138 date = datetime .fromisoformat (transaction ["date" ]).strftime ("%Y-%m-%d" )
156139 symbol = "+" if transaction ["type" ] == "income" else "-"
@@ -161,25 +144,20 @@ def view_transactions(self, limit: int = 10, category: Optional[str] = None):
161144 print (f"{ date } | { symbol } ${ amount :>8.2f} | { category :<20} | { desc } " )
162145
163146 def monthly_report (self , year : int = None , month : int = None ):
164- """Generate monthly financial report."""
165147 if year is None :
166148 year = datetime .now ().year
167149 if month is None :
168150 month = datetime .now ().month
169151
170152 month_str = f"{ year } -{ month :02d} "
171153 month_name = calendar .month_name [month ]
172-
173- # Filter transactions for this month
174154 month_transactions = [
175155 t for t in self .transactions if t ["date" ].startswith (month_str )
176156 ]
177157
178158 if not month_transactions :
179159 print (f"\n π No transactions for { month_name } { year } " )
180160 return
181-
182- # Calculate totals
183161 total_income = sum (
184162 t ["amount" ] for t in month_transactions if t ["type" ] == "income"
185163 )
@@ -188,14 +166,12 @@ def monthly_report(self, year: int = None, month: int = None):
188166 )
189167 net = total_income - total_expenses
190168
191- # Category breakdown
192169 category_spending = defaultdict (float )
193170 for t in month_transactions :
194171 if t ["type" ] == "expense" :
195172 category_spending [t ["category" ]] += t ["amount" ]
196173
197- # Display report
198- print (f"\n π MONTHLY REPORT - { month_name } { year } " )
174+ print (f"\n MONTHLY REPORT - { month_name } { year } " )
199175 print ("=" * 70 )
200176 print (f"π° Total Income: ${ total_income :>10.2f} " )
201177 print (f"πΈ Total Expenses: ${ total_expenses :>10.2f} " )
@@ -204,12 +180,10 @@ def monthly_report(self, year: int = None, month: int = None):
204180 net_label = "Net Savings" if net >= 0 else "Net Loss"
205181 print (f"π { net_label } : { net_symbol } ${ abs (net ):>10.2f} " )
206182
207- # Budget comparison
208183 if self .monthly_income > 0 :
209184 savings_rate = (net / self .monthly_income ) * 100
210185 print (f"π° Savings Rate: { savings_rate :>9.1f} %" )
211186
212- # Category breakdown
213187 print ("\n π SPENDING BY CATEGORY" )
214188 print ("-" * 70 )
215189
@@ -220,7 +194,6 @@ def monthly_report(self, year: int = None, month: int = None):
220194 for category , amount in sorted_categories :
221195 percentage = (amount / total_expenses ) * 100 if total_expenses > 0 else 0
222196
223- # Budget status
224197 budget_status = ""
225198 if category in self .budgets :
226199 budget = self .budgets [category ]
@@ -233,8 +206,7 @@ def monthly_report(self, year: int = None, month: int = None):
233206 budget_status = f" β οΈ ${ remaining :.2f} left"
234207 else :
235208 budget_status = f" β
${ remaining :.2f} left"
236-
237- # Progress bar
209+
238210 bar_length = 20
239211 filled = int ((percentage / 100 ) * bar_length )
240212 bar = "β" * filled + "β" * (bar_length - filled )
@@ -244,7 +216,6 @@ def monthly_report(self, year: int = None, month: int = None):
244216 )
245217
246218 def budget_overview (self ):
247- """Show budget status for current month."""
248219 current_month = datetime .now ().strftime ("%Y-%m" )
249220
250221 print ("\n π° BUDGET OVERVIEW" )
@@ -255,7 +226,6 @@ def budget_overview(self):
255226 return
256227
257228 for category , budget in sorted (self .budgets .items ()):
258- # Calculate spending
259229 spent = sum (
260230 t ["amount" ]
261231 for t in self .transactions
@@ -266,16 +236,12 @@ def budget_overview(self):
266236
267237 remaining = budget - spent
268238 percentage = (spent / budget ) * 100 if budget > 0 else 0
269-
270- # Status
271239 if percentage >= 100 :
272240 status = "β OVER"
273241 elif percentage >= 80 :
274242 status = "β οΈ WARNING"
275243 else :
276244 status = "β
OK"
277-
278- # Progress bar
279245 bar_length = 20
280246 filled = min (int ((percentage / 100 ) * bar_length ), bar_length )
281247 bar = "β" * filled + "β" * (bar_length - filled )
@@ -285,15 +251,12 @@ def budget_overview(self):
285251 print ()
286252
287253 def insights (self ):
288- """Generate financial insights and recommendations."""
289254 if not self .transactions :
290255 print ("\n π Not enough data for insights yet." )
291256 return
292257
293258 print ("\n π‘ FINANCIAL INSIGHTS" )
294259 print ("=" * 70 )
295-
296- # Average daily spending
297260 if self .transactions :
298261 first_date = min (
299262 datetime .fromisoformat (t ["date" ]) for t in self .transactions
@@ -307,7 +270,6 @@ def insights(self):
307270
308271 print (f"π Average daily spending: ${ avg_daily :.2f} " )
309272
310- # Top spending category
311273 category_totals = defaultdict (float )
312274 for t in self .transactions :
313275 if t ["type" ] == "expense" :
@@ -318,8 +280,6 @@ def insights(self):
318280 print (
319281 f"π Top spending category: { top_category [0 ]} (${ top_category [1 ]:.2f} )"
320282 )
321-
322- # Spending trend
323283 current_month = datetime .now ().strftime ("%Y-%m" )
324284 last_month = (datetime .now () - timedelta (days = 30 )).strftime ("%Y-%m" )
325285
@@ -339,8 +299,7 @@ def insights(self):
339299 change = ((current_spending - last_spending ) / last_spending ) * 100
340300 trend = "π Increasing" if change > 0 else "π Decreasing"
341301 print (f"\n { trend } spending: { abs (change ):.1f} % vs last month" )
342-
343- # Recommendations
302+
344303 print ("\n π° RECOMMENDATIONS:" )
345304
346305 if self .monthly_income > 0 :
@@ -360,13 +319,12 @@ def insights(self):
360319
361320
362321def main ():
363- """Main program interface."""
364322 tracker = FinanceTracker ()
365323
366324 print ("""
367325 βββββββββββββββββββββββββββββββββββββββββ
368326 β π° PERSONAL FINANCE TRACKER π° β
369- β Manage Your Money Smartly β
327+ β Manage Your Money Smartly β
370328 βββββββββββββββββββββββββββββββββββββββββ
371329 """ )
372330
@@ -475,7 +433,7 @@ def main():
475433 break
476434
477435 else :
478- print ("β Invalid choice. Please select 1-9." )
436+ print ("Invalid choice. Please select 1-9." )
479437
480438
481439if __name__ == "__main__" :
0 commit comments