fin-infra 0.1.55__py3-none-any.whl → 0.1.57__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.
- fin_infra/banking/history.py +33 -0
- fin_infra/investments/providers/snaptrade.py +32 -18
- fin_infra/models/accounts.py +19 -3
- fin_infra/models/transactions.py +16 -2
- fin_infra/providers/brokerage/alpaca.py +11 -2
- {fin_infra-0.1.55.dist-info → fin_infra-0.1.57.dist-info}/METADATA +8 -8
- {fin_infra-0.1.55.dist-info → fin_infra-0.1.57.dist-info}/RECORD +10 -10
- {fin_infra-0.1.55.dist-info → fin_infra-0.1.57.dist-info}/LICENSE +0 -0
- {fin_infra-0.1.55.dist-info → fin_infra-0.1.57.dist-info}/WHEEL +0 -0
- {fin_infra-0.1.55.dist-info → fin_infra-0.1.57.dist-info}/entry_points.txt +0 -0
fin_infra/banking/history.py
CHANGED
|
@@ -4,6 +4,9 @@ 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.
|
|
8
|
+
For production use, integrate with svc-infra SQL database or set FIN_INFRA_STORAGE_BACKEND.
|
|
9
|
+
|
|
7
10
|
Features:
|
|
8
11
|
- Record daily balance snapshots for accounts
|
|
9
12
|
- Store snapshots in time-series optimized format
|
|
@@ -36,6 +39,8 @@ Integration with svc-infra:
|
|
|
36
39
|
|
|
37
40
|
from __future__ import annotations
|
|
38
41
|
|
|
42
|
+
import logging
|
|
43
|
+
import os
|
|
39
44
|
from datetime import date, datetime, timedelta
|
|
40
45
|
from typing import List, Optional
|
|
41
46
|
from pydantic import BaseModel, Field, ConfigDict
|
|
@@ -50,8 +55,31 @@ __all__ = [
|
|
|
50
55
|
]
|
|
51
56
|
|
|
52
57
|
|
|
58
|
+
_logger = logging.getLogger(__name__)
|
|
59
|
+
|
|
53
60
|
# In-memory storage for testing (will be replaced with SQL database in production)
|
|
61
|
+
# ⚠️ WARNING: All data is LOST on restart when using in-memory storage!
|
|
54
62
|
_balance_snapshots: List[BalanceSnapshot] = []
|
|
63
|
+
_production_warning_logged = False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _check_in_memory_warning() -> None:
|
|
67
|
+
"""Log a warning if using in-memory storage in production."""
|
|
68
|
+
global _production_warning_logged
|
|
69
|
+
if _production_warning_logged:
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
env = os.getenv("ENV", "development").lower()
|
|
73
|
+
storage_backend = os.getenv("FIN_INFRA_STORAGE_BACKEND", "memory").lower()
|
|
74
|
+
|
|
75
|
+
if env in ("production", "staging") and storage_backend == "memory":
|
|
76
|
+
_logger.warning(
|
|
77
|
+
"⚠️ CRITICAL: Balance history using IN-MEMORY storage in %s environment! "
|
|
78
|
+
"All balance snapshots will be LOST on restart. "
|
|
79
|
+
"Set FIN_INFRA_STORAGE_BACKEND=sql for production persistence.",
|
|
80
|
+
env,
|
|
81
|
+
)
|
|
82
|
+
_production_warning_logged = True
|
|
55
83
|
|
|
56
84
|
|
|
57
85
|
class BalanceSnapshot(BaseModel):
|
|
@@ -87,6 +115,8 @@ def record_balance_snapshot(
|
|
|
87
115
|
This function stores a point-in-time balance record for trend analysis.
|
|
88
116
|
In production, this would write to a SQL database via svc-infra.
|
|
89
117
|
|
|
118
|
+
⚠️ WARNING: Uses in-memory storage by default. Data is LOST on restart!
|
|
119
|
+
|
|
90
120
|
Args:
|
|
91
121
|
account_id: Account identifier
|
|
92
122
|
balance: Account balance at the snapshot time
|
|
@@ -103,6 +133,9 @@ def record_balance_snapshot(
|
|
|
103
133
|
- In production, use unique constraint on (account_id, date) in SQL
|
|
104
134
|
- Consider using svc-infra jobs for automatic daily snapshots
|
|
105
135
|
"""
|
|
136
|
+
# Check if in-memory storage is being used in production
|
|
137
|
+
_check_in_memory_warning()
|
|
138
|
+
|
|
106
139
|
snapshot = BalanceSnapshot(
|
|
107
140
|
account_id=account_id,
|
|
108
141
|
balance=balance,
|
|
@@ -20,7 +20,6 @@ from ..models import (
|
|
|
20
20
|
InvestmentAccount,
|
|
21
21
|
InvestmentTransaction,
|
|
22
22
|
Security,
|
|
23
|
-
SecurityType,
|
|
24
23
|
TransactionType,
|
|
25
24
|
)
|
|
26
25
|
from .base import InvestmentProvider
|
|
@@ -96,6 +95,25 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
96
95
|
timeout=30.0,
|
|
97
96
|
)
|
|
98
97
|
|
|
98
|
+
def _auth_headers(self, user_id: str, user_secret: str) -> Dict[str, str]:
|
|
99
|
+
"""Build authentication headers for SnapTrade API requests.
|
|
100
|
+
|
|
101
|
+
SECURITY: User secrets are passed in headers, NOT URL params.
|
|
102
|
+
URL params are logged in access logs, browser history, and proxy logs.
|
|
103
|
+
Headers are not logged by default in most web servers.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
user_id: SnapTrade user ID
|
|
107
|
+
user_secret: SnapTrade user secret (sensitive!)
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dict with authentication headers
|
|
111
|
+
"""
|
|
112
|
+
return {
|
|
113
|
+
"userId": user_id,
|
|
114
|
+
"userSecret": user_secret,
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
async def get_holdings(
|
|
100
118
|
self,
|
|
101
119
|
access_token: str,
|
|
@@ -123,12 +141,12 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
123
141
|
... print(f"{holding.security.ticker_symbol}: P&L ${pnl}")
|
|
124
142
|
"""
|
|
125
143
|
user_id, user_secret = self._parse_access_token(access_token)
|
|
144
|
+
auth_headers = self._auth_headers(user_id, user_secret)
|
|
126
145
|
|
|
127
146
|
try:
|
|
128
147
|
# Get all accounts
|
|
129
148
|
accounts_url = f"{self.base_url}/accounts"
|
|
130
|
-
|
|
131
|
-
response = await self.client.get(accounts_url, params=params)
|
|
149
|
+
response = await self.client.get(accounts_url, headers=auth_headers)
|
|
132
150
|
response.raise_for_status()
|
|
133
151
|
accounts = await response.json()
|
|
134
152
|
|
|
@@ -143,8 +161,7 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
143
161
|
positions_url = (
|
|
144
162
|
f"{self.base_url}/accounts/{account_id}/positions"
|
|
145
163
|
)
|
|
146
|
-
|
|
147
|
-
pos_response = await self.client.get(positions_url, params=pos_params)
|
|
164
|
+
pos_response = await self.client.get(positions_url, headers=auth_headers)
|
|
148
165
|
pos_response.raise_for_status()
|
|
149
166
|
positions = await pos_response.json()
|
|
150
167
|
|
|
@@ -192,12 +209,12 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
192
209
|
raise ValueError("start_date must be before end_date")
|
|
193
210
|
|
|
194
211
|
user_id, user_secret = self._parse_access_token(access_token)
|
|
212
|
+
auth_headers = self._auth_headers(user_id, user_secret)
|
|
195
213
|
|
|
196
214
|
try:
|
|
197
215
|
# Get all accounts
|
|
198
216
|
accounts_url = f"{self.base_url}/accounts"
|
|
199
|
-
|
|
200
|
-
response = await self.client.get(accounts_url, params=params)
|
|
217
|
+
response = await self.client.get(accounts_url, headers=auth_headers)
|
|
201
218
|
response.raise_for_status()
|
|
202
219
|
accounts = await response.json()
|
|
203
220
|
|
|
@@ -212,13 +229,12 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
212
229
|
transactions_url = (
|
|
213
230
|
f"{self.base_url}/accounts/{account_id}/transactions"
|
|
214
231
|
)
|
|
232
|
+
# Date params are non-sensitive, only auth goes in headers
|
|
215
233
|
tx_params = {
|
|
216
|
-
"userId": user_id,
|
|
217
|
-
"userSecret": user_secret,
|
|
218
234
|
"startDate": start_date.isoformat(),
|
|
219
235
|
"endDate": end_date.isoformat(),
|
|
220
236
|
}
|
|
221
|
-
tx_response = await self.client.get(transactions_url, params=tx_params)
|
|
237
|
+
tx_response = await self.client.get(transactions_url, params=tx_params, headers=auth_headers)
|
|
222
238
|
tx_response.raise_for_status()
|
|
223
239
|
transactions = await tx_response.json()
|
|
224
240
|
|
|
@@ -297,12 +313,12 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
297
313
|
... print(f" P&L: {account.total_unrealized_gain_loss_percent:.2f}%")
|
|
298
314
|
"""
|
|
299
315
|
user_id, user_secret = self._parse_access_token(access_token)
|
|
316
|
+
auth_headers = self._auth_headers(user_id, user_secret)
|
|
300
317
|
|
|
301
318
|
try:
|
|
302
319
|
# Get all accounts
|
|
303
320
|
accounts_url = f"{self.base_url}/accounts"
|
|
304
|
-
|
|
305
|
-
response = await self.client.get(accounts_url, params=params)
|
|
321
|
+
response = await self.client.get(accounts_url, headers=auth_headers)
|
|
306
322
|
response.raise_for_status()
|
|
307
323
|
accounts = await response.json()
|
|
308
324
|
|
|
@@ -315,8 +331,7 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
315
331
|
positions_url = (
|
|
316
332
|
f"{self.base_url}/accounts/{account_id}/positions"
|
|
317
333
|
)
|
|
318
|
-
|
|
319
|
-
pos_response = await self.client.get(positions_url, params=pos_params)
|
|
334
|
+
pos_response = await self.client.get(positions_url, headers=auth_headers)
|
|
320
335
|
pos_response.raise_for_status()
|
|
321
336
|
positions = await pos_response.json()
|
|
322
337
|
|
|
@@ -328,8 +343,7 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
328
343
|
|
|
329
344
|
# Get account balances
|
|
330
345
|
balances_url = f"{self.base_url}/accounts/{account_id}/balances"
|
|
331
|
-
|
|
332
|
-
bal_response = await self.client.get(balances_url, params=bal_params)
|
|
346
|
+
bal_response = await self.client.get(balances_url, headers=auth_headers)
|
|
333
347
|
bal_response.raise_for_status()
|
|
334
348
|
balances = await bal_response.json()
|
|
335
349
|
|
|
@@ -373,11 +387,11 @@ class SnapTradeInvestmentProvider(InvestmentProvider):
|
|
|
373
387
|
... print(f"Connected: {conn['brokerage_name']}")
|
|
374
388
|
"""
|
|
375
389
|
user_id, user_secret = self._parse_access_token(access_token)
|
|
390
|
+
auth_headers = self._auth_headers(user_id, user_secret)
|
|
376
391
|
|
|
377
392
|
try:
|
|
378
393
|
url = f"{self.base_url}/connections"
|
|
379
|
-
|
|
380
|
-
response = await self.client.get(url, params=params)
|
|
394
|
+
response = await self.client.get(url, headers=auth_headers)
|
|
381
395
|
response.raise_for_status()
|
|
382
396
|
return await response.json()
|
|
383
397
|
|
fin_infra/models/accounts.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from decimal import Decimal
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from typing import Optional
|
|
5
6
|
|
|
6
|
-
from pydantic import BaseModel
|
|
7
|
+
from pydantic import BaseModel, field_validator
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class AccountType(str, Enum):
|
|
@@ -16,11 +17,26 @@ class AccountType(str, Enum):
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class Account(BaseModel):
|
|
20
|
+
"""Financial account model.
|
|
21
|
+
|
|
22
|
+
Uses Decimal for balance fields to prevent floating-point precision errors
|
|
23
|
+
in financial calculations (e.g., $0.01 + $0.02 != $0.03 with float).
|
|
24
|
+
"""
|
|
19
25
|
id: str
|
|
20
26
|
name: str
|
|
21
27
|
type: AccountType
|
|
22
28
|
mask: Optional[str] = None
|
|
23
29
|
currency: str = "USD"
|
|
24
30
|
institution: Optional[str] = None
|
|
25
|
-
balance_available: Optional[
|
|
26
|
-
balance_current: Optional[
|
|
31
|
+
balance_available: Optional[Decimal] = None
|
|
32
|
+
balance_current: Optional[Decimal] = None
|
|
33
|
+
|
|
34
|
+
@field_validator("balance_available", "balance_current", mode="before")
|
|
35
|
+
@classmethod
|
|
36
|
+
def _coerce_balance_to_decimal(cls, v):
|
|
37
|
+
"""Coerce float/int to Decimal for backwards compatibility."""
|
|
38
|
+
if v is None:
|
|
39
|
+
return v
|
|
40
|
+
if isinstance(v, (int, float)):
|
|
41
|
+
return Decimal(str(v))
|
|
42
|
+
return v
|
fin_infra/models/transactions.py
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from datetime import date
|
|
4
|
+
from decimal import Decimal
|
|
4
5
|
from typing import Optional
|
|
5
6
|
|
|
6
|
-
from pydantic import BaseModel
|
|
7
|
+
from pydantic import BaseModel, field_validator
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Transaction(BaseModel):
|
|
11
|
+
"""Financial transaction model.
|
|
12
|
+
|
|
13
|
+
Uses Decimal for amount to prevent floating-point precision errors
|
|
14
|
+
in financial calculations (e.g., $0.01 + $0.02 != $0.03 with float).
|
|
15
|
+
"""
|
|
10
16
|
id: str
|
|
11
17
|
account_id: str
|
|
12
18
|
date: date
|
|
13
|
-
amount:
|
|
19
|
+
amount: Decimal
|
|
14
20
|
currency: str = "USD"
|
|
15
21
|
description: Optional[str] = None
|
|
16
22
|
category: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
@field_validator("amount", mode="before")
|
|
25
|
+
@classmethod
|
|
26
|
+
def _coerce_amount_to_decimal(cls, v):
|
|
27
|
+
"""Coerce float/int to Decimal for backwards compatibility."""
|
|
28
|
+
if isinstance(v, (int, float)):
|
|
29
|
+
return Decimal(str(v))
|
|
30
|
+
return v
|
|
@@ -105,6 +105,9 @@ class AlpacaBrokerage(BrokerageProvider):
|
|
|
105
105
|
) -> dict:
|
|
106
106
|
"""Submit an order to Alpaca.
|
|
107
107
|
|
|
108
|
+
IMPORTANT: client_order_id is auto-generated if not provided to ensure
|
|
109
|
+
idempotency. Network retries without idempotency can cause DOUBLE ORDERS.
|
|
110
|
+
|
|
108
111
|
Args:
|
|
109
112
|
symbol: Trading symbol (e.g., "AAPL")
|
|
110
113
|
qty: Order quantity
|
|
@@ -113,14 +116,20 @@ class AlpacaBrokerage(BrokerageProvider):
|
|
|
113
116
|
time_in_force: "day", "gtc", "ioc", or "fok" (default: "day")
|
|
114
117
|
limit_price: Limit price (required for limit/stop_limit orders)
|
|
115
118
|
stop_price: Stop price (required for stop/stop_limit orders)
|
|
116
|
-
client_order_id:
|
|
119
|
+
client_order_id: Client order ID for idempotency. Auto-generated if not provided.
|
|
117
120
|
|
|
118
121
|
Returns:
|
|
119
|
-
Order dict with id, status, filled_qty, etc.
|
|
122
|
+
Order dict with id, status, filled_qty, client_order_id, etc.
|
|
120
123
|
|
|
121
124
|
Raises:
|
|
122
125
|
Exception: If order submission fails
|
|
123
126
|
"""
|
|
127
|
+
# CRITICAL: Auto-generate client_order_id for idempotency if not provided.
|
|
128
|
+
# Without this, network retries can cause duplicate order execution = MONEY LOSS.
|
|
129
|
+
if client_order_id is None:
|
|
130
|
+
import uuid
|
|
131
|
+
client_order_id = str(uuid.uuid4())
|
|
132
|
+
|
|
124
133
|
order = self.client.submit_order(
|
|
125
134
|
symbol=symbol,
|
|
126
135
|
qty=qty,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: fin-infra
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.57
|
|
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
|
|
@@ -176,7 +176,7 @@ print(f"Monthly payment: ${monthly:,.2f}")
|
|
|
176
176
|
|
|
177
177
|
## FastAPI Integration
|
|
178
178
|
|
|
179
|
-
Use with [svc-infra](https://github.com/
|
|
179
|
+
Use with [svc-infra](https://github.com/nfraxlab/svc-infra) for a complete backend:
|
|
180
180
|
|
|
181
181
|
```python
|
|
182
182
|
from fastapi import FastAPI
|
|
@@ -306,7 +306,7 @@ This separation keeps financial logic clean and portable.
|
|
|
306
306
|
## Running Examples
|
|
307
307
|
|
|
308
308
|
```bash
|
|
309
|
-
git clone https://github.com/
|
|
309
|
+
git clone https://github.com/nfraxlab/fin-infra.git
|
|
310
310
|
cd fin-infra
|
|
311
311
|
poetry install
|
|
312
312
|
|
|
@@ -327,9 +327,9 @@ fin-infra is part of the **nfrax** infrastructure suite:
|
|
|
327
327
|
|
|
328
328
|
| Package | Purpose |
|
|
329
329
|
|---------|---------|
|
|
330
|
-
| **[fin-infra](https://github.com/
|
|
331
|
-
| **[svc-infra](https://github.com/
|
|
332
|
-
| **[ai-infra](https://github.com/
|
|
330
|
+
| **[fin-infra](https://github.com/nfraxlab/fin-infra)** | Financial infrastructure (banking, portfolio, insights) |
|
|
331
|
+
| **[svc-infra](https://github.com/nfraxlab/svc-infra)** | Backend infrastructure (auth, billing, jobs, webhooks) |
|
|
332
|
+
| **[ai-infra](https://github.com/nfraxlab/ai-infra)** | AI/LLM infrastructure (agents, tools, RAG, MCP) |
|
|
333
333
|
|
|
334
334
|
## License
|
|
335
335
|
|
|
@@ -339,9 +339,9 @@ MIT License - use it for anything.
|
|
|
339
339
|
|
|
340
340
|
<div align="center">
|
|
341
341
|
|
|
342
|
-
**Built by [
|
|
342
|
+
**Built by [nfraxlab](https://github.com/nfraxlab)**
|
|
343
343
|
|
|
344
|
-
[Star us on GitHub](https://github.com/
|
|
344
|
+
[Star us on GitHub](https://github.com/nfraxlab/fin-infra) | [View on PyPI](https://pypi.org/project/fin-infra/)
|
|
345
345
|
|
|
346
346
|
</div>
|
|
347
347
|
|
|
@@ -12,7 +12,7 @@ fin_infra/analytics/savings.py,sha256=tavIRZtu9FjCm-DeWg5f060GcsdgD-cl-vgKOnieOU
|
|
|
12
12
|
fin_infra/analytics/scenarios.py,sha256=LE_dZVkbxxAx5sxitGhiOhZfWTlYtVbIvS9pEXkijLc,12246
|
|
13
13
|
fin_infra/analytics/spending.py,sha256=ypgL52JOsneTsFa2_aFB9fVuu9QWQsImQYChtECeA4Y,25833
|
|
14
14
|
fin_infra/banking/__init__.py,sha256=wva1SEyrH2po79YycQ_00ZyC2tVeuO3uYcyvudOW484,22267
|
|
15
|
-
fin_infra/banking/history.py,sha256=
|
|
15
|
+
fin_infra/banking/history.py,sha256=1ufAwkTnXr-QJetFzJl4xA2e3dqd1-TkT8pf46MNfho,10630
|
|
16
16
|
fin_infra/banking/utils.py,sha256=B2ebnTeUz-56l8XMBWnf2txFOr0bXIo3cKPio7_bhc4,15711
|
|
17
17
|
fin_infra/brokerage/__init__.py,sha256=RB0wbVlxM9PCbWUezzjrOf19JucVDpCvNlT62LoMzho,17023
|
|
18
18
|
fin_infra/budgets/__init__.py,sha256=3VTYU_OdqblYiP5fjHHiw3m-FSj5trPz7XVTb3f3rBc,4106
|
|
@@ -85,7 +85,7 @@ fin_infra/investments/models.py,sha256=NHnkvtMa1QYp_TpuuqT4u3cWEJi3OhW-1e-orMuR4
|
|
|
85
85
|
fin_infra/investments/providers/__init__.py,sha256=V1eIzz6EnGJ-pq-9L3S2-evmcExF-YdZfd5P6JMyDtc,383
|
|
86
86
|
fin_infra/investments/providers/base.py,sha256=cONlsu_z4eSpgzv5ky0-kjWarrC-KYd4tgaghSnarYg,9826
|
|
87
87
|
fin_infra/investments/providers/plaid.py,sha256=OKzLNPAcBiZlqBRCOeaBogB5fvHdvlRpPuGHKvRGS2E,18069
|
|
88
|
-
fin_infra/investments/providers/snaptrade.py,sha256=
|
|
88
|
+
fin_infra/investments/providers/snaptrade.py,sha256=IUgXoI7UCBXOAxn2J62cOiQSW02sujqEk47nb638264,23508
|
|
89
89
|
fin_infra/investments/scaffold_templates/README.md,sha256=PhgxfMLrro2Jz83b7XEnBi7lexiWKqlMrd2UU2Rbs8A,12149
|
|
90
90
|
fin_infra/investments/scaffold_templates/__init__.py,sha256=iR0oiAzXFYXHBnVJjaEnAzk6omncYOLg0TKMJ7xomBc,82
|
|
91
91
|
fin_infra/investments/scaffold_templates/models.py.tmpl,sha256=5inP5-jw-qEfPYxSN71tn4AojZ9PesOIeuHTw181N-c,5849
|
|
@@ -93,14 +93,14 @@ fin_infra/investments/scaffold_templates/repository.py.tmpl,sha256=XwOEpQZfuXut1
|
|
|
93
93
|
fin_infra/investments/scaffold_templates/schemas.py.tmpl,sha256=knWmn-Kyr7AdgPD4ZPMb6T49ZuPXeuOMqmjYNyA0CA0,5451
|
|
94
94
|
fin_infra/markets/__init__.py,sha256=mStcYiA4dq2yHEyStZyOLd-KkW-Jf657l8NSLLa_MU8,9512
|
|
95
95
|
fin_infra/models/__init__.py,sha256=q3SkGzDGFkoAMxwqJw8i4cHWt5NGU5ypjOgntxDGVKo,860
|
|
96
|
-
fin_infra/models/accounts.py,sha256=
|
|
96
|
+
fin_infra/models/accounts.py,sha256=PeobjGg6WM70OvOTe0JIo0zo7tBM0PDAcyClQT-Jo4o,1141
|
|
97
97
|
fin_infra/models/brokerage.py,sha256=z6Zyf0N5zmmXtrN2y_4fNmtIP5wNq40H8lrHLBwY7rc,8311
|
|
98
98
|
fin_infra/models/candle.py,sha256=7vrDxR1JFZodMUG8OGB0ft1_oaGW16gZtawjZ_2OwhA,535
|
|
99
99
|
fin_infra/models/credit.py,sha256=rSdSURsMe9_i2gxmwPTDwNQWOuM2zutL-OhvHsnbtmw,12144
|
|
100
100
|
fin_infra/models/money.py,sha256=5BX8IQZkrNtjjnGIQAK2tyKnVim0R-yc1F_EBxUhcr0,400
|
|
101
101
|
fin_infra/models/quotes.py,sha256=_2cDJS8_RLo4tLpJlqWd32J8uFNP0bbf1V_0u3NuLwo,543
|
|
102
102
|
fin_infra/models/tax.py,sha256=lhNVIW650CdtpfgmSyMMJdojV7QnpHOUFQKiwMLTT4A,15656
|
|
103
|
-
fin_infra/models/transactions.py,sha256=
|
|
103
|
+
fin_infra/models/transactions.py,sha256=zlu7Ath91ZmqQWKn8Bd_iV_XreWTDXFWJyfTTZ3J-ss,828
|
|
104
104
|
fin_infra/net_worth/__init__.py,sha256=EjEuHNg8gEfFwbfko1-o5j-gSUZ2FcO9h7l05C-zAJM,3101
|
|
105
105
|
fin_infra/net_worth/add.py,sha256=5xYy2L5hEEPiQNF79i-ArWVztLXk2XM97DoZYNWGAz8,23100
|
|
106
106
|
fin_infra/net_worth/aggregator.py,sha256=grif-N8qk77L_JQ4IlcOJaKKP1qpxel0lIV_ll3HgjI,12646
|
|
@@ -128,7 +128,7 @@ fin_infra/providers/banking/base.py,sha256=KeNU4ur3zLKHVsBF1LQifcs2AKX06IEE-Rx_S
|
|
|
128
128
|
fin_infra/providers/banking/plaid_client.py,sha256=q0JuU5ULYc2V-RoZGiJQSAprymcsSlJMGmildH0aHDg,6302
|
|
129
129
|
fin_infra/providers/banking/teller_client.py,sha256=r4apwTNt8FJ2Rn2bC97orzaVYFkE0yMXXl--H5rtph0,9800
|
|
130
130
|
fin_infra/providers/base.py,sha256=icMIQ6kmIvN15bkpDCR6C4DC2GaO-oMiFsaUsoWsRag,3303
|
|
131
|
-
fin_infra/providers/brokerage/alpaca.py,sha256=
|
|
131
|
+
fin_infra/providers/brokerage/alpaca.py,sha256=eOzdRp45_VeD1r_2k0IudxFn0IRhGogn-htF5IJVKnk,9862
|
|
132
132
|
fin_infra/providers/brokerage/base.py,sha256=JJFH0Cqca4Rg4rmxfiwcQt-peRoBf4JpG3g6jx8DVks,106
|
|
133
133
|
fin_infra/providers/credit/experian.py,sha256=hNEVqmCaPT72NHV3Nw3sKOYPX0kIsl819ucqUc-7z2k,341
|
|
134
134
|
fin_infra/providers/identity/stripe_identity.py,sha256=JQGJRuQdWP5dWDcROgtz1RrmpkytRv95H6Fn-x1kifU,501
|
|
@@ -173,8 +173,8 @@ fin_infra/utils/http.py,sha256=wgXo5amXyzAX49v_lRUvp4Xxq8nodX32CMJyWl6u89I,568
|
|
|
173
173
|
fin_infra/utils/retry.py,sha256=VxT4ssP4r8Krl3KThvI-opPMhGCpZUCH4rUyit1LEUk,967
|
|
174
174
|
fin_infra/utils.py,sha256=VxT4ssP4r8Krl3KThvI-opPMhGCpZUCH4rUyit1LEUk,967
|
|
175
175
|
fin_infra/version.py,sha256=4t_crzhrLum--oyowUMxtjBTzUtWp7oRTF22ewEvJG4,49
|
|
176
|
-
fin_infra-0.1.
|
|
177
|
-
fin_infra-0.1.
|
|
178
|
-
fin_infra-0.1.
|
|
179
|
-
fin_infra-0.1.
|
|
180
|
-
fin_infra-0.1.
|
|
176
|
+
fin_infra-0.1.57.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
|
|
177
|
+
fin_infra-0.1.57.dist-info/METADATA,sha256=QJ0u6cERtWUuLhAOPspw1HfUdW_bhPw4_wbawiYIaRs,10182
|
|
178
|
+
fin_infra-0.1.57.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
179
|
+
fin_infra-0.1.57.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
|
|
180
|
+
fin_infra-0.1.57.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|