# Daily Profit Snapshot Architecture

## Why Snapshot Architecture is Critical in Hedge Fund/Trading Systems

### 1. Historical Analytics
- Track account performance over time
- Calculate returns, drawdowns, and risk metrics
- Analyze trading patterns and strategies
- Generate performance reports for investors

### 2. Profit Distribution
- Daily settlement requires accurate equity snapshots
- Calculate daily profit: `current_equity - previous_equity`
- Distribute profits based on unit ownership
- Maintain audit trail for regulatory compliance

### 3. Investor Reporting
- Provide daily/monthly/yearly performance reports
- Show account growth charts
- Calculate ROI for each investor
- Generate tax documents

### 4. Risk Management
- Monitor daily drawdowns
- Track margin usage trends
- Alert on unusual equity changes
- Calculate risk metrics (Sharpe ratio, Max DD, etc.)

### 5. Regulatory Compliance
- Maintain accurate financial records
- Audit trail for all transactions
- Proof of fair profit distribution
- Transparent reporting to investors

## Snapshot Strategy

### Daily Snapshots
- **When**: End of trading day (after market close)
- **What**: Balance, equity, margin, floating profit
- **Purpose**: Daily profit calculation and distribution

### Real-Time Snapshots (Optional)
- **When**: Every 5-15 minutes during trading hours
- **What**: Current account state
- **Purpose**: Real-time monitoring and risk alerts

### Weekly/Monthly Snapshots
- **When**: End of week/month
- **What**: Aggregated performance metrics
- **Purpose**: Periodic reporting and analysis

## Database Schema

### daily_profit_snapshots Table
```sql
CREATE TABLE daily_profit_snapshots (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    mt5_account_id BIGINT UNSIGNED NOT NULL,
    snapshot_date DATE UNIQUE NOT NULL,
    balance DECIMAL(15,2) NOT NULL,
    equity DECIMAL(15,2) NOT NULL,
    margin DECIMAL(15,2) NOT NULL,
    floating_profit DECIMAL(15,2) NOT NULL,
    daily_profit DECIMAL(15,2) NOT NULL,
    open_trades_count INT DEFAULT 0,
    closed_trades_count INT DEFAULT 0,
    snapshot_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    FOREIGN KEY (mt5_account_id) REFERENCES mt5_accounts(id) ON DELETE CASCADE,
    INDEX idx_account_date (mt5_account_id, snapshot_date),
    INDEX idx_date (snapshot_date)
);
```

### Key Design Decisions

**Unique Constraint on snapshot_date**
- Prevents duplicate snapshots for same day
- Ensures data integrity
- Simplifies profit calculation queries

**Decimal Precision (15,2)**
- Supports values up to 999,999,999,999.99
- Sufficient for hedge fund scale
- Standard for financial applications

**Foreign Key with Cascade Delete**
- Automatically cleans up snapshots when account is deleted
- Maintains referential integrity

## Model Architecture

### DailyProfitSnapshot Model
```php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class DailyProfitSnapshot extends Model
{
    protected $fillable = [
        'mt5_account_id',
        'snapshot_date',
        'balance',
        'equity',
        'margin',
        'floating_profit',
        'daily_profit',
        'open_trades_count',
        'closed_trades_count',
        'snapshot_at',
    ];

    protected $casts = [
        'snapshot_date' => 'date',
        'balance' => 'decimal:2',
        'equity' => 'decimal:2',
        'margin' => 'decimal:2',
        'floating_profit' => 'decimal:2',
        'daily_profit' => 'decimal:2',
        'open_trades_count' => 'integer',
        'closed_trades_count' => 'integer',
        'snapshot_at' => 'datetime',
    ];

    public function mt5Account(): BelongsTo
    {
        return $this->belongsTo(Mt5Account::class);
    }
}
```

### Mt5Account Model (Updated)
```php
namespace App\Models;

use App\Models\DailyProfitSnapshot;

class Mt5Account extends Model
{
    public function dailyProfitSnapshots(): HasMany
    {
        return $this->hasMany(DailyProfitSnapshot::class);
    }
}
```

## Snapshot Creation Flow

### Automated Flow (Scheduler)
```
00:00 UTC - Recalculate investor units
00:05 UTC - Create daily profit snapshots
00:10 UTC - Process profit distribution
```

