**Documentation Structure:** - Created docs/ subdirectory organization (analysis/, architecture/, bugs/, cluster/, deployments/, roadmaps/, setup/, archived/) - Moved 68 root markdown files to appropriate categories - Root directory now clean (only README.md remains) - Total: 83 markdown files now organized by purpose **New Content:** - Added comprehensive Environment Variable Reference to copilot-instructions.md - 100+ ENV variables documented with types, defaults, purpose, notes - Organized by category: Required (Drift/RPC/Pyth), Trading Config (quality/ leverage/sizing), ATR System, Runner System, Risk Limits, Notifications, etc. - Includes usage examples (correct vs wrong patterns) **File Distribution:** - docs/analysis/ - Performance analyses, blocked signals, profit projections - docs/architecture/ - Adaptive leverage, ATR trailing, indicator tracking - docs/bugs/ - CRITICAL_*.md, FIXES_*.md bug reports (7 files) - docs/cluster/ - EPYC setup, distributed computing docs (3 files) - docs/deployments/ - *_COMPLETE.md, DEPLOYMENT_*.md status (12 files) - docs/roadmaps/ - All *ROADMAP*.md strategic planning files (7 files) - docs/setup/ - TradingView guides, signal quality, n8n setup (8 files) - docs/archived/2025_pre_nov/ - Obsolete verification checklist (1 file) **Key Improvements:** - ENV variable reference: Single source of truth for all configuration - Common Pitfalls #68-71: Already complete, verified during audit - Better findability: Category-based navigation vs 68 files in root - Preserves history: All files git mv (rename), not copy/delete - Zero broken functionality: Only documentation moved, no code changes **Verification:** - 83 markdown files now in docs/ subdirectories - Root directory cleaned: 68 files → 0 files (except README.md) - Git history preserved for all moved files - Container running: trading-bot-v4 (no restart needed) **Next Steps:** - Create README.md files in each docs subdirectory - Add navigation index - Update main README.md with new structure - Consolidate duplicate deployment docs - Archive truly obsolete files (old SQL backups) See: docs/analysis/CLEANUP_PLAN.md for complete reorganization strategy
219 lines
6.1 KiB
Markdown
219 lines
6.1 KiB
Markdown
# Blocked Signals Tracking System
|
|
|
|
**Date Implemented:** November 11, 2025
|
|
**Status:** ✅ ACTIVE
|
|
|
|
## Overview
|
|
|
|
Automatically tracks all signals that get blocked by the trading bot's risk checks. This data allows us to analyze whether blocked signals would have been profitable, helping optimize the signal quality thresholds over time.
|
|
|
|
## What Gets Tracked
|
|
|
|
Every time a signal is blocked, the system saves:
|
|
|
|
### Signal Metrics
|
|
- Symbol (e.g., SOL-PERP)
|
|
- Direction (long/short)
|
|
- Timeframe (5min, 15min, 1H, etc.)
|
|
- Price at signal time
|
|
- ATR, ADX, RSI, volume ratio, price position
|
|
|
|
### Quality Score
|
|
- Calculated score (0-100)
|
|
- Score version (v4 = current)
|
|
- Detailed breakdown of scoring reasons
|
|
- Minimum score required (currently 91, raised Nov 21, 2025)
|
|
- **Why 91?** Perfect separation in 7 v8 trades:
|
|
- ALL winners: quality ≥95 (95, 95, 100, 105)
|
|
- ALL losers: quality ≤90 (80, 90, 90)
|
|
- Would have prevented 100% of losses (-$624.90 total)
|
|
|
|
### Block Reason
|
|
- `QUALITY_SCORE_TOO_LOW` - Score below threshold
|
|
- `COOLDOWN_PERIOD` - Too soon after last trade
|
|
- `HOURLY_TRADE_LIMIT` - Too many trades in last hour
|
|
- `DAILY_DRAWDOWN_LIMIT` - Max daily loss reached
|
|
|
|
### Future Analysis Fields (NOT YET IMPLEMENTED)
|
|
- `priceAfter1Min`, `priceAfter5Min`, `priceAfter15Min`, `priceAfter30Min`
|
|
- `wouldHitTP1`, `wouldHitTP2`, `wouldHitSL`
|
|
- `analysisComplete`
|
|
|
|
These will be filled by a monitoring job that tracks what happened after each blocked signal.
|
|
|
|
## Database Table
|
|
|
|
```sql
|
|
Table: BlockedSignal
|
|
- id (PK)
|
|
- createdAt (timestamp)
|
|
- symbol, direction, timeframe
|
|
- signalPrice, atr, adx, rsi, volumeRatio, pricePosition
|
|
- signalQualityScore, signalQualityVersion, scoreBreakdown (JSON)
|
|
- minScoreRequired, blockReason, blockDetails
|
|
- priceAfter1Min/5Min/15Min/30Min (for future analysis)
|
|
- wouldHitTP1/TP2/SL, analysisComplete
|
|
```
|
|
|
|
## Query Examples
|
|
|
|
### Recent Blocked Signals
|
|
```sql
|
|
SELECT
|
|
symbol,
|
|
direction,
|
|
signalQualityScore as score,
|
|
minScoreRequired as threshold,
|
|
blockReason,
|
|
createdAt
|
|
FROM "BlockedSignal"
|
|
ORDER BY createdAt DESC
|
|
LIMIT 20;
|
|
```
|
|
|
|
### Blocked by Quality Score (60-64 range)
|
|
```sql
|
|
SELECT
|
|
symbol,
|
|
direction,
|
|
signalQualityScore,
|
|
ROUND(atr::numeric, 2) as atr,
|
|
ROUND(adx::numeric, 1) as adx,
|
|
ROUND(rsi::numeric, 1) as rsi,
|
|
ROUND(pricePosition::numeric, 1) as pos,
|
|
blockDetails
|
|
FROM "BlockedSignal"
|
|
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
|
|
AND signalQualityScore >= 60
|
|
AND signalQualityScore < 65
|
|
ORDER BY createdAt DESC;
|
|
```
|
|
|
|
### Breakdown by Block Reason
|
|
```sql
|
|
SELECT
|
|
blockReason,
|
|
COUNT(*) as count,
|
|
ROUND(AVG(signalQualityScore)::numeric, 1) as avg_score,
|
|
MIN(signalQualityScore) as min_score,
|
|
MAX(signalQualityScore) as max_score
|
|
FROM "BlockedSignal"
|
|
GROUP BY blockReason
|
|
ORDER BY count DESC;
|
|
```
|
|
|
|
### Today's Blocked Signals
|
|
```sql
|
|
SELECT
|
|
TO_CHAR(createdAt, 'HH24:MI:SS') as time,
|
|
symbol,
|
|
direction,
|
|
signalQualityScore,
|
|
blockReason
|
|
FROM "BlockedSignal"
|
|
WHERE createdAt >= CURRENT_DATE
|
|
ORDER BY createdAt DESC;
|
|
```
|
|
|
|
## Analysis Workflow
|
|
|
|
### Step 1: Collect Data (Current Phase)
|
|
- Bot automatically saves blocked signals
|
|
- Wait for 10-20 blocked signals to accumulate
|
|
- No action needed - runs automatically
|
|
|
|
### Step 2: Manual Analysis (When Ready)
|
|
```sql
|
|
-- Check how many blocked signals we have
|
|
SELECT COUNT(*) FROM "BlockedSignal";
|
|
|
|
-- Analyze score distribution
|
|
SELECT
|
|
CASE
|
|
WHEN signalQualityScore >= 60 THEN '60-64 (Close Call)'
|
|
WHEN signalQualityScore >= 55 THEN '55-59 (Marginal)'
|
|
WHEN signalQualityScore >= 50 THEN '50-54 (Weak)'
|
|
ELSE '0-49 (Very Weak)'
|
|
END as score_tier,
|
|
COUNT(*) as count,
|
|
ROUND(AVG(atr)::numeric, 2) as avg_atr,
|
|
ROUND(AVG(adx)::numeric, 1) as avg_adx
|
|
FROM "BlockedSignal"
|
|
WHERE blockReason = 'QUALITY_SCORE_TOO_LOW'
|
|
GROUP BY score_tier
|
|
ORDER BY MIN(signalQualityScore) DESC;
|
|
```
|
|
|
|
### Step 3: Future Automation (Not Yet Built)
|
|
Create a monitoring job that:
|
|
1. Fetches `BlockedSignal` records where `analysisComplete = false` and `createdAt` > 30min ago
|
|
2. Gets price history for those timestamps
|
|
3. Calculates if TP1/TP2/SL would have been hit
|
|
4. Updates the record with analysis results
|
|
5. Sets `analysisComplete = true`
|
|
|
|
## Integration Points
|
|
|
|
### Code Files Modified
|
|
1. `prisma/schema.prisma` - Added `BlockedSignal` model
|
|
2. `lib/database/trades.ts` - Added `createBlockedSignal()` function
|
|
3. `app/api/trading/check-risk/route.ts` - Saves blocked signals
|
|
|
|
### Where Blocking Happens
|
|
- Quality score check (line ~311-350)
|
|
- Cooldown period check (line ~281-303)
|
|
- Hourly trade limit (line ~235-258)
|
|
- Daily drawdown limit (line ~211-223)
|
|
|
|
## Next Steps
|
|
|
|
### Phase 1: Data Collection (CURRENT)
|
|
- ✅ Database table created
|
|
- ✅ Automatic saving implemented
|
|
- ✅ Bot deployed and running
|
|
- ⏳ Collect 10-20 blocked signals (wait ~1-2 weeks)
|
|
|
|
### Phase 2: Analysis
|
|
- Query blocked signal patterns
|
|
- Identify "close calls" (score 60-64)
|
|
- Compare with executed trades that had similar scores
|
|
- Determine if threshold adjustment is warranted
|
|
|
|
### Phase 3: Automation (Future)
|
|
- Build price monitoring job
|
|
- Auto-calculate would-be outcomes
|
|
- Generate reports on missed opportunities
|
|
- Feed data into threshold optimization algorithm
|
|
|
|
## Benefits
|
|
|
|
1. **Data-Driven Decisions** - No guessing, only facts
|
|
2. **Prevents Over-Optimization** - Wait for statistically significant sample
|
|
3. **Tracks All Block Reasons** - Not just quality score
|
|
4. **Historical Record** - Can review past decisions
|
|
5. **Continuous Improvement** - System learns from what it blocks
|
|
|
|
## Important Notes
|
|
|
|
⚠️ **Don't change thresholds prematurely!**
|
|
- 2 trades is NOT enough data
|
|
- Wait for 10-20 blocked signals minimum
|
|
- Analyze patterns before making changes
|
|
|
|
✅ **System is working correctly if:**
|
|
- Blocked signals appear in database
|
|
- Each has metrics (ATR, ADX, RSI, etc.)
|
|
- Block reason is recorded
|
|
- Timestamp is correct
|
|
|
|
❌ **Troubleshooting:**
|
|
- If no blocked signals appear: Check bot is receiving TradingView alerts with metrics
|
|
- If missing metrics: Ensure TradingView webhook includes ATR/ADX/RSI/volume/pricePosition
|
|
- If database errors: Check Prisma client is regenerated after schema changes
|
|
|
|
---
|
|
|
|
**Last Updated:** November 11, 2025
|
|
**Version:** 1.0
|
|
**Maintained By:** Trading Bot v4 Development Team
|