Multi-Timeframe Analysis

TradeStaq supports multi-timeframe (MTF) analysis, allowing your strategies to access indicators and price data from multiple timeframes simultaneously.

Overview

Multi-timeframe analysis enables:

  • Higher timeframe confirmation - Confirm entries with longer-term trends
  • Multiple perspectives - See market structure across timeframes
  • Better entries - Time entries on lower timeframes
  • Reduced noise - Filter signals with higher timeframe context

Enabling Multi-Timeframe

Bot Configuration

When creating or editing a bot, enable MTF in settings:

{
    "mtfConfig": {
        "enabled": true,
        "timeframes": ["4h", "1d"],
        "includeIndicators": true
    }
}

Configuration Options

OptionTypeDescription
enabledbooleanEnable MTF data loading
timeframesstring[]Additional timeframes to load
includeIndicatorsbooleanPre-calculate indicators for each timeframe
candleLimitnumberNumber of candles per timeframe (default: 200)

Available Timeframes

  • 1m, 5m, 15m, 30m - Intraday
  • 1h, 4h - Short-term
  • 1d, 1w - Long-term

The td.mtf Object

Access multi-timeframe data through td.mtf:

td.mtf = {
    // Get indicators for a specific timeframe
    indicators(timeframe: string): IndicatorValues | null;

    // Get OHLCV candles for a specific timeframe
    candles(timeframe: string): OHLCV[];

    // Get ticker data (last candle OHLC)
    ticker(timeframe: string): { high, low, open, close } | null;

    // List available timeframes
    available(): string[];

    // Check if timeframe is loaded
    has(timeframe: string): boolean;

    // The primary (bot configured) timeframe
    primary: string;

    // Raw MTF data for advanced access
    data: Record<string, MTFData>;
}

Accessing MTF Indicators

Basic Usage

// Your primary timeframe indicators (e.g., 1h)
const rsi1h = td.indicators.rsi;
const macd1h = td.indicators.macd;

// 4-hour timeframe indicators
const rsi4h = td.mtf.indicators('4h')?.rsi;
const macd4h = td.mtf.indicators('4h')?.macd;

// Daily timeframe indicators
const rsiDaily = td.mtf.indicators('1d')?.rsi;
const adxDaily = td.mtf.indicators('1d')?.adx;

Safe Access Pattern

// Always check if timeframe is available
if (td.mtf.has('4h')) {
    const htfIndicators = td.mtf.indicators('4h');
    if (htfIndicators) {
        const rsi4h = htfIndicators.rsi;
        const trend4h = htfIndicators.macd.trend;
        // Use indicators...
    }
}

All Available Indicators per Timeframe

Each timeframe has the full indicator set:

const htf = td.mtf.indicators('4h');

// All these are available:
htf.rsi                    // RSI value
htf.rsiArray               // RSI history
htf.macd                   // { line, signal, histogram, trend }
htf.atr                    // ATR value
htf.atrArray               // ATR history
htf.bbands                 // { upper, middle, lower, width, percentB }
htf.adx                    // { value, diPlus, diMinus, trend }
htf.stochastic             // { k, d, zone }
htf.pivots                 // { pivot, r1, r2, r3, s1, s2, s3 }
htf.mfi                    // Money Flow Index

// Custom indicators - use helper function for safe access
function getHtfIndicator(htf, key) {
    const val = htf?.custom?.[key];
    if (val === undefined || val === null) return 0;
    if (Array.isArray(val)) return val[val.length - 1];
    return val;
}
getHtfIndicator(htf, 'ema_20')   // EMA with period 20
getHtfIndicator(htf, 'sma_50')   // SMA with period 50

Accessing MTF Candles

// Get candles for higher timeframe
const candles4h = td.mtf.candles('4h');
const candlesDaily = td.mtf.candles('1d');

// Latest candle
const last4hCandle = candles4h[candles4h.length - 1];
const lastDailyCandle = candlesDaily[candlesDaily.length - 1];

// Use ticker for quick access to last candle OHLC
const ticker4h = td.mtf.ticker('4h');
if (ticker4h) {
    const { high, low, open, close } = ticker4h;
}

MTF Strategy Patterns

Pattern 1: Higher Timeframe Trend Filter

Only trade in direction of higher timeframe trend.

