Commit Graph

100 Commits

Author SHA1 Message Date
mindesbunister
d5b3dbbbee fix: Correct ETH-PERP minimum order size to 0.001 ETH
**Problem:**
Config had minOrderSize: 0.01 ETH for ETH-PERP, but user successfully opens positions as small as $4-8 (0.001-0.002 ETH at ~$4000/ETH).

Database shows successful ETH trades:
- $8 positions = 0.002 ETH at $4000/ETH
- $4 positions = 0.001 ETH at $4000/ETH

**Actual Drift Minimum:**
0.001 ETH (~$4 at $4000/ETH), NOT 0.01 ETH

**Fix:**
Updated config/trading.ts:
- minOrderSize: 0.01 → 0.001 ETH
- Updated comment to reflect actual minimum

**Impact:**
-  Accurate minimum validation
-  Small runner positions (0.0005-0.001 ETH) won't be falsely flagged
-  Prevents incorrect "forcing 100% close" on valid sizes
-  Allows proper data collection at $4 position size

**Note:**
The previous fix for checking minOrderSize before close is still valid and needed - it just now uses the correct minimum (0.001 instead of 0.01).
2025-11-03 16:33:31 +01:00
mindesbunister
cfc15cd3b0 fix: Prevent runner positions from being below minimum order size
**Problem:**
When closing small runner positions (5% after TP1+TP2), the calculated size could be below Drift's minimum order size:
- ETH minimum: 0.01 ETH
- After TP1 (75%): 0.0025 ETH left
- After TP2 (80%): 0.0005 ETH runner
- Trailing stop tries to close 0.0005 ETH → ERROR: Below minimum 0.01

n8n showed: "Order size 0.0011 is below minimum 0.01"

**Root Cause:**
closePosition() calculated: sizeToClose = position.size * (percentToClose / 100)
No validation against marketConfig.minOrderSize before submitting to Drift.

**Solution:**
Added minimum size check in closePosition() (lib/drift/orders.ts):
1. Calculate intended close size
2. If below minOrderSize → force 100% close instead
3. Log warning when this happens
4. Prevents Drift API rejection

**Code Change:**
```typescript
let sizeToClose = position.size * (params.percentToClose / 100)

// If calculated size is below minimum, close 100%
if (sizeToClose < marketConfig.minOrderSize) {
  console.log('⚠️ Calculated size below minimum - forcing 100% close')
  sizeToClose = position.size
}
```

**Impact:**
-  Small runner positions close successfully
-  No more "below minimum" errors from Drift
-  Trades complete cleanly
- ⚠️ Runner may close slightly earlier than intended (but better than error)

**Example:**
ETH runner at 0.0005 ETH → tries to close → detects <0.01 → closes entire 0.0005 ETH position at once instead of rejecting.

This is the correct behavior - if the position is already too small, we should close it entirely.
2025-11-03 15:59:31 +01:00
mindesbunister
80635fc0c0 feat: Add position scaling controls to settings UI
**UI Updates (settings page):**
Added new '📈 Position Scaling' section with:
- Enable/disable toggle (defaults to OFF)
- Min quality score slider (60-90, default 75)
- Min profit to scale (0-2%, default 0.4%)
- Scale size percent (10-100%, default 50%)
- Max position multiplier (1-3x, default 2.0x)
- Min ADX increase (0-15, default 5)
- Max price position for scale (50-90%, default 70%)

**Visual Feedback:**
- Purple-themed section with warning banner
- Real-time risk calculator showing:
  * Original position size (SOL example)
  * Scale addition amount
  * Total after 1 scale
  * Maximum possible position size
- Dynamic descriptions explain each parameter
- Warning: 'DISABLED by default' with red indicator

**API Updates:**
Extended /api/settings GET/POST to handle 7 new fields:
- ENABLE_POSITION_SCALING
- MIN_SCALE_QUALITY_SCORE
- MIN_PROFIT_FOR_SCALE
- MAX_SCALE_MULTIPLIER
- SCALE_SIZE_PERCENT
- MIN_ADX_INCREASE
- MAX_PRICE_POSITION_FOR_SCALE

