Initial release v1.1.0

- Complete MVP for tracking Fidelity brokerage account performance
- Transaction import from CSV with deduplication
- Automatic FIFO position tracking with options support
- Real-time P&L calculations with market data caching
- Dashboard with timeframe filtering (30/90/180 days, 1 year, YTD, all time)
- Docker-based deployment with PostgreSQL backend
- React/TypeScript frontend with TailwindCSS
- FastAPI backend with SQLAlchemy ORM

Features:
- Multi-account support
- Import via CSV upload or filesystem
- Open and closed position tracking
- Balance history charting
- Performance analytics and metrics
- Top trades analysis
- Responsive UI design

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Chris
2026-01-22 14:27:43 -05:00
commit eea4469095
90 changed files with 14513 additions and 0 deletions

199
docs/TIMEFRAME_FILTERING.md Normal file
View File

@@ -0,0 +1,199 @@
# Timeframe Filtering Feature
## Overview
The timeframe filtering feature allows users to view dashboard metrics and charts for specific date ranges, providing better insights into performance over different time periods.
## User Interface
### Location
- Dashboard page (DashboardV2 component)
- Dropdown filter positioned at the top of the dashboard, above metrics cards
### Available Options
1. **All Time** - Shows all historical data
2. **Last 30 Days** - Shows data from the past 30 days
3. **Last 90 Days** - Shows data from the past 90 days
4. **Last 180 Days** - Shows data from the past 180 days (default for chart)
5. **Last 1 Year** - Shows data from the past 365 days
6. **Year to Date** - Shows data from January 1st of current year to today
## What Gets Filtered
### Metrics Cards (Top of Dashboard)
When a timeframe is selected, the following metrics are filtered by position open date:
- Total Positions count
- Open Positions count
- Closed Positions count
- Total Realized P&L
- Total Unrealized P&L
- Win Rate percentage
- Average Win amount
- Average Loss amount
- Current Balance (always shows latest)
### Balance History Chart
The chart adjusts to show the requested number of days:
- All Time: ~10 years (3650 days)
- Last 30 Days: 30 days
- Last 90 Days: 90 days
- Last 180 Days: 180 days
- Last 1 Year: 365 days
- Year to Date: Dynamic calculation from Jan 1 to today
## Implementation Details
### Frontend
#### Component: `DashboardV2.tsx`
```typescript
// State management
const [timeframe, setTimeframe] = useState<TimeframeOption>('all');
// Convert timeframe to days for balance history
const getDaysFromTimeframe = (tf: TimeframeOption): number => {
switch (tf) {
case 'last30days': return 30;
case 'last90days': return 90;
// ... etc
}
};
// Get date range for filtering
const { startDate, endDate } = getTimeframeDates(timeframe);
```
#### API Calls
1. **Overview Stats**:
- Endpoint: `GET /analytics/overview/{account_id}`
- Parameters: `start_date`, `end_date`
- Query key includes timeframe for proper caching
2. **Balance History**:
- Endpoint: `GET /analytics/balance-history/{account_id}`
- Parameters: `days` (calculated from timeframe)
- Query key includes timeframe for proper caching
### Backend
#### Endpoint: `analytics_v2.py`
```python
@router.get("/overview/{account_id}")
def get_overview(
account_id: int,
refresh_prices: bool = False,
max_api_calls: int = 5,
start_date: Optional[date] = None, # NEW
end_date: Optional[date] = None, # NEW
db: Session = Depends(get_db)
):
# Passes dates to calculator
stats = calculator.calculate_account_stats(
account_id,
update_prices=True,
max_api_calls=max_api_calls,
start_date=start_date,
end_date=end_date
)
```
#### Service: `performance_calculator_v2.py`
```python
def calculate_account_stats(
self,
account_id: int,
update_prices: bool = True,
max_api_calls: int = 10,
start_date = None, # NEW
end_date = None # NEW
) -> Dict:
# Filter positions by open date
query = self.db.query(Position).filter(Position.account_id == account_id)
if start_date:
query = query.filter(Position.open_date >= start_date)
if end_date:
query = query.filter(Position.open_date <= end_date)
positions = query.all()
# ... rest of calculation logic
```
## Filter Logic
### Position Filtering
Positions are filtered based on their `open_date`:
- Only positions opened on or after `start_date` are included
- Only positions opened on or before `end_date` are included
- Open positions are always included if they match the date criteria
### Balance History
The balance history shows account balance at end of each day:
- Calculated from transactions within the specified days
- Does not filter by open date, shows actual historical balances
## Caching Strategy
React Query cache keys include timeframe parameters to ensure:
1. Different timeframes don't conflict in cache
2. Changing timeframes triggers new API calls
3. Cache invalidation works correctly
Cache keys:
- Overview: `['analytics', 'overview', accountId, startDate, endDate]`
- Balance: `['analytics', 'balance-history', accountId, timeframe]`
## User Experience
### Performance
- Balance history queries are fast (no market data needed)
- Overview queries use cached prices by default (fast)
- Users can still trigger price refresh within filtered timeframe
### Visual Feedback
- Filter immediately updates both metrics and chart
- Loading states handled by React Query
- Stale data shown while fetching (stale-while-revalidate pattern)
## Testing Checklist
- [ ] All timeframe options work correctly
- [ ] Metrics update when timeframe changes
- [ ] Balance history chart adjusts to show correct date range
- [ ] "All Time" shows complete data
- [ ] Year to Date calculation is accurate
- [ ] Filter persists during price refresh
- [ ] Cache invalidation works properly
- [ ] UI shows loading states appropriately
## Future Enhancements
Potential improvements:
1. Add custom date range picker
2. Compare multiple timeframes side-by-side
3. Save preferred timeframe in user settings
4. Add timeframe filter to Transactions table
5. Add timeframe presets for tax year, quarters
6. Export filtered data to CSV
## Related Components
- `TimeframeFilter.tsx` - Reusable dropdown component
- `getTimeframeDates()` - Helper function to convert timeframe to dates
- `TransactionTable.tsx` - Already uses timeframe filtering
## API Reference
### GET /analytics/overview/{account_id}
```
Query Parameters:
- refresh_prices: boolean (default: false)
- max_api_calls: integer (default: 5)
- start_date: date (optional, format: YYYY-MM-DD)
- end_date: date (optional, format: YYYY-MM-DD)
```
### GET /analytics/balance-history/{account_id}
```
Query Parameters:
- days: integer (default: 30, max: 3650)
```