// Check 4h trend
const htfIndicators = td.mtf.indicators('4h');
const htfTrend = htfIndicators?.macd.trend;
const htfAdx = htfIndicators?.adx;

// Only long if 4h is bullish with strong trend
const bullishHTF = htfTrend === 'bullish' && htfAdx?.trend === 'strong';
const bearishHTF = htfTrend === 'bearish' && htfAdx?.trend === 'strong';

// Primary timeframe entry signal
const rsi = td.indicators.rsi;
const oversold = rsi < 30;
const overbought = rsi > 70;

// Trade with HTF confirmation
if (!td.position.hasPosition) {
    if (oversold && bullishHTF) {
        td.trade.buy({
            amountPercent: 50,
            reason: 'RSI oversold + 4h bullish trend'
        });
    }

    if (overbought && bearishHTF) {
        td.trade.sell({
            amountPercent: 50,
            reason: 'RSI overbought + 4h bearish trend'
        });
    }
}

Pattern 2: Multi-Timeframe RSI Confluence

Enter when RSI is oversold on multiple timeframes.

const rsi1h = td.indicators.rsi;
const rsi4h = td.mtf.indicators('4h')?.rsi || 50;
const rsiDaily = td.mtf.indicators('1d')?.rsi || 50;

// Count oversold timeframes
let oversoldCount = 0;
if (rsi1h < 30) oversoldCount++;
if (rsi4h < 35) oversoldCount++;
if (rsiDaily < 40) oversoldCount++;

// Strong buy signal when multiple timeframes oversold
if (!td.position.hasPosition && oversoldCount >= 2) {
    td.trade.buy({
        amountPercent: 50,
        stopLoss: td.market.price * 0.97,
        reason: `${oversoldCount} timeframes oversold`
    });
}

// Log confluence
td.utils.log('RSI Confluence', {
    rsi1h,
    rsi4h,
    rsiDaily,
    oversoldCount
});

Pattern 3: Timeframe Alignment Entry

Entry when trend aligns across all timeframes.

// Get trends from multiple timeframes
const trend1h = td.indicators.macd.trend;
const trend4h = td.mtf.indicators('4h')?.macd.trend;
const trendDaily = td.mtf.indicators('1d')?.macd.trend;

// Check alignment
const allBullish = trend1h === 'bullish' &&
                   trend4h === 'bullish' &&
                   trendDaily === 'bullish';

const allBearish = trend1h === 'bearish' &&
                   trend4h === 'bearish' &&
                   trendDaily === 'bearish';

// Only trade when fully aligned
if (!td.position.hasPosition) {
    if (allBullish && td.indicators.rsi < 50) {
        td.trade.buy({
            amountPercent: 75,  // Higher confidence = bigger size
            reason: 'All timeframes bullish aligned'
        });
    }

    if (allBearish && td.indicators.rsi > 50) {
        td.trade.sell({
            amountPercent: 75,
            reason: 'All timeframes bearish aligned'
        });
    }
}

Pattern 4: Daily Support/Resistance

Use daily pivot points for entry/exit levels.

// Get daily pivots
const dailyPivots = td.mtf.indicators('1d')?.pivots;
const currentPrice = td.market.price;

if (dailyPivots && !td.position.hasPosition) {
    const { pivot, s1, s2, r1, r2 } = dailyPivots;

    // Long near support
    if (currentPrice <= s1 * 1.005 && td.indicators.rsi < 35) {
        td.trade.buy({
            amountPercent: 50,
            stopLoss: s2 * 0.995,
            takeProfit: pivot,
            reason: `Long at daily S1 (${s1.toFixed(2)})`
        });
    }

    // Short near resistance
    if (currentPrice >= r1 * 0.995 && td.indicators.rsi > 65) {
        td.trade.sell({
            amountPercent: 50,
            stopLoss: r2 * 1.005,
            takeProfit: pivot,
            reason: `Short at daily R1 (${r1.toFixed(2)})`
        });
    }
}

Pattern 5: ATR-Based Position Sizing with HTF

Use higher timeframe ATR for volatility-adjusted sizing.

// Use 4h ATR for more stable volatility reading
const atr4h = td.mtf.indicators('4h')?.atr || td.indicators.atr;
const entryPrice = td.market.price;

// Calculate stop based on 4h ATR
const stopDistance = atr4h * 1.5;
const stopLoss = entryPrice - stopDistance;
const takeProfit = entryPrice + (stopDistance * 2);

