fin-infra 0.1.92__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,8 +8,8 @@ This module provides comprehensive financial analytics capabilities including:
8
8
  - Growth projections (net worth forecasting with scenarios)
9
9
 
10
10
  Feature Status:
11
- STABLE: Core calculation functions (all analytics work with provided data)
12
- ⚠️ INTEGRATION: Auto-fetching from providers requires setup:
11
+ [OK] STABLE: Core calculation functions (all analytics work with provided data)
12
+ [!] INTEGRATION: Auto-fetching from providers requires setup:
13
13
  - Banking provider for transaction data
14
14
  - Brokerage provider for investment data
15
15
  - Categorization for expense categorization
@@ -4,7 +4,7 @@ This module provides functionality to record and retrieve historical account bal
4
4
  snapshots over time. This enables balance trend analysis, sparklines, and time-series
5
5
  visualizations in fintech dashboards.
6
6
 
7
- ⚠️ WARNING: This module uses IN-MEMORY storage by default. All data is LOST on restart.
7
+ [!] WARNING: This module uses IN-MEMORY storage by default. All data is LOST on restart.
8
8
  For production use, integrate with svc-infra SQL database or set FIN_INFRA_STORAGE_BACKEND.
9
9
 
10
10
  Features:
@@ -57,7 +57,7 @@ __all__ = [
57
57
  _logger = logging.getLogger(__name__)
58
58
 
59
59
  # In-memory storage for testing (will be replaced with SQL database in production)
60
- # ⚠️ WARNING: All data is LOST on restart when using in-memory storage!
60
+ # [!] WARNING: All data is LOST on restart when using in-memory storage!
61
61
  _balance_snapshots: list[BalanceSnapshot] = []
62
62
  _production_warning_logged = False
63
63
 
@@ -73,7 +73,7 @@ def _check_in_memory_warning() -> None:
73
73
 
74
74
  if env in ("production", "staging") and storage_backend == "memory":
75
75
  _logger.warning(
76
- "⚠️ CRITICAL: Balance history using IN-MEMORY storage in %s environment! "
76
+ "[!] CRITICAL: Balance history using IN-MEMORY storage in %s environment! "
77
77
  "All balance snapshots will be LOST on restart. "
78
78
  "Set FIN_INFRA_STORAGE_BACKEND=sql for production persistence.",
79
79
  env,
@@ -114,7 +114,7 @@ def record_balance_snapshot(
114
114
  This function stores a point-in-time balance record for trend analysis.
115
115
  In production, this would write to a SQL database via svc-infra.
116
116
 
117
- ⚠️ WARNING: Uses in-memory storage by default. Data is LOST on restart!
117
+ [!] WARNING: Uses in-memory storage by default. Data is LOST on restart!
118
118
 
119
119
  Args:
120
120
  account_id: Account identifier
@@ -1,6 +1,6 @@
1
1
  """Brokerage module - easy setup for trading operations.
2
2
 
3
- ⚠️ **TRADING WARNING**: This module provides real trading capabilities.
3
+ [!] **TRADING WARNING**: This module provides real trading capabilities.
4
4
  Always use paper trading mode for development and testing.
5
5
  Live trading requires explicit opt-in and involves real financial risk.
6
6
 
@@ -51,7 +51,7 @@ def easy_brokerage(
51
51
  ) -> BrokerageProvider:
52
52
  """Create a brokerage provider with paper/live trading support.
53
53
 
54
- ⚠️ **SAFETY**: Defaults to paper trading mode. Live trading requires explicit mode="live".
54
+ [!] **SAFETY**: Defaults to paper trading mode. Live trading requires explicit mode="live".
55
55
 
56
56
  Auto-detects provider based on environment variables:
57
57
  1. If ALPACA_API_KEY and ALPACA_API_SECRET are set → Alpaca
@@ -138,7 +138,7 @@ def add_brokerage(
138
138
  ) -> BrokerageProvider:
139
139
  """Wire brokerage provider to FastAPI app with routes and safety checks.
140
140
 
141
- ⚠️ **TRADING WARNING**: This mounts trading API endpoints.
141
+ [!] **TRADING WARNING**: This mounts trading API endpoints.
142
142
  Always use paper trading mode for development.
143
143
  Live trading requires explicit mode="live" and proper safeguards.
144
144
 
@@ -280,7 +280,7 @@ def add_brokerage(
280
280
  async def submit_order(order_request: OrderRequest):
281
281
  """Submit a new order.
282
282
 
283
- ⚠️ **TRADING WARNING**: This endpoint executes real trades in live mode.
283
+ [!] **TRADING WARNING**: This endpoint executes real trades in live mode.
284
284
  """
285
285
  try:
286
286
  order = brokerage_provider.submit_order(
@@ -447,7 +447,7 @@ def add_brokerage(
447
447
  add_prefixed_docs(
448
448
  app,
449
449
  prefix=prefix,
450
- title="Brokerage" + (" (Paper Trading)" if mode == "paper" else " ⚠️ LIVE"),
450
+ title="Brokerage" + (" (Paper Trading)" if mode == "paper" else " [!] LIVE"),
451
451
  auto_exclude_from_root=True,
452
452
  visible_envs=None, # Show in all environments
453
453
  )
@@ -173,7 +173,7 @@ Answer: "To assess your retirement progress, I need more information: (1) What's
173
173
  Follow-ups: ["I want to retire at 65 with $1.5M", "How much should I save monthly?", "What's a realistic retirement goal?"]
174
174
  Sources: []
175
175
 
176
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
176
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
177
177
  Verify calculations independently. For personalized advice, consult a professional."""
178
178
 
179
179
 
@@ -102,7 +102,7 @@ def cmd_scaffold(
102
102
  # Validate required parameters
103
103
  if dest_dir is None:
104
104
  typer.secho(
105
- " Error: --dest-dir is required",
105
+ "[X] Error: --dest-dir is required",
106
106
  fg=typer.colors.RED,
107
107
  err=True,
108
108
  )
@@ -137,7 +137,7 @@ def cmd_scaffold(
137
137
  )
138
138
  else:
139
139
  typer.secho(
140
- f" Unknown domain: {domain}. Must be one of: budgets, goals",
140
+ f"[X] Unknown domain: {domain}. Must be one of: budgets, goals",
141
141
  fg=typer.colors.RED,
142
142
  err=True,
143
143
  )
@@ -145,7 +145,7 @@ def cmd_scaffold(
145
145
 
146
146
  # Display results
147
147
  typer.echo("")
148
- typer.secho("📦 Scaffold Results:", bold=True)
148
+ typer.secho(" Scaffold Results:", bold=True)
149
149
  typer.echo("")
150
150
 
151
151
  files = result.get("files", [])
@@ -157,7 +157,7 @@ def cmd_scaffold(
157
157
  action = file_info.get("action", "unknown")
158
158
 
159
159
  if action == "wrote":
160
- typer.secho(f" Created: {path}", fg=typer.colors.GREEN)
160
+ typer.secho(f" [OK] Created: {path}", fg=typer.colors.GREEN)
161
161
  wrote_count += 1
162
162
  elif action == "skipped":
163
163
  reason = file_info.get("reason", "unknown")
@@ -168,7 +168,7 @@ def cmd_scaffold(
168
168
 
169
169
  # Summary
170
170
  typer.echo("")
171
- typer.secho(f" Done! Created {wrote_count} file(s), skipped {skipped_count}.", bold=True)
171
+ typer.secho(f" Done! Created {wrote_count} file(s), skipped {skipped_count}.", bold=True)
172
172
  typer.echo("")
173
173
 
174
174
  # Next steps
@@ -187,7 +187,7 @@ def cmd_scaffold(
187
187
  }
188
188
  route_prefix = prefix_map.get(domain, f"/{domain}")
189
189
 
190
- typer.secho("📝 Next Steps:", bold=True)
190
+ typer.secho(" Next Steps:", bold=True)
191
191
  typer.echo("")
192
192
  typer.echo(" 1. Review generated files and customize as needed")
193
193
  typer.echo(" 2. Run migrations:")
@@ -182,7 +182,7 @@ Your response: {
182
182
  "confidence": 0.94
183
183
  }
184
184
 
185
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
185
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
186
186
  Verify calculations independently. For personalized advice, consult a professional."""
187
187
 
188
188
  GOAL_PROGRESS_SYSTEM_PROMPT = """You are a financial advisor reviewing goal progress.
@@ -237,7 +237,7 @@ Your response: {
237
237
  "projected_completion_date": "2029-06-01",
238
238
  "variance_from_target_days": -365,
239
239
  "course_corrections": [
240
- "⚠️ 12 months behind! Current $1,000/month payment needs to increase to $1,500/month",
240
+ "[!] 12 months behind! Current $1,000/month payment needs to increase to $1,500/month",
241
241
  "Emergency: reduce expenses by $500/month (cancel subscriptions, cut entertainment)",
242
242
  "Contact debt counselor for consolidation or negotiation options",
243
243
  "Consider side income: gig work, selling unused items ($500/month target)",
@@ -246,7 +246,7 @@ Your response: {
246
246
  "confidence": 0.95
247
247
  }
248
248
 
249
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
249
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
250
250
  Verify calculations independently. For personalized advice, consult a professional."""
251
251
 
252
252
 
@@ -22,7 +22,7 @@ Example:
22
22
  # Check which milestones have been reached
23
23
  reached = check_milestones("goal_123")
24
24
  for m in reached:
25
- print(f"🎉 Milestone reached: {m['description']}")
25
+ print(f" Milestone reached: {m['description']}")
26
26
  """
27
27
 
28
28
  from datetime import datetime
@@ -124,7 +124,7 @@ def check_milestones(goal_id: str) -> list[dict[str, Any]]:
124
124
 
125
125
  reached = check_milestones("goal_123")
126
126
  if reached:
127
- print(f"🎉 {len(reached)} milestones reached!")
127
+ print(f" {len(reached)} milestones reached!")
128
128
  for m in reached:
129
129
  print(f" - {m['description']}: ${m['amount']:,.0f}")
130
130
 
@@ -184,17 +184,17 @@ def get_celebration_message(milestone: dict[str, Any]) -> str:
184
184
 
185
185
  Example:
186
186
  message = get_celebration_message(milestone)
187
- # "🎉 Milestone reached! You've hit $25,000 - 25% to target!"
187
+ # " Milestone reached! You've hit $25,000 - 25% to target!"
188
188
  """
189
189
  amount = milestone["amount"]
190
190
  description = milestone["description"]
191
191
 
192
192
  messages = [
193
- f"🎉 Milestone reached! You've hit ${amount:,.0f} - {description}!",
193
+ f" Milestone reached! You've hit ${amount:,.0f} - {description}!",
194
194
  f"🎊 Congratulations! ${amount:,.0f} milestone achieved - {description}",
195
195
  f"🌟 Great progress! You reached ${amount:,.0f} - {description}",
196
- f"💪 Keep going! ${amount:,.0f} milestone completed - {description}",
197
- f"🚀 Amazing! You hit ${amount:,.0f} - {description}",
196
+ f" Keep going! ${amount:,.0f} milestone completed - {description}",
197
+ f" Amazing! You hit ${amount:,.0f} - {description}",
198
198
  ]
199
199
 
200
200
  # Use amount to pick consistent message for same milestone
@@ -18,15 +18,15 @@ These templates generate production-ready persistence code for investment holdin
18
18
  ## Why Historical Snapshots?
19
19
 
20
20
  **Investment data providers (Plaid, SnapTrade, etc.) only provide current/live data:**
21
- - No historical portfolio values from past dates
22
- - No historical performance metrics
23
- - Cannot answer "What was my portfolio worth 3 months ago?"
21
+ - [X] No historical portfolio values from past dates
22
+ - [X] No historical performance metrics
23
+ - [X] Cannot answer "What was my portfolio worth 3 months ago?"
24
24
 
25
25
  **Solution: Store periodic snapshots in your database**
26
- - Track portfolio value changes over time
27
- - Calculate performance metrics (returns, growth)
28
- - Show trend charts and historical analysis
29
- - Works even if user disconnects provider
26
+ - [OK] Track portfolio value changes over time
27
+ - [OK] Calculate performance metrics (returns, growth)
28
+ - [OK] Show trend charts and historical analysis
29
+ - [OK] Works even if user disconnects provider
30
30
 
31
31
  ## Template Variables
32
32
 
@@ -148,12 +148,12 @@ async def capture_holdings_snapshot(
148
148
  holdings_data: list[dict], # From Plaid/SnapTrade API
149
149
  ) -> None:
150
150
  """Capture current holdings as a snapshot for historical tracking."""
151
-
151
+
152
152
  # Calculate aggregated metrics
153
153
  total_value = sum(Decimal(str(h.get("institution_value", 0))) for h in holdings_data)
154
154
  total_cost_basis = sum(Decimal(str(h.get("cost_basis", 0))) for h in holdings_data if h.get("cost_basis"))
155
155
  total_unrealized_gain_loss = sum(Decimal(str(h.get("unrealized_gain_loss", 0))) for h in holdings_data if h.get("unrealized_gain_loss"))
156
-
156
+
157
157
  # Create snapshot
158
158
  service = create_holding_snapshot_service(session)
159
159
  snapshot = await service.create(HoldingSnapshotCreate(
@@ -167,7 +167,7 @@ async def capture_holdings_snapshot(
167
167
  provider="plaid", # or "snaptrade"
168
168
  notes="Automatic daily snapshot"
169
169
  ))
170
-
170
+
171
171
  await session.commit()
172
172
  ```
173
173
 
@@ -181,18 +181,18 @@ async def daily_holdings_snapshot():
181
181
  """Capture holdings snapshots for all users with investment accounts."""
182
182
  from sqlalchemy import select
183
183
  from my_app.models.user import User
184
-
184
+
185
185
  async with AsyncSession(engine) as session:
186
186
  # Get all users with Plaid/SnapTrade connections
187
187
  stmt = select(User).where(User.banking_providers.isnot(None))
188
188
  result = await session.execute(stmt)
189
189
  users = result.scalars().all()
190
-
190
+
191
191
  for user in users:
192
192
  try:
193
193
  # Fetch current holdings from provider
194
194
  holdings = await fetch_holdings_from_provider(user)
195
-
195
+
196
196
  # Create snapshot
197
197
  await capture_holdings_snapshot(session, user.id, holdings)
198
198
  except Exception as e:
@@ -299,10 +299,10 @@ async def get_portfolio_performance_data(user_id: str):
299
299
  """Get data for portfolio performance dashboard."""
300
300
  async with AsyncSession(engine) as session:
301
301
  repo = create_holding_snapshot_service(session)
302
-
302
+
303
303
  # Get last 12 months trend
304
304
  snapshots = await repo.get_trend(user_id=user_id, months=12)
305
-
305
+
306
306
  # Calculate YTD performance
307
307
  today = date.today()
308
308
  year_start = date(today.year, 1, 1)
@@ -311,10 +311,10 @@ async def get_portfolio_performance_data(user_id: str):
311
311
  start_date=year_start,
312
312
  end_date=today
313
313
  )
314
-
314
+
315
315
  # Get latest snapshot
316
316
  latest = await repo.get_latest(user_id=user_id)
317
-
317
+
318
318
  return {
319
319
  "current_value": latest.total_value if latest else 0,
320
320
  "ytd_return": ytd_performance["percent_return"],
@@ -5,11 +5,11 @@ Calculates net worth by aggregating balances from multiple financial providers
5
5
  (banking, brokerage, crypto) with historical snapshots and change detection.
6
6
 
7
7
  **Feature Status**:
8
- STABLE: Core calculation (works with provided data)
9
- STABLE: Banking integration (Plaid, Teller)
10
- ⚠️ INTEGRATION: Brokerage integration (requires provider setup)
11
- ⚠️ INTEGRATION: Crypto integration (requires provider setup)
12
- ⚠️ INTEGRATION: Currency conversion (pass exchange_rate manually)
8
+ [OK] STABLE: Core calculation (works with provided data)
9
+ [OK] STABLE: Banking integration (Plaid, Teller)
10
+ [!] INTEGRATION: Brokerage integration (requires provider setup)
11
+ [!] INTEGRATION: Crypto integration (requires provider setup)
12
+ [!] INTEGRATION: Currency conversion (pass exchange_rate manually)
13
13
 
14
14
  **Key Features**:
15
15
  - Multi-provider aggregation (banking + brokerage + crypto)
@@ -215,7 +215,7 @@ Response: {
215
215
  "confidence": 0.89
216
216
  }
217
217
 
218
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
218
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
219
219
  Verify calculations independently. For personalized advice, consult a professional."""
220
220
 
221
221
  DEBT_REDUCTION_SYSTEM_PROMPT = """You are a debt counselor using the avalanche method (highest APR first).
@@ -269,7 +269,7 @@ Response: {
269
269
  "confidence": 0.98
270
270
  }
271
271
 
272
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
272
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
273
273
  Verify calculations independently. For personalized advice, consult a professional."""
274
274
 
275
275
  GOAL_RECOMMENDATION_SYSTEM_PROMPT = """You are a financial planner validating goals and suggesting paths.
@@ -322,7 +322,7 @@ Response: {
322
322
  "confidence": 0.89
323
323
  }
324
324
 
325
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
325
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
326
326
  Verify calculations independently. For personalized advice, consult a professional."""
327
327
 
328
328
  ASSET_ALLOCATION_SYSTEM_PROMPT = """You are a portfolio advisor recommending asset allocation.
@@ -365,7 +365,7 @@ Response: {
365
365
  "confidence": 0.91
366
366
  }
367
367
 
368
- ⚠️ This is AI-generated advice. Not a substitute for a certified financial advisor.
368
+ [!] This is AI-generated advice. Not a substitute for a certified financial advisor.
369
369
  Verify calculations independently. For personalized advice, consult a professional."""
370
370
 
371
371
 
@@ -1,6 +1,6 @@
1
1
  """Alpaca brokerage provider for paper and live trading.
2
2
 
3
- ⚠️ IMPORTANT: This module provides real trading capabilities. Always use paper trading
3
+ [!] IMPORTANT: This module provides real trading capabilities. Always use paper trading
4
4
  mode for development and testing. Live trading requires explicit opt-in.
5
5
  """
6
6
 
fin_infra/tax/add.py CHANGED
@@ -279,7 +279,7 @@ def add_tax_data(
279
279
  that can be sold to offset capital gains. Suggests replacement securities
280
280
  to maintain market exposure without triggering wash sale rules.
281
281
 
282
- ⚠️ **DISCLAIMER**: Not a substitute for professional tax or financial advice.
282
+ [!] **DISCLAIMER**: Not a substitute for professional tax or financial advice.
283
283
  Consult a certified tax professional before executing TLH trades.
284
284
 
285
285
  Args:
@@ -344,7 +344,7 @@ def add_tax_data(
344
344
  Projects the outcome of executing provided TLH opportunities, including
345
345
  total tax savings, portfolio impact, and risk assessment.
346
346
 
347
- ⚠️ **DISCLAIMER**: Not a substitute for professional tax or financial advice.
347
+ [!] **DISCLAIMER**: Not a substitute for professional tax or financial advice.
348
348
  Consult a certified tax professional before executing TLH trades.
349
349
 
350
350
  Args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fin-infra
3
- Version: 0.1.92
3
+ Version: 0.2.1
4
4
  Summary: Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations
5
5
  License: MIT
6
6
  Keywords: finance,banking,plaid,brokerage,markets,credit,tax,cashflow,fintech,infra
@@ -28,7 +28,9 @@ Provides-Extra: yahoo
28
28
  Requires-Dist: ai-infra (>=0.1.142)
29
29
  Requires-Dist: cashews[redis] (>=7.0)
30
30
  Requires-Dist: ccxt (>=4.0.0) ; extra == "markets" or extra == "crypto" or extra == "all"
31
+ Requires-Dist: fastapi-users (>=15.0.2,<16.0.0)
31
32
  Requires-Dist: httpx (>=0.25.0)
33
+ Requires-Dist: langchain-core (>=1.2.5,<2.0.0)
32
34
  Requires-Dist: loguru (>=0.7.0)
33
35
  Requires-Dist: numpy (>=1.24.0)
34
36
  Requires-Dist: numpy-financial (>=1.0.0)
@@ -1,6 +1,6 @@
1
1
  fin_infra/__init__.py,sha256=7oL-CCsALNifBODAn9LriicaIrzgJkmVPvE-9duP0mw,1574
2
2
  fin_infra/__main__.py,sha256=1qNP7j0ffw0wFs1dBwDcJ9TNXlC6FcYuulzoV87pMi8,262
3
- fin_infra/analytics/__init__.py,sha256=zjAOFkI9xjg76ozZStYBXEPNwIsioj5fUBltja5JLyc,2327
3
+ fin_infra/analytics/__init__.py,sha256=-OsQUqLgOdafSNzbcIHy3G37nX2OwD0OzGj8C2Aiufs,2325
4
4
  fin_infra/analytics/add.py,sha256=-iAqKdvf9t0gQjjo3uOO56qA_ei4omKYDOynxb4SZPI,12654
5
5
  fin_infra/analytics/cash_flow.py,sha256=VSsQHwTi6r6VFoScH9nu9Fj8XHC4O4B9TkAI8Alobm4,10284
6
6
  fin_infra/analytics/ease.py,sha256=aTAPc-Lmh6XP7REPVlAom38MtKCqeS-auNW-rpXRZJs,14282
@@ -12,9 +12,9 @@ fin_infra/analytics/savings.py,sha256=n3rGNFP8TU5mW-uz9kOuqX_mDiVnDyAeDN06Q7Abot
12
12
  fin_infra/analytics/scenarios.py,sha256=LE_dZVkbxxAx5sxitGhiOhZfWTlYtVbIvS9pEXkijLc,12246
13
13
  fin_infra/analytics/spending.py,sha256=ogLcfF5ZOLMkBIj02RISnA3hiY_PsLWZ2_AAzA7FenY,26209
14
14
  fin_infra/banking/__init__.py,sha256=6wwGNITzyehC9MBQc5jy0ewSTuNetyQu2AdND51O55w,22450
15
- fin_infra/banking/history.py,sha256=BYvKLI_F198TBrtP7vMCCcBcszzFxZkmD-ClCezSVW8,10575
15
+ fin_infra/banking/history.py,sha256=YB-v9A03IZ_qki6A6mA-RO5Y4imlqk1CyP0W482ufdQ,10563
16
16
  fin_infra/banking/utils.py,sha256=HhxZbeaA8zqVttgMiJGnShTo_r_0DaD7T3IMq8n8340,15252
17
- fin_infra/brokerage/__init__.py,sha256=wJpgdOMWNxKt01eUIbu2oSmcFlL189nlWR0-PhLLVFc,17154
17
+ fin_infra/brokerage/__init__.py,sha256=Z5w1vWqETaajWNFPJ3DbHscVpqjlkKtDAJ6O8JgS7Tg,17139
18
18
  fin_infra/budgets/__init__.py,sha256=GgfujfgdVld6_yUf8bhkW-bsIXBLb4THlJMocVpA4mM,3986
19
19
  fin_infra/budgets/add.py,sha256=i7Av--Z14sYQDJHETiF9VL71ouWBZcs3H3VZ62gqFEo,13508
20
20
  fin_infra/budgets/alerts.py,sha256=XDSUPpRR1LNgSQU0Szlht0bLWI7RRBh1ElbcwGexbPs,9701
@@ -39,10 +39,10 @@ fin_infra/categorization/rules.py,sha256=IpDnHBeuykRdu5vs3Lph4Y9-3RseIjjleQ5hZph
39
39
  fin_infra/categorization/taxonomy.py,sha256=p-tSOwJ0O-rFZ1LIlHSYdaYdSc65084j0fdMI_6LW84,13251
40
40
  fin_infra/chat/__init__.py,sha256=-gufQz-rOZVXkcTUcCcXdG2oGL8csJBxwSuOMN_5aVc,6324
41
41
  fin_infra/chat/ease.py,sha256=8T0BQUkWQVpaTooD5-ZtinackkciqGargXnzWzayj3M,3113
42
- fin_infra/chat/planning.py,sha256=Vc3_58XxCnpT-347Q4BV0OY-xNINX79W7hFes4gou60,19915
42
+ fin_infra/chat/planning.py,sha256=goXAHQFv-du89wAHw_X_vm8aF7-HGBeRlyiA_BWx5xw,19912
43
43
  fin_infra/cli/__init__.py,sha256=7M8gKULnui4__9kXRKRHgETuFwZlacK9xrq5rSZ31CM,376
44
44
  fin_infra/cli/cmds/__init__.py,sha256=BvL3wRoUl3cO5wesv1Cqoatup7VeYMhq82tS19iNZHE,136
45
- fin_infra/cli/cmds/scaffold_cmds.py,sha256=CDEg1Ak_2DT6iHtpMk2RfC-BUfP8zDNDA6Ekwa03Pl4,7574
45
+ fin_infra/cli/cmds/scaffold_cmds.py,sha256=bbVSNmnePOS5lqPH1Wq0ohiQWV3UnX_uTIjQkAr5qjs,7564
46
46
  fin_infra/clients/__init__.py,sha256=CL_NUNxLAKFvG7wL_F-rAhUucp6pm0sNHVtvCzVvLcw,708
47
47
  fin_infra/clients/base.py,sha256=fZebDGIfQQybqeXpFpORlDZ6wSKf33aIAkUUpmyvZrA,979
48
48
  fin_infra/clients/plaid.py,sha256=0_kV95vDgasbWyVQe3OEqtVXkF4Q6SNmvHwXXY0gzh8,816
@@ -68,8 +68,8 @@ fin_infra/exceptions.py,sha256=k7L3vfXcONM2-AqmqNhQvOHobVBrLPTYp44cMUxuP3o,16951
68
68
  fin_infra/goals/__init__.py,sha256=iiy7qkPazSSAmPFhy2EXkfJvOBfb7ymrqS1eXBNiaQc,2130
69
69
  fin_infra/goals/add.py,sha256=zobcqEsEzsmd9itSPyPmzpkzFQYZlETo9d17bU9s3mc,20534
70
70
  fin_infra/goals/funding.py,sha256=Fw6hUvb8yNWineEbRXFYgw4_ZRnGrBSChBjkb7Qozrs,9303
71
- fin_infra/goals/management.py,sha256=nf1Es-rdQcp8bAM1FNWonX94CvGMBS1Nis4Q1CWgY0c,33868
72
- fin_infra/goals/milestones.py,sha256=mQHDn9FXVI0HJ9qBHGW25HRwyBjp_MOxjDml7z2kgiw,9996
71
+ fin_infra/goals/management.py,sha256=1Ur76J6-EoxIbLZVnyfw64F4wwTq8Sp5e-YWDk5qVP4,33859
72
+ fin_infra/goals/milestones.py,sha256=1Sq-ZbW_H9Makw-kz4ekuw5kFGeDBNgnyTy-1Lr9TQo,9972
73
73
  fin_infra/goals/models.py,sha256=5X0BddvK9FBsXMTXBQn8YFBNLtIbXue9a4VdLH3rWR8,10173
74
74
  fin_infra/goals/scaffold_templates/README.md,sha256=CoE_3I2K32orOFH6CvfVBaJBTGDYIESd5-48V7vU1FI,9974
75
75
  fin_infra/goals/scaffold_templates/__init__.py,sha256=rLFam-mRsj8LvJu5kRBEIJtw9rFUof7KApgD2IRE56c,107
@@ -87,7 +87,7 @@ fin_infra/investments/providers/__init__.py,sha256=V1eIzz6EnGJ-pq-9L3S2-evmcExF-
87
87
  fin_infra/investments/providers/base.py,sha256=1plM-o_fV6jQyyPnpZT5q8ir96oyxvh0zwA3qpiVIFY,9810
88
88
  fin_infra/investments/providers/plaid.py,sha256=X42cMpsHNcOPcYvl73jrP8x7nQ399n2_it3Ko9UIkI0,18751
89
89
  fin_infra/investments/providers/snaptrade.py,sha256=Hs5uM3F31mGzSONgVXLlL2BR86mjOWs8OhcpLiUeaAo,23251
90
- fin_infra/investments/scaffold_templates/README.md,sha256=PhgxfMLrro2Jz83b7XEnBi7lexiWKqlMrd2UU2Rbs8A,12149
90
+ fin_infra/investments/scaffold_templates/README.md,sha256=q9xB__7xqSK5JTvzsDDHMsFirwWV-7TNn45R0k9F2aE,12081
91
91
  fin_infra/investments/scaffold_templates/__init__.py,sha256=iR0oiAzXFYXHBnVJjaEnAzk6omncYOLg0TKMJ7xomBc,82
92
92
  fin_infra/investments/scaffold_templates/models.py.tmpl,sha256=5inP5-jw-qEfPYxSN71tn4AojZ9PesOIeuHTw181N-c,5849
93
93
  fin_infra/investments/scaffold_templates/repository.py.tmpl,sha256=XwOEpQZfuXut1WLiq-GSSvv0oX0iYCW54eJNL0Cav94,14656
@@ -102,13 +102,13 @@ fin_infra/models/money.py,sha256=63pdGD1WBMHicJ1w7pbU1g5fqt4gIzPuqQQ2-NSlBuc,401
102
102
  fin_infra/models/quotes.py,sha256=-YBzgnjjCihRAprUdaPRtfwKrgliDIGgqAnaM69VbDU,521
103
103
  fin_infra/models/tax.py,sha256=as40J9h24BB7LmeaIfay509UaYEctmk5CPW9CfcjWZc,15657
104
104
  fin_infra/models/transactions.py,sha256=gzc6hLKKU6VUWGshqw2WChU_x0qyXhdvOGwmj9H_H3I,790
105
- fin_infra/net_worth/__init__.py,sha256=4LzVM2Y0OkBlZoD5FUAbLwtORp1okYcsYc4zj0P8C7k,3452
105
+ fin_infra/net_worth/__init__.py,sha256=mTus1Y_JCwWuWMstbkQVlxIJqZa2SWRn3ERUTFVH9xg,3445
106
106
  fin_infra/net_worth/add.py,sha256=QWfHIHJs2CV99WRBqjQ2OteiOrn5cR9nurmxTF9v5rg,23191
107
107
  fin_infra/net_worth/aggregator.py,sha256=9Kx2vUR71QwqYZdGaCfmYrJ1hNxzd1EEuAdWJoNjqTI,12780
108
108
  fin_infra/net_worth/calculator.py,sha256=SQJGJDok5HgvoAhKBxeeqt8vhGMchABU3zPmNRpqNy4,13139
109
109
  fin_infra/net_worth/ease.py,sha256=ERdFrUjjb5l5BRp_c2tEfE1obTpRc_-FA9LnV7BTiEw,15883
110
110
  fin_infra/net_worth/goals.py,sha256=BJGxdsMjvgQDELFEJo-ai3DvsAzUNXvzMXkwovHr8yQ,1238
111
- fin_infra/net_worth/insights.py,sha256=LJ-EI0jQuBVqoFthgDq2PAmwRGorx0dP2Rsm4yNvquY,25221
111
+ fin_infra/net_worth/insights.py,sha256=MdZHrwk4T0WNNIo97DroNelQBDoBr9z70VS05yBXqb8,25209
112
112
  fin_infra/net_worth/models.py,sha256=sZv3dGw5zwckE2XQ7n5ehK7sv4jdGCo9c2g4ZtZHwCI,26880
113
113
  fin_infra/net_worth/scaffold_templates/README.md,sha256=Wqd6ksqFjmtNdDFOWVV_duuAcePWwiu3_YgkVM9N_WY,14363
114
114
  fin_infra/net_worth/scaffold_templates/__init__.py,sha256=OKeMCC_JNw6m8rBWr_wesOIJ1OR9LCBeIkXKahbCGC4,132
@@ -129,7 +129,7 @@ fin_infra/providers/banking/base.py,sha256=KeNU4ur3zLKHVsBF1LQifcs2AKX06IEE-Rx_S
129
129
  fin_infra/providers/banking/plaid_client.py,sha256=8Nvd9Ow_v6Scnw79R86uSvRcBRHPgc3ytsQze50E7aM,6524
130
130
  fin_infra/providers/banking/teller_client.py,sha256=733Eq-o9Yt7Sm_aWOeunJU4EWYRAaZNS7vgDVGqR0W4,10279
131
131
  fin_infra/providers/base.py,sha256=Tqjl5_hSTShgYLrSiKzeDbnL_I-dji-G_itkumm15IM,7722
132
- fin_infra/providers/brokerage/alpaca.py,sha256=X37cKou4jhekY-EHB4WKOa8K66Vkb4m5riDcuVdv7wc,9926
132
+ fin_infra/providers/brokerage/alpaca.py,sha256=BObiI_dFQZ3fOpTfmZMkri8sVrsz5uW6i5ZVUb0etCU,9923
133
133
  fin_infra/providers/brokerage/base.py,sha256=JJFH0Cqca4Rg4rmxfiwcQt-peRoBf4JpG3g6jx8DVks,106
134
134
  fin_infra/providers/credit/experian.py,sha256=r7lpFecgOdNEhb_Lxz2Z-BG8R3p2n0XlqDKL7y8NZ-0,482
135
135
  fin_infra/providers/identity/stripe_identity.py,sha256=JQGJRuQdWP5dWDcROgtz1RrmpkytRv95H6Fn-x1kifU,501
@@ -167,15 +167,15 @@ fin_infra/security/pii_patterns.py,sha256=SM-o7cL6NdgkOmtBedsN2nJZ5QPbeYehZdYmAu
167
167
  fin_infra/security/token_store.py,sha256=FsfoAkIMQ2NRfkBuyG1eH30nnfO3w_V5tDPAZwUj9Os,6041
168
168
  fin_infra/settings.py,sha256=11JgIhjGwWnwixV-hveEWpoWd_JC0ixLnOQoLWCiwNo,1387
169
169
  fin_infra/tax/__init__.py,sha256=U0EUKQwbDqnAYwU8WRx6AD07TaB-ELdKGISOQ-904lw,6103
170
- fin_infra/tax/add.py,sha256=dYigcgQFEP38NLoNuhh7vpSoy07sWX6Z_DTp1tWFJXw,14553
170
+ fin_infra/tax/add.py,sha256=d17Zuoi-xMjuJNykDHzQXnAUVzd_41BUMHQdqm23jJ8,14547
171
171
  fin_infra/tax/tlh.py,sha256=3khtiEkGKIIHi2mbMM0ss-GKQ8vM3FS6hly8R00qseY,21482
172
172
  fin_infra/utils/__init__.py,sha256=x_FUlv7FONdTPHwXTbPWY-EEOBwWnm-y8TPJ1W1PrXM,944
173
173
  fin_infra/utils/deprecation.py,sha256=DTcqv7ECnrWOOwoA07JOnRci4Hqqo9YtKSSmoS-DVPY,5187
174
174
  fin_infra/utils/http.py,sha256=rDEgYsEBrEe75ml5RA-iSs3xeU5W-3j-czJlT7WbrM4,632
175
175
  fin_infra/utils/retry.py,sha256=YiyTgy26eJ1ah7fE2_-ZPa4hv4bIT4OzjYolkNWb5j0,1057
176
176
  fin_infra/version.py,sha256=4t_crzhrLum--oyowUMxtjBTzUtWp7oRTF22ewEvJG4,49
177
- fin_infra-0.1.92.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
178
- fin_infra-0.1.92.dist-info/METADATA,sha256=EqhdCM25a42nfH0YJb-5fs1nhfCIZzI_YbvUQItkamI,10712
179
- fin_infra-0.1.92.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
180
- fin_infra-0.1.92.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
181
- fin_infra-0.1.92.dist-info/RECORD,,
177
+ fin_infra-0.2.1.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
178
+ fin_infra-0.2.1.dist-info/METADATA,sha256=NdGFOF-FPeuEB_BxH8xAhdKjvjdYycn6akhJ9COg0wo,10806
179
+ fin_infra-0.2.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
180
+ fin_infra-0.2.1.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
181
+ fin_infra-0.2.1.dist-info/RECORD,,