**User Flow:**
1. Navigate to http://localhost:3001/settings
2. Scroll to '📈 Position Scaling' section
3. Toggle 'Enable Position Scaling' to 1
4. Adjust thresholds (defaults are conservative)
5. See live calculation of scaling impact
6. Click 'Save Settings'
7. Click 'Restart Bot' to apply

**Safety:**
- Feature OFF by default (requires explicit opt-in)
- Warning banner explains scaling behavior
- Risk calculator shows maximum exposure
- Conservative defaults prevent aggressive scaling
- All parameters adjustable via sliders

**Example:**
With defaults (SOL $210×10x = $2100):
- Scale adds: $1050 (50% of $2100)
- Total after 1 scale: $3150
- Max position (2x): $4200

User can now enable and configure position scaling without touching .env file!
2025-11-03 15:45:11 +01:00
mindesbunister
8a8d4a348c feat: Add position scaling for strong confirmation signals
**Feature: Position Scaling**
Allows adding to existing profitable positions when high-quality signals confirm trend strength.

**Configuration (config/trading.ts):**
- enablePositionScaling: false (disabled by default - enable after testing)
- minScaleQualityScore: 75 (higher bar than initial 60)
- minProfitForScale: 0.4% (must be at/past TP1)
- maxScaleMultiplier: 2.0 (max 200% of original size)
- scaleSizePercent: 50% (add 50% of original position)
- minAdxIncrease: 5 (ADX must strengthen)
- maxPricePositionForScale: 70% (don't chase resistance)

**Validation Logic (check-risk endpoint):**
Same-direction signal triggers scaling check if enabled:
1. Quality score ≥75 (stronger than initial entry)
2. Position profitable ≥0.4% (at/past TP1)
3. ADX increased ≥5 points (trend strengthening)
4. Price position <70% (not near resistance)
5. Total size <2x original (risk management)
6. Returns 'allowed: true, reason: Position scaling' if all pass

**Execution (execute endpoint):**
- Opens additional position at scale size (50% of original)
- Updates ActiveTrade: timesScaled, totalScaleAdded, currentSize
- Tracks originalAdx from first entry for comparison
- Returns 'action: scaled' with scale details

**ActiveTrade Interface:**
Added fields:
- originalAdx?: number (for scaling validation)
- timesScaled?: number (track scaling count)
- totalScaleAdded?: number (total USD added)

**Example Scenario:**
1. LONG SOL at $176 (quality: 45, ADX: 13.4) - weak but entered
2. Price hits $176.70 (+0.4%) - at TP1
3. New LONG signal (quality: 78, ADX: 19) - strong confirmation
4. Scaling validation:  Quality 78  Profit +0.4%  ADX +5.6  Price 68%
5. Adds 50% more position at $176.70
6. Total position: 150% of original size

**Conservative Design:**
- Disabled by default (requires manual enabling)
- Only scales INTO profitable positions (never averaging down)
- Requires significant quality improvement (75 vs 60)
- Requires trend confirmation (ADX increase)
- Hard cap at 2x original size
- Won't chase near resistance levels

**Next Steps:**
1. Enable in settings: ENABLE_POSITION_SCALING=true
2. Test with small positions first
3. Monitor data: do scaled positions outperform?
4. Adjust thresholds based on results

**Safety:**
- All existing duplicate prevention logic intact
- Flip logic unchanged (still requires quality check)
- Position Manager tracks scaling state
- Can be toggled on/off without code changes
2025-11-03 15:35:33 +01:00
mindesbunister
57f0457f95 fix: Require signal quality check for position flips
**Problem:**
- Signal flips (SHORT→LONG or LONG→SHORT) were auto-approved
- Bypassed signal quality scoring, cooldown, drawdown checks
- User wanted flips ONLY if new signal has strong quality (score ≥60)

**Solution:**
- Removed early return for opposite-direction signals in check-risk
- Flips now go through FULL validation: quality score, cooldown, limits
- Execute endpoint still handles flip logic (close opposite + open new)

**New Flow:**
1. n8n sends flip signal → check-risk endpoint
2. Detects potential flip, logs 'checking quality score'
3. Continues to quality checks (not early return)
4. If score ≥60 AND all checks pass → execute handles flip
5. If score <60 → BLOCKS flip with 'Signal quality too low'

**Result:**
Flips now require signal strength, not just direction change
2025-11-03 14:34:26 +01:00
mindesbunister
6b1d32a72d fix: Add phantom trade detection and prevention safeguards
**Root Causes:**
1. Auto-flip logic could create phantom trades if close failed
2. Position size mismatches (0.01 SOL vs 11.92 SOL expected) not caught
3. Multiple trades for same symbol+direction in database

**Preventive Measures:**

1. **Startup Validation (lib/startup/init-position-manager.ts)**
   - Validates all open trades against Drift positions on startup
   - Auto-closes phantom trades with <50% expected size
   - Logs size mismatches for manual review
   - Prevents Position Manager from tracking ghost positions

2. **Duplicate Position Prevention (app/api/trading/execute/route.ts)**
   - Blocks opening same-direction position on same symbol
   - Returns 400 error if duplicate detected
   - Only allows auto-flip (opposite direction close + open)

3. **Runtime Phantom Detection (lib/trading/position-manager.ts)**
   - Checks position size every 2s monitoring cycle
   - Auto-closes if size ratio <50% (extreme mismatch)
   - Logs as 'manual' exit with AUTO_CLEANUP tx
   - Removes from monitoring immediately

4. **Quality Score Fix (app/api/trading/check-risk/route.ts)**
   - Hardcoded minScore=60 (removed non-existent config reference)

**Prevention Summary:**
-  Startup validation catches historical phantoms
-  Duplicate check prevents new phantoms
-  Runtime detection catches size mismatches <30s after they occur
-  All three layers work together for defense-in-depth

Issue: User had LONG (phantom) + SHORT (undersized 0.01 SOL vs 11.92 expected)
Fix: Both detected and closed, bot now clean with 0 active trades
2025-11-03 13:53:12 +01:00
mindesbunister
1313031acd docs: Update copilot instructions with per-symbol settings
- Updated TP/SL percentages to current values (0.4%/0.7%)
- Added Per-Symbol Configuration section with SOL/ETH controls
- Documented getPositionSizeForSymbol() usage pattern
- Added per-symbol settings to API endpoints documentation
- Updated execute workflow to include symbol enabled checks
- Corrected ETH minimum size (0.01 ETH, not 0.002)
- Added comprehensive Per-Symbol Trading Controls section
2025-11-03 13:33:07 +01:00
mindesbunister
881a99242d feat: Add per-symbol trading controls for SOL and ETH
- Add SymbolSettings interface with enabled/positionSize/leverage fields
- Implement per-symbol ENV variables (SOLANA_*, ETHEREUM_*)
- Add SOL and ETH sections to settings UI with enable/disable toggles
- Add symbol-specific test buttons (SOL LONG/SHORT, ETH LONG/SHORT)
- Update execute and test endpoints to check symbol enabled status
- Add real-time risk/reward calculator per symbol
- Rename 'Position Sizing' to 'Global Fallback' for clarity
- Fix position manager P&L calculation for externally closed positions
- Fix zero P&L bug affecting 12 historical trades
- Add SQL scripts for recalculating historical P&L data
- Move archive TypeScript files to .archive to fix build

Defaults:
- SOL: 10 base × 10x leverage = 100 notional (profit trading)
- ETH:  base × 1x leverage =  notional (data collection)
- Global: 10 × 10x for BTC and other symbols

Configuration priority: Per-symbol ENV > Market config > Global ENV > Defaults
2025-11-03 10:28:48 +01:00
mindesbunister
aa8e9f130a docs: update AI agent instructions with recent fixes
Added documentation for recent improvements:
- MAE/MFE tracking for trade optimization
- On-chain order synchronization after TP1 hits
- Exit reason detection using trade state flags (not current price)
- Per-symbol cooldown to avoid missing opportunities
- Quality score integration in analytics dashboard

Updated workflows and pitfalls sections with lessons learned from debugging session
2025-11-03 08:33:46 +01:00
mindesbunister
0ed2e89c7e feat: implement per-symbol cooldown period
CRITICAL: Cooldown was global across ALL symbols, causing missed opportunities
Example: ETH trade at 10:00 blocked SOL trade at 10:04 (5min cooldown)

Changes:
- Added getLastTradeTimeForSymbol() function to query last trade per symbol
- Updated check-risk endpoint to use symbol-specific cooldown
- Each coin (SOL/ETH/BTC) now has independent cooldown timer
- Cooldown message shows symbol: 'Must wait X min before next SOL-PERP trade'

Result: Can trade ETH and SOL simultaneously without interference
Example: ETH LONG at 10:00, SOL SHORT at 10:01 = both allowed
2025-11-03 08:01:30 +01:00
mindesbunister
0ea8773bdc fix: detect exit reason using trade state flags instead of current price
CRITICAL BUG: Position Manager was using current price to determine exit reason,
but on-chain orders filled at a DIFFERENT price in the past!

Example: LONG entry $184.55, TP1 filled at $184.66, but when Position Manager
checked later (price dropped), it saw currentPrice < TP1 and defaulted to 'SL'

Result: Profitable trades incorrectly labeled as SL exits in database

Fix:
- Use trade.tp1Hit and trade.tp2Hit flags to determine exit reason
- If no TP flags set, use realized P&L to distinguish:
  - Profit >0.5% = TP1 filled
  - Negative P&L = SL filled
- Remove duplicate P&L calculation

This ensures exit reasons match actual on-chain order fills
2025-11-03 00:02:19 +01:00
mindesbunister
da960330f4 fix(n8n): pass quality score from Check Risk to Execute Trade
- Added qualityScore field to Execute Trade node JSON body
- Pulls value from Check Risk response: .item.json.qualityScore
- This enables quality score to be saved in database and displayed on analytics dashboard
2025-11-02 23:51:50 +01:00
mindesbunister
d4aeeb4f99 fix: add MAE/MFE fields to all ActiveTrade initializations
Updated execute, test, and test-db endpoints to include:
- maxFavorableExcursion: 0
- maxAdverseExcursion: 0
- maxFavorablePrice: entryPrice
- maxAdversePrice: entryPrice

Required for TypeScript compilation after adding MAE/MFE tracking
2025-11-02 23:04:02 +01:00
mindesbunister
ee7558b47c fix: remove duplicate line from MAE/MFE implementation 2025-11-02 23:01:34 +01:00
mindesbunister
12d874ff93 feat: implement MAE/MFE tracking for trade optimization
Added Maximum Favorable/Adverse Excursion tracking:
- Track maxFavorableExcursion: best profit % reached during trade
- Track maxAdverseExcursion: worst loss % reached during trade
- Track maxFavorablePrice and maxAdversePrice
- Update every price check (2s interval)
- Save to database on trade exit for optimization analysis

Benefits:
- Identify if TP levels are too conservative (MFE consistently higher)
- Determine if SL is too tight (MAE < SL but trade recovers)
- Optimize runner size based on how often MFE >> TP2
- Data-driven exit strategy tuning after collecting 10-20 trades

Display in monitoring logs: Shows MFE/MAE % every 20 seconds
2025-11-02 23:00:21 +01:00
mindesbunister
7c18e81164 fix: update on-chain SL orders after TP1 hits
CRITICAL: After TP1 closes 75%, the on-chain stop loss orders were NOT being updated
- Position Manager was tracking new SL price internally but not updating Drift orders
- Old SL orders (e.g., $181.69) remained active even after TP1 at $185.28
- This prevented the 'move SL to breakeven after TP1' logic from working

Fix:
- After TP1 hits, cancel ALL old orders on-chain
- Place new SL orders at updated price (breakeven + configured %)
- Place remaining TP2 order for the 25% runner position
- Maintains dual-stop system if enabled

Result: SL will now actually move up on Drift UI after TP1 fires
2025-11-02 22:41:06 +01:00
mindesbunister
9572b54775 fix(drift): calculate realizedPnL with leverage on USD notional, not base asset
- Old calculation: (closePrice - entryPrice) * sizeInBaseAsset = tiny P&L in dollars
- New calculation: profitPercent * leverage * notionalUSD / 100 = correct leveraged P&L
- Example: -0.13% price move * 10x leverage * $540 notional = -$7.02 (not -$0.38)
- Fixes trades showing -$0.10 to -$0.77 losses when they should be -$5 to -$40
- Applied to both DRY_RUN and real execution paths
2025-11-02 20:45:57 +01:00
mindesbunister
bcd1cd0c76 fix(position-manager): correctly handle partial close size conversions to USD
- Convert closePosition.closedSize (base asset) to USD when updating trade.currentSize
- Fix conversion when position.size detected from Drift: set currentSize = position.size * currentPrice
- Prevent trade.currentSize from being reduced to tiny values due to unit mismatch
2025-11-02 20:34:59 +01:00
mindesbunister
202c44e4bc fix: remove qualityScore from Execute Trade body (causes syntax error)
- Execute Trade node was trying to access qualityScore from Check Risk node
- This caused syntax error in n8n when Check Risk blocks the trade
- Backend API calculates qualityScore from the provided metrics (atr, adx, rsi, etc.)
- No need to pass it explicitly in the request body
2025-11-02 16:47:10 +01:00
mindesbunister
32e88c3823 fix: improve signal quality scoring for volume breakouts
- Lower ATR threshold from 0.6% to 0.15% (allows low volatility breakouts)
- Increase volume bonus: +15 for very strong volume (1.5x+), was +10 for 1.2x+
- Add volume breakout logic: High volume (1.4x+) at 95%+ range gets +5 instead of -15 penalty
- Add volume compensation: +10 bonus when volume >1.8x and ATR <0.6%
- Example: SOL signal with 0.18% ATR, 1.74x volume at 95.6% range now scores 70/100 (PASS) instead of 25/100 (BLOCK)
- This signal moved +0.97% and would have hit TP1 (+1.5%) - proves quality scoring was too conservative
- Changes apply globally to all symbols (SOL, ETH, BTC) using same scoring algorithm
2025-11-02 09:10:03 +01:00
mindesbunister
466c0c8001 fix: runner tracking bug - detect TP fills by size reduction
- Position Manager now detects TP1/TP2 fills by monitoring position size reductions instead of entry price mismatches
- When position size reduces by ~75%, marks TP1 as filled and updates currentSize
- When position size reduces by ~95%, marks TP2 as filled and activates trailing stop for 5% runner
- Entry price mismatch check now skipped after TP fills (Drift shows weighted average entry price after partial closes)
- Fixes bug where runners were incorrectly closed after TP1/TP2 fired on-chain
- Adds grace period for new trades (<30s) to avoid false positives during blockchain propagation delays
- This unblocks Phase 1 data collection for signal quality optimization (need 10+ trades with MAE/MFE data)
2025-11-01 20:06:14 +01:00
mindesbunister
056440bf8f feat: add quality score display and timezone fixes
- Add qualityScore to ExecuteTradeResponse interface and response object
- Update analytics page to always show Signal Quality card (N/A if unavailable)
- Fix n8n workflow to pass context metrics and qualityScore to execute endpoint
- Fix timezone in Telegram notifications (Europe/Berlin)
- Fix symbol normalization in /api/trading/close endpoint
- Update Drift ETH-PERP minimum order size (0.002 ETH not 0.01)
- Add transaction confirmation to closePosition() to prevent phantom closes
- Add 30-second grace period for new trades in Position Manager
- Fix execution order: database save before Position Manager.addTrade()
- Update copilot instructions with transaction confirmation pattern
2025-11-01 17:00:37 +01:00
mindesbunister
7788327a4e Update Parse Signal Enhanced for new alert format
- Changed regex from /\.P\s+(\d+)/ to /\b(buy|sell)\s+(\d+|D|W|M)\b/i
- Matches new format: 'ETH buy 15' instead of 'SOL buy .P 15'
- Supports all timeframes: 5, 15, 60, D (daily), W (weekly), M (monthly)
- Updated comment to reflect new format example
2025-11-01 11:12:38 +01:00
mindesbunister
eb2fea7bc0 Clean up alert format - remove .P notation
- Changed 'SOL buy .P 15' to 'SOL buy 15' (cleaner format)
- timeframe.period is already dynamic (no conversion needed)
- Works for any timeframe: 5, 15, 60, 240, D, etc.
- Format: 'ETH buy 15' or 'BTC sell 5' or 'SOL buy 60'
2025-11-01 11:09:37 +01:00
mindesbunister
fe0496121c Fix hardcoded SOL symbol in Pine Script alerts
- Use syminfo.ticker to dynamically get symbol name
- Strip USD/USDT/PERP suffixes to get base currency
- Works for ETH, SOL, BTC, and any other symbol
- Alerts now correctly show 'ETH buy' for Ethereum, 'BTC buy' for Bitcoin, etc.

This fixes the bug where ETH triggers sent 'SOL buy' alerts.
2025-11-01 11:06:14 +01:00
mindesbunister
8f0aa7223d Fix Format Risk node data references
- Updated to Set node v3.4 with proper assignments format
- Explicitly reference Parse Signal Enhanced for rawMessage
- Use $json for Check Risk output (reason, details, score, reasons)
- Properly formatted message with all data fields populated
- Added seconds to timestamp for better tracking
2025-11-01 11:00:13 +01:00
mindesbunister
c70fe45b15 Fix Format Risk message - clean readable format
- Removed ugly escaped syntax with $('Parse Signal').item.json references
- Use $json directly (cleaner and works correctly)
- Issues now display as bullet points instead of comma-separated
- Proper line breaks and formatting
- Professional looking blocked trade notifications
2025-11-01 10:54:30 +01:00
mindesbunister
49a09ef04e Add 'Clear Manual Closes' button to analytics
- New button in analytics page to clear orphaned trades
- API endpoint /api/trading/clear-manual-closes
- Intelligently checks Drift positions before deleting
- Only removes trades with no matching position or mismatched entry price
- Safe operation: keeps trades on error (false positives better than deletions)
- User-friendly confirmation dialog
2025-11-01 02:41:26 +01:00
mindesbunister
c82da51bdc CRITICAL FIX: Add transaction confirmation to detect failed orders
- Added getConnection() method to DriftService
- Added proper transaction confirmation in openPosition()
- Check confirmation.value.err to detect on-chain failures
- Return error if transaction fails instead of assuming success
- Prevents phantom trades that never actually execute

This fixes the issue where bot was recording trades with transaction
signatures that don't exist on-chain (like 2gqrPxnvGzdRp56...).
2025-11-01 02:26:47 +01:00
mindesbunister
a6005b6a5b Add configurable minimum quality score setting
- Added minQualityScore to TradingConfig (default: 60)
- Updated settings UI with slider control (0-100, step 5)
- Updated check-risk endpoint to use config value
- Made scoreSignalQuality function accept minScore parameter
- Updated API to read/write MIN_QUALITY_SCORE env variable
- Allows users to adjust quality threshold from settings page
2025-11-01 01:59:08 +01:00
mindesbunister
553c1f105a fix: increase ETH position size to 0 to meet Drift minimum (0.01 ETH) 2025-10-31 16:40:57 +01:00
mindesbunister
6f1c7bd5e3 fix: update test endpoint to use symbol-specific position sizing 2025-10-31 16:34:25 +01:00
mindesbunister
26f70c6426 feat: implement symbol-specific position sizing for multi-asset trading
- Extended MarketConfig with optional positionSize and leverage fields
- Configured ETH-PERP at  @ 1x leverage for minimal-risk data collection
- Created getPositionSizeForSymbol() helper function in config/trading.ts
- Integrated symbol-specific sizing into execute endpoint
- Added comprehensive guide in docs/guides/SYMBOL_SPECIFIC_SIZING.md

Purpose: Enable ETH trading for faster signal quality data collection
         while preserving SOL's profit-generation sizing (0 @ 10x)

Next: Create ETH alert in TradingView and restart bot
2025-10-31 16:16:03 +01:00
mindesbunister
a2d7cbcc4c Add detailed blocking reasons to risk check notifications
Enhanced 'Format Risk' node in n8n workflow to display:
- Specific blocking reason (duplicate, drawdown, cooldown, quality, etc.)
- Details about what triggered the block
- Quality score if low quality was the reason
- Quality issues breakdown (ATR too low, weak ADX, etc.)

Example output:
 TRADE BLOCKED
SHORT | ATR:0.30 | ADX:19.1 | RSI:46

 Issues: ATR too low (0.30% - dead market), Moderate trend (ADX 19.1), RSI supports short (46.0)
14:23
2025-10-31 14:34:49 +01:00
mindesbunister
d3f385deac Add ATR-based position scaling guide
Comprehensive guide covering:
- How ATR is captured and stored (entry value frozen)
- Static ATR approach (Phases 1-3): Use entry ATR for entire trade
- Dynamic ATR approach (Phase 5+): Real-time updates via TradingView or bot calculation
- Use cases: Dynamic TP/SL, trailing stops, scaling in/out decisions
- Implementation path: Start simple with entry ATR, add real-time later if data supports
- Code examples for all approaches
- Troubleshooting common ATR issues
- Database schema considerations

Explains why waiting for data is critical before implementing advanced ATR features.
2025-10-31 13:34:18 +01:00
mindesbunister
27c6a06d31 Update copilot-instructions.md with latest system features
Major additions:
- Exit strategy details: 3-tier scaling (TP1 75%, TP2 80% of remaining, 5% runner with trailing stop)
- Signal quality system: 5 metrics scored 0-100, filters trades at 60+ threshold
- Runner implementation: Trailing stop activation after TP2, peakPrice tracking
- Database fields: signalQualityScore, MAE/MFE, configSnapshot for state persistence
- New API endpoints: /check-risk, /analytics/last-trade, /restart
- Updated workflows with quality score validation and runner management
- Common pitfalls: Quality score duplication, runner configuration confusion
- Development roadmap: Link to POSITION_SCALING_ROADMAP.md with 6 phases

Critical corrections:
- Position Manager singleton: getPositionManager() → getInitializedPositionManager()
- Updated monitoring loop details with external closure detection and state saving
2025-10-31 12:04:20 +01:00
mindesbunister
1e858cd25d Fix roadmap: Runner already implemented, need to optimize size & trailing stop
Corrections:
- Runner system already exists (5% with 0.3% trailing stop)
- Current +41% trade is the runner in action!
- Phase 5 reframed: Optimize runner size (5% → 10-25% for high quality) and make trailing stop ATR-based
- Updated current state and trade example to reflect actual implementation
2025-10-31 11:59:29 +01:00
mindesbunister
9989f75955 Add position scaling & exit optimization roadmap
- 6-phase development plan: data collection → ATR-based → quality tiers → direction bias → runners → ML
- Each phase has clear prerequisites, implementation tasks, and success criteria
- Decision gates based on data validation (20+ trades for Phase 2, 30+ for Phase 3, etc.)
- Includes SQL queries for analysis and performance validation
- Documents current +41% trade as motivation for runner implementation
- Estimated 3-4 months timeline to complete Phases 1-5
2025-10-31 11:55:34 +01:00
mindesbunister
3c79ecbe55 Display signal quality score on analytics dashboard
- Add signalQualityScore to LastTrade interface
- Display quality score badge in last trade section (0-100)
- Color-coded: green (80+), yellow (70-79), orange (60-69)
- Shows 'Excellent', 'Good', or 'Marginal' label
- Gracefully handles null values (old trades without scores)
- Better layout when quality score is present
2025-10-31 11:34:46 +01:00
mindesbunister
090b79a07f Store signal quality score in database for future analysis
- Add signalQualityScore field to Trade model (0-100)
- Calculate quality score in execute endpoint using same logic as check-risk
- Save score with every trade for correlation analysis
- Create database migration for new field
- Enables future analysis: score vs win rate, P&L, etc.

This allows data-driven decisions on dynamic position sizing
2025-10-31 11:12:07 +01:00
mindesbunister
aecdc108f6 Add last trade details to analytics dashboard
- Add getLastTrade() function to database service
- Create /api/analytics/last-trade endpoint
- Display last trade with full details on analytics page
- Show entry/exit prices, P&L, position size, targets
- Visual indicators for trade direction and exit reason
- Helps quickly diagnose where trades went (TP1, TP2, or SL)
2025-10-31 10:47:19 +01:00
mindesbunister
8a17c2cf90 Fix Position Manager bug: prevent cancelling orders when tracking old trades
Bug: Position Manager was comparing ANY position on the symbol to the trade being
tracked, without verifying entry price match. When a new position opened, it would
think the old tracked trade 'closed externally' and cancel ALL orders - including
the new position's exit orders.

Fix: Added entry price verification (0.5% tolerance). If position entry price doesn't
match the tracked trade, mark the old trade as 'lost tracking' and remove from
monitoring WITHOUT cancelling orders (they belong to the new position).

This prevents the catastrophic scenario where exit orders are repeatedly cancelled,
leaving positions unprotected.
2025-10-31 09:34:48 +01:00
mindesbunister
37ce94d8f1 Restore context metrics in execute endpoint and clean up test files 2025-10-31 09:09:26 +01:00
mindesbunister
c88d94d14d Add n8n nodes with signal quality scoring - ready for import 2025-10-30 19:45:24 +01:00
mindesbunister
15ae57b303 Add signal quality scoring test results - all tests passed 2025-10-30 19:40:55 +01:00
mindesbunister
171c5ed1b7 Add comprehensive signal quality scoring setup guide 2025-10-30 19:38:27 +01:00
mindesbunister
830468d524 Implement signal quality scoring system
- Updated execute endpoint to store context metrics in database
- Updated CreateTradeParams interface with 5 context metrics
- Updated Prisma schema with rsiAtEntry and pricePositionAtEntry
- Ran migration: add_rsi_and_price_position_metrics
- Complete flow: TradingView → n8n → check-risk (scores) → execute (stores)
2025-10-30 19:31:32 +01:00
mindesbunister
781b88f803 Enhance TradingView indicator with context metrics for signal quality
Added 5 context metrics to alert messages:
- ATR% (volatility as % of price)
- ADX (trend strength)
- RSI (momentum)
- VOL (volume ratio vs 20-bar MA)
- POS (price position in 20-bar range 0-100%)

Changes to Pine Script:
- Always calculate ADX (needed for context even if filter disabled)
- Extract ta.rma() calls outside ternary operators (Pine Script requirement)
- Use alert() instead of alertcondition() for dynamic message support
- Changed to single-line string concatenation for compatibility

Alert message format:
OLD: 'Buy SOL 15 | Profile=Hours ATR=10 Mult=3.0'
NEW: 'SOL buy .P 15 | ATR:1.85 | ADX:28.3 | RSI:62.5 | VOL:1.45 | POS:75.3'

Next: Update n8n to parse these metrics, implement signal quality scoring in bot
2025-10-30 15:53:48 +01:00
mindesbunister
7c4adff4e4 Implement risk checks: cooldown, hourly limit, and daily drawdown
Implemented 3 critical risk checks in /api/trading/check-risk:

1. Daily Drawdown Check
   - Blocks trades if today's P&L < maxDailyDrawdown
   - Prevents catastrophic daily losses
   - Currently: -0 limit (configurable via MAX_DAILY_DRAWDOWN)

2. Hourly Trade Limit
   - Blocks trades if tradesInLastHour >= maxTradesPerHour
   - Prevents overtrading / algorithm malfunction
   - Currently: 20 trades/hour (configurable via MAX_TRADES_PER_HOUR)

3. Cooldown Period
   - Blocks trades if timeSinceLastTrade < minTimeBetweenTrades
   - Enforces breathing room between trades
   - Uses minutes (not seconds) thanks to previous commit
   - Currently: 0 min = disabled (configurable via MIN_TIME_BETWEEN_TRADES)

Added database helper functions:
- getLastTradeTime() - Returns timestamp of most recent trade
- getTradesInLastHour() - Counts trades in last 60 minutes
- getTodayPnL() - Sums realized P&L since midnight

All checks include detailed logging with values and thresholds.
Risk check called by n8n workflow before every trade execution.
2025-10-30 10:50:08 +01:00
mindesbunister
b7b0fb9bb2 Change cooldown unit from seconds to minutes
- Updated minTimeBetweenTrades config to use minutes instead of seconds
- Changed default from 600 seconds to 10 minutes
- Updated Settings UI label from 'seconds' to 'minutes' and adjusted range (0-60 min)
- Updated .env comments to reflect new unit
- No functional change since cooldown enforcement not yet implemented (TODO in check-risk route)
2025-10-30 10:35:47 +01:00