### Manual Flow (API)
```
POST /api/v1/mt5/sync
→ Validates API key
→ Syncs account data
→ Creates/updates snapshot
→ Queues processing job
→ Returns success
```

## Daily Profit Calculation

### Formula
```php
$previousSnapshot = DailyProfitSnapshot::where('mt5_account_id', $accountId)
    ->where('snapshot_date', '<', $today)
    ->orderBy('snapshot_date', 'desc')
    ->first();

$previousEquity = $previousSnapshot ? $previousSnapshot->equity : $account->initial_equity;
$dailyProfit = ($currentEquity - $previousEquity) + $closedTradesProfit;
```

### Example
- Previous equity: $5,000
- Current equity: $5,500
- Closed trades profit: $200
- Daily profit: ($5,500 - $5,000) + $200 = $700

## Best Practices

### 1. Atomic Operations
```php
DB::transaction(function () use ($account, $data) {
    $snapshot = DailyProfitSnapshot::create([...]);
    $account->update(['last_profit_snapshot_at' => now()]);
});
```

### 2. Duplicate Prevention
```php
$snapshot = DailyProfitSnapshot::firstOrCreate(
    [
        'mt5_account_id' => $accountId,
        'snapshot_date' => $today,
    ],
    $snapshotData
);
```

### 3. Error Handling
```php
try {
    $snapshot = $this->createSnapshot($account);
    Log::info("Snapshot created", ['snapshot_id' => $snapshot->id]);
} catch (\Exception $e) {
    Log::error("Snapshot creation failed", ['error' => $e->getMessage()]);
    throw $e;
}
```

### 4. Validation
```php
$validator = Validator::make($data, [
    'balance' => 'required|numeric|min:0',
    'equity' => 'required|numeric|min:0',
    'snapshot_date' => 'required|date|unique:daily_profit_snapshots,snapshot_date,NULL,id,mt5_account_id,' . $accountId,
]);
```

## Query Scopes

### Common Queries
```php
// Get latest snapshot
$snapshot = DailyProfitSnapshot::forAccount($accountId)->latest()->first();

// Get snapshots for date range
$snapshots = DailyProfitSnapshot::forAccount($accountId)
    ->whereBetween('snapshot_date', [$from, $to])
    ->get();

// Get snapshots for specific date
$snapshot = DailyProfitSnapshot::forAccount($accountId)
    ->forDate($date)
    ->first();
```

## Troubleshooting

### Issue: Duplicate snapshot for same day
**Solution**: Use `firstOrCreate()` instead of `create()`

### Issue: Negative daily profit when account grew
**Solution**: Check if previous snapshot exists, use initial equity if not

### Issue: Missing relationship
**Solution**: Ensure `use App\Models\DailyProfitSnapshot;` is imported in Mt5Account model

### Issue: Unique constraint violation
**Solution**: Check if snapshot already exists before creating new one

## Production Considerations

### 1. Index Optimization
- Composite index on (mt5_account_id, snapshot_date)
- Index on snapshot_date for date range queries
- Consider partitioning by date for large datasets

### 2. Data Retention
- Keep daily snapshots for at least 7 years (regulatory requirement)
- Archive older snapshots to cold storage
- Implement data purging policy

### 3. Backup Strategy
- Daily backup of snapshots table
- Point-in-time recovery capability
- Test restore procedures regularly

### 4. Monitoring
- Monitor snapshot creation success rate
- Alert on missing daily snapshots
- Track snapshot creation time
- Monitor disk space usage

## Queue Retry Commands

### Retry Failed Jobs
```bash
# List failed jobs
php artisan queue:failed

# Retry all failed jobs
php artisan queue:retry all

# Retry specific job
php artisan queue:retry <job-id>

# Flush failed jobs
php artisan queue:flush
```

### Monitor Queue
```bash
# Check queue status
php artisan queue:work --status

# List pending jobs
php artisan queue:listen

# Clear queue
php artisan queue:clear
```

## Testing Checklist

- [ ] DailyProfitSnapshot model exists
- [ ] Migration runs successfully
- [ ] Unique constraint on snapshot_date works
- [ ] Relationships are defined correctly
- [ ] Snapshot creation in sync flow works
- [ ] Duplicate snapshots are prevented
- [ ] Daily profit calculation is accurate
- [ ] Queue worker processes snapshots successfully
- [ ] Logs show snapshot creation
- [ ] Error handling works correctly
