- Changed Format Success from Set node (n8n-nodes-base.set) to Code node (n8n-nodes-base.code)
- Set nodes with complex inline JS expressions often fail to evaluate, returning raw template code
- Code node typeVersion 2 properly executes JavaScript with template literals
- Fixes Telegram receiving raw ${resp.symbol} instead of actual values
Affects:
- Smart Entry queue messages
- Trade opened messages
- Signal processed messages
IMPORTANT: User must import updated workflow to n8n via:
1. Open https://flow.egonetix.de
2. Money Machine workflow → Settings → Export
4. Import workflows/trading/Money_Machine.json
- Optimized indicator was missing Direction Mode feature (Long Only)
- Copied working moneyline_v11_2_indicator.pinescript over broken optimized version
- Direction Mode defaults to 'Long Only' (disables SHORT signals)
- Key feature: allowLong/allowShort gates final signals based on direction setting
- Green supertrend line now properly sticks to candles with plot.style_linebr
- Added Monte Carlo simulation notebook for v11.2 projections
Files changed:
- workflows/trading/moneyline_v11_2_optimized_indicator.pinescript (restored)
- docs/analysis/v11_compounding_simulation.ipynb (new)
- Updated CURRENT ACTIVE SYSTEM section with Direction Mode feature
- Default: 'Long Only' (84% win rate on LONGs, SHORTs disabled until optimized)
- Added allowLong/allowShort filter logic documentation
- Updated Last Updated date to Jan 2, 2026 with commit reference
- Added 'Trade Direction' dropdown (Both/Long Only/Short Only)
- Default set to 'Long Only' to disable SHORT signals
- Signals filtered by allowLong/allowShort before alerts fire
- Debug table shows current direction mode setting
- User discovered 84% win rate on LONGs - shorts need optimization
- Production ready for LONG-only live trading
CRITICAL BUG FIXED (Jan 2, 2026):
- Old backtest treated SHORT signal as 'exit LONG only' (reversal system)
- Live trading opens actual SHORT position = different outcome
- Backtest showed profit but live trading lost money due to mismatch
Changes:
- Added close_entries_rule='ANY' to strategy declaration
- Opposite signal now CLOSES current position first, then opens NEW
- Added 'Direction Mode' dropdown: Both / Long Only / Short Only
- Comments document the fix for future reference
This allows honest evaluation:
1. Run 'Both' mode to see true combined performance
2. Run 'Long Only' to see LONG-only results
3. Run 'Short Only' to see SHORT-only results (likely the problem area)
Root Cause: Math.floor(sizeToClose * 1e9) truncated position sizes, leaving tiny fractional remnants (e.g., 0.00000008 SOL) that prevented full position closure.
Discovery: Drift UI 'Close All Positions' failed with 'not enough collateral' but clicking 'Market' order worked - because Market uses exact position size.
Solution: SDK's driftClient.closePosition() uses exact BN arithmetic internally (baseAssetAmount.abs()), avoiding any floating point truncation.
Changes:
- lib/drift/orders.ts lines 647-690
- For 100% closes: Now uses driftClient.closePosition(marketIndex)
- For partial closes: Continues using placeAndTakePerpOrder
Expected Impact: Flip operations will now fully close positions without leaving fractional remnants that cause 'position still open' failures.
Financial Impact: Prevents flip failures that caused user 000+ losses from multiple bugs in position closing logic.
ROOT CAUSE: placePerpOrder() only places orders on Drift order book, doesn't fill.
SOLUTION: placeAndTakePerpOrder() places AND matches against makers atomically.
Real Incident (Dec 31, 2025):
- Dec 30 18:17: SHORT opened at $124.36
- Dec 31 00:30: LONG signal received - should flip position
- Transaction confirmed but Solscan showed 'Place' not 'Fill'
- Position remained open, eventually hit SL twice
- Total loss: ~$40.21
Files changed:
- lib/drift/orders.ts (line 662): placePerpOrder → placeAndTakePerpOrder
- docs/COMMON_PITFALLS.md: Added Bug #90 documentation
Deployment: Dec 31, 2025 11:38 CET (container trading-bot-v4)
- Q95 strategy section marked as ARCHIVED (superseded by v11.2)
- 5-Candle Time Exit marked as REMOVED (commit 9036252)
- Updated 'Filters Applied' to note 5-candle removal
- Added references to v11.2 as current production system
- v11.2 backtest (+53.80% return, PF 2.617) did NOT include 5-candle rule
- Removed TIME_EXIT_5_CANDLE logic from position-manager.ts
- v11.2 backtest (+53.80%) didn't include this exit rule
- Trades will now be allowed to reach TP1 (+1.1%) instead of early exit
- Previous behavior: Exit after 25min if MFE < $30 (force-exited -0.20% trade)
- New behavior: Let trades run to configured TP1/SL levels
Rationale: The 5-candle rule was from an older Q>=95 strategy optimization.
v11.2 indicator already filters to PF 2.617 profitable setups, additional
time-based filtering was counter-productive and introduced untested behavior.
- Corrected comment from +50%/2.507 to actual verified +53.80%/2.617
- 202 trades, 8.35% max drawdown confirmed via user screenshot
- At 5x leverage: ~269% monthly return potential, 00 → 00-,100
- Created comprehensive exit strategy analysis from 30-day backtest
- Key finding: Average loss -1.84 vs average win /bin/bash.76 (42 asymmetry)
- Root cause: Position management not working, not entry quality
- Dynamic thresholds tested: only +.21/month improvement (rejected)
- Backtesting infrastructure: 487-line Python script with regime analysis
- Database: PostgreSQL integration for 78 real trades Nov 23 - Dec 23
- Next steps: Fix exit strategy, not thresholds (exits are the problem)
- Insert 'Check Skip Notification' IF node between Format Risk and Telegram Risk
- Route TRUE branch (skipNotification === true) to workflow end (no notification)
- Route FALSE branch to Telegram Risk for notification
- Fixes unwanted FARTCOIN-PERP notifications while preserving SOL-PERP notifications
- API at /api/trading/check-risk returns skipNotification: true for disabled symbols
Key clarifications in ORDERBOOK_SHADOW_LOGGING.md:
1. Trade execution only (NOT periodic):
- Orderbook captured in /api/trading/execute (lines 1037-1053)
- NOT captured in /api/trading/market-data (1-minute feed)
- Frequency: 3-5 orderbook snapshots per day (when trades execute)
- vs. 1,440 market data updates per day (price/ATR/ADX/RSI)
2. Phase 1.5 declined (Dec 19, 2025):
- User asked about 1-minute periodic orderbook capture
- Agent explained tradeoffs: 1,440 API calls/day, more storage
- User confirmed trade-time capture sufficient for now
- Periodic monitoring not needed for Phase 1 validation
3. Scope clarity for resumption:
- Phase 1 complete and deployed
- Goal: Collect 50-100 trades with orderbook data
- Phase 2: Real orderbook API integration (Hyperliquid/Jupiter)
- Next agent: Monitor trade data collection, analyze patterns
Status: ✅ All Phase 1 tasks complete, awaiting first trade validation
User clarification: 'i thought it is the v11 v2'
- Updated to show v11.2 IMPROVED as active version
- Documented both available indicators (v11.2 improved and v11 all filters)
- Added parameters for both versions for comparison
- Note: Database shows 'v11' but user has v11.2 loaded in TradingView
MANDATORY section for all AI agents to check first:
- Current TradingView indicator: v11 All Filters (filters NOW working)
- Signal quality scoring: v9 with direction-specific thresholds
- Position management: TP2-as-runner with ATR-based dynamic targets
- Adaptive leverage: 10x/5x with LONG 95+, SHORT 90+ thresholds
- Verification commands to check what's actually deployed
This prevents confusion when multiple implementations exist.
User mandate: 'i want this to be a mandatory thing to document'
- Added Bug #87 (Position Manager state lost on restart) to TOP 10 Critical Pitfalls
- Comprehensive documentation with incident details, root cause, fix implementation
- Created state-persistence.test.ts to validate all 18 critical state fields
- Test suite validates tp2Hit, trailingStopActive, peakPrice (critical for runner recovery)
- Testing notes: TypeScript ✅, npm test ⏱ timeout (120s), Docker deployment ✅
- Real-world validation pending: Next trade with container restart
Bug #87 Impact:
- Financial: ~$18.56 runner profit lost
- Root Cause: Race condition in nested Prisma query
- Fix: 4-step bulletproof atomic persistence with verification
- Status: ✅ DEPLOYED Dec 17, 2025 15:14 UTC (commit 341341d)
PROBLEM: Container restart caused Position Manager to lose tracking of runner
system state, resulting in on-chain TP1 order closing entire position (100%)
instead of partial close (60%).
ROOT CAUSE: updateTradeState() had race condition in configSnapshot merge logic
- nested Prisma query inside update caused non-atomic read-modify-write
- positionManagerState was NULL in database despite saveTradeState() calls
- Missing critical state fields: tp2Hit, trailingStopActive, peakPrice
THE FIX (3-Layer Protection):
1. Atomic state persistence with verification
- Separate read → merge → write → verify steps
- Bulletproof verification after save (catches silent failures)
- Persistent logger for save failures (investigation trail)
2. Complete state tracking
- Added tp2Hit (runner system activation)
- Added trailingStopActive (trailing stop recovery)
- Added peakPrice (trailing stop calculations)
- All MAE/MFE fields preserved
3. Bulletproof recovery on restart
- initialize() restores ALL state from configSnapshot
- Runner system can continue after TP1 partial close
- Trailing stop resumes with correct peak price
- No on-chain order conflicts
FILES CHANGED:
- lib/database/trades.ts (lines 66-90, 282-362)
* UpdateTradeStateParams: Added tp2Hit, trailingStopActive, peakPrice
* updateTradeState(): 4-step atomic save with verification
* Persistent logging for save failures
- lib/trading/position-manager.ts (lines 2233-2258)
* saveTradeState(): Now saves ALL critical runner system state
* Includes tp2Hit, trailingStopActive, peakPrice
* Complete MAE/MFE tracking
EXPECTED BEHAVIOR AFTER FIX:
- Container restart: PM restores full state from database
- TP1 partial close: 60% closed, 40% runner continues
- TP2 activation: Runner exits with trailing stop
- No on-chain order conflicts (PM controls partial closes)
USER IMPACT:
- No more missed runner profits due to restarts
- Complete position tracking through container lifecycle
- Bulletproof verification catches save failures early
INCIDENT REFERENCE:
- Trade ID: cmja0z6r00006t907qh24jfyk
- Date: Dec 17, 2025
- Loss: ~$18.56 potential runner profit missed
- User quote: "we have missed out here despite being a winner"
See Bug #87 in Common Pitfalls for full incident details
- Documents critical incident where --force-recreate didn't deploy code
- Telegram showed 0.15% instead of 0.3% despite commits and rebuild
- Root cause: Docker cached build layers, only container recreated
- Solution: docker compose build --no-cache trading-bot required
- Adds when to use --no-cache vs --force-recreate guidelines
- Includes verification steps and prevention rules
- 2 hours debugging time, now documented for future reference
CHANGES:
- Extended sendValidationNotification interface with confirmationThreshold, maxDrawdown, entryWindowMinutes
- Updated telegram.ts to display actual queued signal thresholds instead of hardcoded values
- Modified smart-validation-queue.ts to pass dynamic threshold values to Telegram
- Messages now show exact thresholds used for each signal (not fixed 0.3%/1.0%/90min)
PURPOSE:
- User requested adaptive display instead of hardcoded values
- Enables future per-signal threshold customization
- Each signal can have different thresholds based on characteristics
EXAMPLE:
Before: 'Will enter if +0.3% confirms' (all signals)
After: 'Will enter if +0.25% confirms' (high ADX signal)
'Will enter if +0.4% confirms' (low ADX signal)
STATUS: Ready for deployment - will show actual threshold per signal
- Fixed import in health monitor to include getPrismaClient
- Required for Bug #89 FRACTIONAL_REMNANT database queries
- Resolved Build 2 module resolution error (../database/client)
- Corrected import path to ../database/trades
Also includes v11.2 PineScript emergency parameter fix
- Part 1: Position Manager fractional remnant detection after close attempts
* Check if position < 1.5× minOrderSize after close transaction
* Log to persistent logger with FRACTIONAL_REMNANT_DETECTED
* Track closeAttempts, limit to 3 maximum
* Mark exitReason='FRACTIONAL_REMNANT' in database
* Remove from monitoring after 3 failed attempts
- Part 2: Pre-close validation in closePosition()
* Check if position viable before attempting close
* Reject positions < 1.5× minOrderSize with specific error
* Prevent wasted transaction attempts on too-small positions
* Return POSITION_TOO_SMALL_TO_CLOSE error with manual instructions
- Part 3: Health monitor detection for fractional remnants
* Query Trade table for FRACTIONAL_REMNANT exits in last 24h
* Alert operators with position details and manual cleanup instructions
* Provide trade IDs, symbols, and Drift UI link
- Database schema: Added closeAttempts Int? field to Track attempts
Root cause: Drift protocol exchange constraints can leave fractional positions
Evidence: 3 close transactions confirmed but 0.15 SOL remnant persisted
Financial impact: ,000+ risk from unprotected fractional positions
Status: Fix implemented, awaiting deployment verification
See: docs/COMMON_PITFALLS.md Bug #89 for complete incident details