# Test Plan: Tastytrade Transaction Recording

**Issue:** OTB-xxx - Missing transactions for Tastytrade orders  
**Date:** 2025-10-30

## Pre-Test Setup

1. **Start OptraBot** with Tastytrade connection
2. **Clear test data** (optional):
   ```sql
   -- Check current transactions
   SELECT COUNT(*) FROM transactions WHERE tradeid IN (
       SELECT id FROM trades WHERE account = '5WW18591'
   );
   ```

## Test Cases

### Test 1: Single Leg Order (Iron Condor Entry)

**Setup:**
- Template: Iron Condor
- Symbol: SPX
- Broker: Tastytrade
- Entry: 4 legs (Short Call, Long Call, Short Put, Long Put)
- Quantity: 1

**Steps:**
1. Place Iron Condor entry order
2. Wait for fill confirmation
3. Check database

**Expected Results:**
```sql
-- Should see 4 transactions (one per leg)
SELECT * FROM transactions WHERE tradeid = [TRADE_ID];

-- Each transaction should have:
-- - Correct symbol, strike, expiration
-- - Correct sec_type ('Call' or 'Put')
-- - Correct quantity (1)
-- - Price = spread_price / 4 (approximation)
```

**Log Verification:**
```
✅ "Emitting execution details for Tastytrade order [ORDER_ID]: SPX Call 5700 qty=1 @ $0.XX"
✅ "Trade Manager Order Execution Details:"
✅ "Trade [ID]: Execution Details for Entry Order received"
✅ (4 times, once per leg)
```

### Test 2: Multiple Contracts (Quantity > 1)

**Setup:**
- Same as Test 1, but quantity = 2

**Expected Results:**
```sql
-- Should see 4 transactions (one per leg, NOT 8)
SELECT * FROM transactions WHERE tradeid = [TRADE_ID];

-- Each transaction should have:
-- - quantity = 2 (not 1)
```

### Test 3: Multiple FILLED Events (No Duplicates)

**Setup:**
- Any order
- Tastytrade will send multiple FILLED status updates

**Expected Results:**
- **Only ONE set of transactions created**, not multiple duplicates
- `_processed_fills` set prevents duplicate processing

**Log Verification:**
```
✅ Multiple "Update on order [ID] status OrderStatus.FILLED" messages
✅ Only ONE set of "Emitting execution details..." messages
✅ NO duplicate transaction IDs in database
```

### Test 4: Exit Order (Take Profit)

**Setup:**
- Existing trade with entry transactions
- Place exit order (manual or automatic TP)

**Expected Results:**
```sql
-- Should see additional 4 transactions (exit legs)
SELECT * FROM transactions WHERE tradeid = [TRADE_ID] ORDER BY transactionid;

-- transactionid should be sequential: 1, 2, 3, 4, 5, 6, 7, 8
-- Trade status should be CLOSED
```

### Test 5: realizedPNL Calculation

**Setup:**
- Complete trade (entry + exit)
- Check P&L calculation

**Expected Results:**
```sql
SELECT id, status, entry_net_value, exit_net_value, realized_pnl 
FROM trades WHERE id = [TRADE_ID];

-- realizedPNL should be calculated correctly
-- Should match: (exit_net_value - entry_net_value) * 100 * quantity
```

## Verification Queries

### Check Transaction Count
```sql
-- For a specific trade
SELECT COUNT(*) as transaction_count FROM transactions WHERE tradeid = [TRADE_ID];
-- Expected: 4 for entry (or 8 for entry + exit)

-- For all Tastytrade trades
SELECT t.id, t.status, COUNT(tx.id) as tx_count
FROM trades t
LEFT JOIN transactions tx ON tx.tradeid = t.id
WHERE t.account = '5WW18591'
GROUP BY t.id, t.status
ORDER BY t.id DESC
LIMIT 10;
```

### Check Transaction Details
```sql
SELECT 
    transactionid,
    symbol,
    type as action,
    sectype,
    strike,
    contracts,
    price,
    DATE(expiration) as expiration
FROM transactions 
WHERE tradeid = [TRADE_ID]
ORDER BY transactionid;
```

### Check for Duplicates
```sql
-- Should return 0 rows (no duplicates)
SELECT 
    tradeid,
    symbol,
    strike,
    sectype,
    COUNT(*) as dup_count
FROM transactions
WHERE tradeid = [TRADE_ID]
GROUP BY tradeid, symbol, strike, sectype
HAVING COUNT(*) > 1;
```

## Troubleshooting

### Issue: No Transactions Created

**Check:**
1. Was execution details event emitted?
   ```
   grep "Emitting execution details" logs/optrabot_*.log
   ```
2. Was order FILLED?
   ```
   grep "status OrderStatus.FILLED" logs/optrabot_*.log
   ```
3. Was order ID processed?
   - Add debug log to check `_processed_fills` set

### Issue: Wrong Price

**Expected Behavior:**
- Price is **spread price divided by number of legs**
- For Iron Condor @ $0.65 with 4 legs: price = $0.1625 per leg
- This is an **approximation** (Tastytrade API limitation)

### Issue: Duplicate Transactions

**Check:**
1. Is `_processed_fills` working?
2. Are multiple orders being created with same broker order ID?
3. Check logs for "Ignoring" messages

## Success Criteria

✅ All Tastytrade orders create transactions  
✅ Transaction count matches leg count  
✅ No duplicate transactions despite multiple FILLED events  
✅ realizedPNL calculated correctly  
✅ Complete audit trail for compliance  

## Regression Testing

Also verify that **IBKR orders still work correctly**:
- IBKR should continue using per-leg fill prices (more accurate)
- IBKR transactions should have exact prices, not approximations
- No impact on IBKR functionality