// Risk-based entry
if (!td.position.hasPosition && td.indicators.rsi < 30) {
    td.trade.buyRisk({
        riskPercent: 2,
        stopLoss,
        takeProfit,
        reason: 'Risk entry with 4h ATR stops'
    });
}

Complete MTF Strategy

// ═══════════════════════════════════════════════════════════════
// Multi-Timeframe Trend Following Strategy
// Primary: 1h | Confirmation: 4h | Bias: Daily
// ═══════════════════════════════════════════════════════════════

// ─── Configuration ───────────────────────────────────────────────
const RSI_OVERSOLD = td.config.getNumber('RSI_OVERSOLD', 30);
const RSI_OVERBOUGHT = td.config.getNumber('RSI_OVERBOUGHT', 70);
const RISK_PERCENT = td.config.getNumber('RISK_PERCENT', 2);

// ─── Helper for custom indicators ────────────────────────────────
function getIndicator(key) {
    const val = td.indicators.custom[key];
    if (val === undefined || val === null) return 0;
    if (Array.isArray(val)) return val[val.length - 1];
    return val;
}

// ─── Get Multi-Timeframe Data ────────────────────────────────────
const primary = {
    rsi: td.indicators.rsi,
    macd: td.indicators.macd,
    atr: td.indicators.atr,
    ema9: getIndicator('ema_9'),
    ema21: getIndicator('ema_21'),
    openGraph: { title: 'Multi-Timeframe Analysis', description: 'How to use multiple timeframes in custom strategies.' },
};

const htf4h = td.mtf.indicators('4h');
const htfDaily = td.mtf.indicators('1d');

// Ensure MTF data is available
if (!htf4h || !htfDaily) {
    td.utils.log('MTF data not available, skipping');
    return;
}

// ─── Define Trend Bias ───────────────────────────────────────────
const dailyTrend = htfDaily.macd.trend;
const htfTrend = htf4h.macd.trend;
const htfTrendStrong = htf4h.adx.trend === 'strong';

const bullishBias = dailyTrend === 'bullish' || htfTrend === 'bullish';
const bearishBias = dailyTrend === 'bearish' || htfTrend === 'bearish';

// ─── Entry Logic ─────────────────────────────────────────────────
if (!td.position.hasPosition) {
    // EMA crossover on primary timeframe
    const ema9 = getIndicator('ema_9');
    const ema21 = getIndicator('ema_21');
    const prevEma9 = td.state.get('prevEma9', ema9);
    const prevEma21 = td.state.get('prevEma21', ema21);

    const emaCrossUp = prevEma9 <= prevEma21 && ema9 > ema21;
    const emaCrossDown = prevEma9 >= prevEma21 && ema9 < ema21;

    // Store for next spin
    td.state.set('prevEma9', ema9);
    td.state.set('prevEma21', ema21);

    // Long entry
    if (emaCrossUp && bullishBias && primary.rsi < 60) {
        const atrStop = primary.atr * 1.5;

        td.trade.buyRisk({
            riskPercent: RISK_PERCENT,
            stopLoss: td.market.price - atrStop,
            takeProfit: td.market.price + (atrStop * 2),
            reason: `Long: EMA cross + ${dailyTrend} daily + ${htfTrend} 4h`
        });

        td.utils.log('Long Entry', {
            rsi: primary.rsi,
            dailyTrend,
            htfTrend,
            htfTrendStrong
        });
    }

    // Short entry
    if (emaCrossDown && bearishBias && primary.rsi > 40) {
        const atrStop = primary.atr * 1.5;

        td.trade.sellRisk({
            riskPercent: RISK_PERCENT,
            stopLoss: td.market.price + atrStop,
            takeProfit: td.market.price - (atrStop * 2),
            reason: `Short: EMA cross + ${dailyTrend} daily + ${htfTrend} 4h`
        });
    }
}

// ─── Position Management ─────────────────────────────────────────
if (td.position.hasPosition) {
    const profit = td.position.pnlPercent;
    const side = td.position.side;

    // Exit if higher timeframe trend reverses
    const trendReversed =
        (side === 'long' && htfTrend === 'bearish' && htfTrendStrong) ||
        (side === 'short' && htfTrend === 'bullish' && htfTrendStrong);

    if (trendReversed && profit > 0) {
        td.trade.close('HTF trend reversed');
    }

    // Move to breakeven at 2% profit
    if (profit >= 2 && !td.state.get('breakeven')) {
        td.trade.breakeven({ breakevenOffset: 0.1 });
        td.state.set('breakeven', true);
    }

    // Scale out at profit targets
    if (profit >= 3 && !td.state.get('scaled1')) {
        td.trade.close('Scale out 33% at 3%');
        td.state.set('scaled1', true);
    }
}

