Testing & Validation

Learn how to test and validate your custom strategies before deployment.

Overview

Testing is crucial to ensure your strategy works correctly and doesn't have bugs that could cause unexpected trades or losses. TradeStaq provides multiple ways to test your strategies.

Code Validation

Before a strategy can run, it goes through validation:

Syntax Checking

The platform checks for JavaScript syntax errors:

// This will fail validation
if (rsi < 30 {  // Missing closing parenthesis
    td.trade.buy();
}

// Correct syntax
if (rsi < 30) {
    td.trade.buy();
}

Forbidden Patterns

Certain patterns are blocked for security:

// FORBIDDEN - will fail validation
eval('code');              // No dynamic code execution
new Function('code');      // No function constructor
fetch('https://...');      // No network access
require('fs');             // No Node.js modules
process.exit();            // No process control

Resource Limits

Strategies must operate within platform resource limits for code size, execution time, and memory usage. These limits ensure fair resource sharing across all users.

Data Validation

Before each strategy spin, the platform validates that critical market data is available and valid. If validation fails, the spin is skipped and an error is logged.

Critical Data (Spin will fail if invalid)

DataValidation
td.market.priceMust be > 0, not NaN
td.market.symbolMust be non-empty
td.market.timeframeMust be non-empty
td.market.exchangeMust be non-empty
td.market.bid / askMust be > 0
td.market.candlesMust not be empty
td.account.balanceMust be > 0
td.indicators.rsiMust be 0-100
td.indicators.atrMust be >= 0

Warnings (Spin continues with warning)

DataWarning Condition
td.market.candlesLess than 15 candles (indicators may be unreliable)
td.market.bid/askBid >= ask (unusual spread)
OHLC valuesHigh < low (invalid candle)
Bollinger BandsUpper < lower

Handling Sparse Data

For newly listed coins with limited history:

// Check if we have enough data for your strategy
if (td.market.candles.length < 50) {
    td.utils.log('Limited candle history, using simplified logic');
    // Use simpler entry logic or skip
    return;
}

Bots in on_bar_close execution mode need at least one fully-closed candle before they can run at all. During the warm-up window (fresh bot, feed gap, cache rebuild) the spin returns no_signal with a clear skip reason rather than silently falling back to continuous behavior. Nothing for you to handle in the strategy — it just means the first signal arrives one closed bar later than deploy time.

Consecutive Failures

If a bot encounters 5 consecutive validation failures, it will be automatically paused. Check your bot's activity log for error details.

Test Endpoint

Test your strategy without deploying it:

POST /api/tradedroid/strategies/{id}?action=test
Content-Type: application/json

{
    "symbol": "BTC/USDT",
    "timeframe": "1h",
    "basePrice": 50000,
    "config": {
        "RSI_OVERSOLD": 25,
        "STOP_LOSS_PCT": 3
    }
}

Test Response

{
    "status": "success",
    "signals": [
        {
            "type": "buy",
            "amount": 100,
            "amountPercent": true,
            "stopLoss": 48500,
            "takeProfit": 52000,
            "reason": "RSI oversold at 23.45"
        }
    ],
    "logs": [
        {
            "message": "Strategy tick",
            "data": { "rsi": 23.45, "price": 50000 },
            "timestamp": 1699999999999
        }
    ],
    "state": {
        "previousRsi": 23.45
    },
    "executionTimeMs": 45,
    "memoryUsedMb": 12.5
}

Validation Errors

Common Errors

ErrorCauseSolution
Syntax errorJavaScript syntax issueCheck for missing brackets, semicolons
Timeout exceededExecution took too longOptimize loops, reduce complexity
Memory exceededUsed too much memoryReduce data storage, optimize arrays
Infinite loopwhile(true) or similarAdd loop exit conditions
Code too largeStrategy file is too bigReduce comments, consolidate code
Forbidden patternSecurity violationRemove eval, fetch, require, etc.

Debugging Syntax Errors

// Error: Unexpected token
const rsi = td.indicators.rsi
if (rsi < 30) {  // Missing semicolon above
    td.trade.buy();
}

// Fixed
const rsi = td.indicators.rsi;
if (rsi < 30) {
    td.trade.buy();
}

Debugging Infinite Loops

// BAD - infinite loop
while (true) {
    // Process forever
}

// GOOD - loop with exit condition
let iterations = 0;
while (condition && iterations < 1000) {
    // Process
    iterations++;
}

Paper Trading Testing

The safest way to test strategies with real market data:

Setup

  1. Create a paper trading exchange
  2. Create a bot using your strategy
  3. Link bot to paper exchange
  4. Let it run for observation period

What to Monitor

  • Signal frequency: Is it trading too often or too rarely?
  • Entry timing: Are entries at expected indicator levels?
  • Exit behavior: Are positions closing as expected?
  • Error messages: Check logs for any issues

Recommended Testing Period

Strategy TypeMinimum Test Period
Scalping (1m-5m)3-7 days
Day trading (15m-1h)1-2 weeks
Swing trading (4h-1d)2-4 weeks
Position trading (1w)1-2 months

Backtesting

Test against historical data:

Running a Backtest

  1. Navigate to Dashboard → Backtests
  2. Click New Backtest
  3. Configure:
    • Strategy selection
    • Trading pair
    • Timeframe
    • Date range
    • Initial balance
    • Position sizing
  4. Run backtest

Interpreting Results

Key metrics to evaluate:

MetricGood ValueDescription
Win Rate> 40%Percentage of winning trades
Profit Factor> 1.5Gross profit / gross loss
Max Drawdown< 20%Largest peak-to-trough decline
Sharpe Ratio> 1.0Risk-adjusted returns
Total Trades30+Statistical significance

Backtest Limitations

  • No slippage simulation: Real execution may differ
  • Idealized fills: Assumes orders always fill at expected price
  • Past ≠ future: Historical performance doesn't guarantee results
  • Curve fitting risk: Over-optimized parameters may not generalize

Unit Testing Patterns

Test individual components of your strategy:

// Test helper function
function testCalculation() {
    const testCases = [
        { input: 100, expected: 98 },
        { input: 200, expected: 196 },
    ];

    for (const test of testCases) {
        const result = calculateStopLoss(test.input, 2);
        if (result !== test.expected) {
            td.utils.log('TEST FAILED', {
                input: test.input,
                expected: test.expected,
                got: result
            });
        }
    }
}

// Run tests on first spin
if (td.meta.spinCount === 1) {
    testCalculation();
}

Logging for Debugging

Use comprehensive logging during testing:

// Verbose logging for testing
const DEBUG = td.config.getBoolean('DEBUG_MODE', true);

if (DEBUG) {
    td.utils.log('Strategy state', {
        spinCount: td.meta.spinCount,
        price: td.market.price,
        rsi: td.indicators.rsi,
        macd: td.indicators.macd,
        hasPosition: td.position.hasPosition,
        pnl: td.position.pnl,
        state: td.state.getAll()
    });
}

// Entry decision logging
if (entryCondition) {
    td.utils.log('ENTRY SIGNAL', {
        reason: 'RSI oversold',
        rsi: td.indicators.rsi,
        price: td.market.price,
        stopLoss: calculatedSL,
        takeProfit: calculatedTP
    });
}

Pre-deployment Checklist

Before going live:

  • Code passes validation without errors
  • Strategy tested on paper exchange for minimum period
  • Backtest shows acceptable performance metrics
  • All parameters have sensible defaults
  • Edge cases handled (missing data, extreme values)
  • Stop losses are always set
  • Position checks prevent duplicate entries
  • Logging is appropriate (not excessive in production)
  • Risk per trade is within acceptable limits

Going Live Safely

Start Small

// Use smaller position sizes initially
const isNewStrategy = td.state.get('totalTrades', 0) < 10;
const positionSize = isNewStrategy ? 25 : 100; // 25% until proven

td.trade.buy({ amountPercent: positionSize });

Monitor Closely

First week of live trading:

  • Check bot status multiple times daily
  • Review each trade in logs
  • Compare to expected behavior
  • Be ready to pause if issues arise

Gradual Scaling

  1. Week 1-2: 25% position size
  2. Week 3-4: 50% position size
  3. Month 2+: Full position size (if performing well)

Next Steps