TDR Strategy (Trend Direction & Risk)
A sophisticated strategy combining trend detection with risk-based position management.
Overview
TDR generates multiple signal types for nuanced position management:
| Signal | Type | Trigger |
|---|---|---|
| buySignal | Full Entry | EMA crosses above Donchian baseline |
| sellSignal | Full Exit | EMA crosses below Donchian baseline |
| preEntry | Partial Entry | Price crosses short baseline (early positioning) |
| takeProfit | Partial Exit | Price crosses below short baseline in profit |
| lowRiskEntry | Partial Entry | Extended time in low-risk PPO zone |
| highRiskTP | Partial Exit | Extended time in high-risk PPO zone |
Key Concepts
Donchian Channel Baseline
The Donchian channel provides a dynamic baseline (midpoint of highest high and lowest low):
ctx.indicator('baseline', 'DONCHIAN', { period: 50 }); // Access the middle line (baseline) const baseline = ctx.ind.baseline_middle; // EMA crossing above/below baseline defines trend if (q.crossOver(ema, baseline, i)) { // Bullish trend confirmed }
PPO Risk Zones
The PPO (Percent Price Oscillator) measures momentum on a -100 to +100 scale:
ctx.indicator('ppo', 'PPO', { shortGamma: 0.4, // Fast Laguerre filter longGamma: 0.8, // Slow Laguerre filter accuracy: 10 // Calculation precision }); // Define risk zones const ppoValue = ctx.ind.ppo[i]; if (ppoValue < -85) { // Low risk zone: good for entries } else if (ppoValue > 85) { // High risk zone: consider taking profits }
Zone Duration Signals
LowRiskEntry and HighRiskTP fire when the market stays in a risk zone for an extended period (average zone length):
function checkLowRiskEntry(riskState) { // Fire when current zone length equals average if (riskState.inLowRisk && riskState.avgLowRiskLength > 0) { return riskState.lowRiskLength === Math.round(riskState.avgLowRiskLength); } return false; }
Trading Modes
TDR supports all three trading modes: Long-only, Short-only, and Bidirectional. The mode is accessed via ctx.p.tradingMode and the strategy branches its order logic accordingly. This is what allows TDR to be used in any direction from the UI.
For a complete guide on implementing trading modes in your own strategies, including code examples for each mode, partial positions, and common mistakes, see the Trading Modes guide under Best Practices.
Signal Delay Pattern
TDR uses 1-bar delayed execution for realistic backtesting:
// Store raw signal for next bar ctx.state.delayed.prevBuy = rawBuySignal; // Execute delayed signal from previous bar const buySignal = ctx.state.delayed.prevBuy; if (buySignal) { ctx.order.market('ASSET', 1, { signal: 'buy' }); }
Partial Position Sizing
Use partial entries and exits for sophisticated position management:
// Partial entry (5% of portfolio) if (preEntry && ctx.state.tradeState === 'flat') { ctx.order.market('ASSET', 0.05, { signal: 'preEntry' }); } // Partial exit (reduce position by 5%) if (highRiskTP && ctx.state.tradeState === 'long') { ctx.order.reduce('ASSET', 0.05, { signal: 'highRiskTP' }); }
Performance Notes
- Best on 4h and daily timeframes
- Strong in trending markets with pullbacks
- PPO zones help avoid chasing extended moves
- Partial signals allow gradual position building/reduction
Related
- Donchian Indicator - Channel calculation details
- PPO Indicator - Risk oscillator details
- Multi-Indicator Strategy - Simpler multi-indicator example