// ─── Logging ─────────────────────────────────────────────────────
td.utils.log('MTF Analysis', {
    primary: {
        rsi: primary.rsi.toFixed(2),
        macdTrend: primary.macd.trend,
    },
    htf4h: {
        rsi: htf4h.rsi.toFixed(2),
        macdTrend: htf4h.macd.trend,
        adxTrend: htf4h.adx.trend,
    },
    daily: {
        rsi: htfDaily.rsi.toFixed(2),
        macdTrend: htfDaily.macd.trend,
    },
    bias: bullishBias ? 'BULLISH' : bearishBias ? 'BEARISH' : 'NEUTRAL'
});

Best Practices

1. Don't Over-Complicate

// Good: 2-3 timeframes
const timeframes = ['4h', '1d'];

// Avoid: Too many timeframes causes confusion
const timeframes = ['5m', '15m', '30m', '1h', '4h', '1d', '1w'];

2. Use HTF for Direction, LTF for Timing

// Daily/4h for trend direction
const trendDirection = htfDaily.macd.trend;

// 1h/15m for entry timing
const entrySignal = td.indicators.rsi < 30;

// Combine both
if (trendDirection === 'bullish' && entrySignal) {
    td.trade.buy();
}

3. Confirm with Multiple Indicators

// Don't rely on single HTF indicator
const htfBullish =
    htf4h.macd.trend === 'bullish' &&
    htf4h.rsi > 50 &&
    htf4h.adx.value > 25;

4. Handle Missing Data

// Always check for null
const htfRsi = td.mtf.indicators('4h')?.rsi;
if (htfRsi === undefined || htfRsi === null) {
    td.utils.log('HTF data missing, using default');
    return; // or use fallback
}

Troubleshooting

MTF Data Not Available

Cause: MTF not enabled in bot config or timeframes not specified.

Solution: Check bot settings:

{
    "mtfConfig": {
        "enabled": true,
        "timeframes": ["4h", "1d"],
        "includeIndicators": true
    }
}

Indicators Returning null

Cause: Insufficient candle data for indicator calculation.

Solution: Use safe access with fallbacks:

const htfRsi = td.mtf.indicators('4h')?.rsi ?? 50;

Performance Issues

Cause: Too many timeframes or indicators.

Solution: Limit to 2-3 additional timeframes and use includeIndicators: false if you only need candle data.


S/R Zone Analysis (td.zones)

In addition to MTF indicators, TradeStaq offers automatic multi-timeframe support and resistance zone analysis. When enabled in the Multi-Timeframe Setup step, the platform:

  1. Dynamically selects 3 candle timeframes (short, medium, long) from your exchange
  2. Generates up to 20 time intervals spanning from intraday to yearly windows
  3. Computes classic pivot points (P, S1-S3, R1-R3) for each interval
  4. Checks if the current price is near any S/R level

Enabling Zones

Enable S/R Zone Analysis in the strategy wizard's Multi-Timeframe Setup step (same step as MTF configuration). Configure:

  • Proximity Type: atr (volatility-based), percentage (fixed %), or both
  • ATR Multiplier: How close price must be to count as "near" (uses primary TF ATR)
  • % Threshold: Fixed percentage proximity threshold

Quick Example

const zones = td.zones;
if (!zones) return; // Not enabled

const supportDepth = zones.withinSupportCount;   // 0 to zones.totalIntervals
const resistanceDepth = zones.withinResistanceCount;

// Buy near strong multi-timeframe support confluence
if (!td.position.hasPosition && supportDepth >= 5 && td.indicators.rsi < 40) {
    td.trade.buy({
        amountPercent: 5,
        stopLoss: zones.strongestSupport * 0.99,
        takeProfit: zones.strongestResistance,
        reason: `Support confluence: ${supportDepth}/${zones.totalIntervals}`
    });
}

For full details on td.zones properties, see the TD API Reference.


Next Steps