Getting Started with Custom Strategies

This guide walks you through creating your first custom trading strategy on TradeStaq.

Prerequisites

Before creating custom strategies, ensure you have:

  • Basic JavaScript knowledge
  • Understanding of trading concepts (entries, exits, stop loss, etc.)
  • Any TradeStaq plan (custom strategies are available on all tiers)
  • At least one connected exchange (paper trading recommended for testing)

Your First Strategy: Hello World

Let's start with a simple strategy that logs market information:

// Hello World Strategy
// Logs current market state on each spin

td.utils.log('Hello from my strategy!', {
    symbol: td.market.symbol,
    price: td.market.price,
    rsi: td.indicators.rsi,
    hasPosition: td.position.hasPosition,
    spinCount: td.meta.spinCount
});

This strategy doesn't execute any trades - it simply logs information to help you understand the available data.

A Simple Trading Strategy

Now let's create a strategy that actually trades based on RSI:

// RSI Mean Reversion Strategy
// Buys when oversold, sells when overbought

const rsi = td.indicators.rsi;
const oversoldLevel = 30;
const overboughtLevel = 70;

if (!td.position.hasPosition) {
    // No position - look for entry
    if (rsi < oversoldLevel) {
        td.trade.buy({
            amountPercent: 100,
            stopLoss: td.market.price * 0.98,  // 2% stop loss
            takeProfit: td.market.price * 1.04, // 4% take profit
            reason: `RSI oversold at ${rsi.toFixed(2)}`
        });
    }
} else {
    // In position - look for exit
    if (rsi > overboughtLevel) {
        td.trade.close(`RSI overbought at ${rsi.toFixed(2)}`);
    }
}

Understanding the Code

Accessing Indicators

const rsi = td.indicators.rsi;  // Current RSI value (14-period default)

The td.indicators object provides pre-calculated technical indicators. See the Indicators Guide for all available indicators.

Checking Position Status

if (!td.position.hasPosition) {
    // No open position
}

The td.position object tells you about your current position:

  • hasPosition: Boolean - whether you have an open position
  • side: 'long', 'short', or 'none'
  • pnl: Current unrealized profit/loss

Executing Trades

td.trade.buy({
    amountPercent: 100,        // Use 100% of available balance
    stopLoss: price * 0.98,    // Stop loss price
    takeProfit: price * 1.04,  // Take profit price
    reason: 'Entry reason'     // Logged for debugging
});

Available trade functions:

  • td.trade.buy() - Open a long position
  • td.trade.sell() - Open a short position
  • td.trade.close() - Close current position

Logging

td.utils.log('Message', { data: 'here' });

Logs are visible in the bot's activity panel. Use logging to debug your strategy.

Making Strategies Configurable

Hard-coding values like 30 for oversold is inflexible. Use td.config to make strategies configurable:

// Configurable RSI Strategy
const rsiPeriod = td.config.getNumber('RSI_PERIOD', 14);
const oversold = td.config.getNumber('RSI_OVERSOLD', 30);
const overbought = td.config.getNumber('RSI_OVERBOUGHT', 70);
const stopLossPercent = td.config.getNumber('STOP_LOSS_PCT', 2);
const takeProfitPercent = td.config.getNumber('TAKE_PROFIT_PCT', 4);

// Note: Standard RSI (14) is built-in. Custom periods require custom indicator configured in bot settings.
const rsi = rsiPeriod === 14 ? td.indicators.rsi : td.indicators.custom['rsi_' + rsiPeriod];
const price = td.market.price;

if (!td.position.hasPosition && rsi < oversold) {
    td.trade.buy({
        amountPercent: 100,
        stopLoss: price * (1 - stopLossPercent / 100),
        takeProfit: price * (1 + takeProfitPercent / 100),
        reason: `RSI ${rsi.toFixed(2)} < ${oversold}`
    });
} else if (td.position.hasPosition && rsi > overbought) {
    td.trade.close(`RSI ${rsi.toFixed(2)} > ${overbought}`);
}

Users can then customize these parameters when creating a bot with your strategy.

Using State for Complex Logic

Sometimes you need to remember values between spins. Use td.state:

// Track consecutive losses
const consecutiveLosses = td.state.get('consecutiveLosses', 0);
const lastPnl = td.state.get('lastPnl', 0);

// Check if last trade was a loss
if (td.position.pnl < lastPnl && lastPnl !== 0) {
    td.state.set('consecutiveLosses', consecutiveLosses + 1);
} else if (td.position.pnl > 0) {
    td.state.set('consecutiveLosses', 0);
}

td.state.set('lastPnl', td.position.pnl);

// Pause trading after 3 consecutive losses
if (consecutiveLosses >= 3) {
    td.utils.log('Pausing - 3 consecutive losses');
    return; // Exit strategy early
}

// ... rest of trading logic

Testing Your Strategy

Before deploying with real money:

  1. Paper Trading: Always test on a paper exchange first
  2. Backtesting: Use the backtesting feature to test against historical data
  3. Small Positions: When going live, start with small position sizes
  4. Monitor Closely: Watch your bot's behavior for the first few days

Common Mistakes to Avoid

Trading on Every Spin

// BAD - Will trade too frequently
td.trade.buy({ amountPercent: 100 });

// GOOD - Only trade when conditions are met
if (rsi < 30 && !td.position.hasPosition) {
    td.trade.buy({ amountPercent: 100 });
}

Ignoring Stop Losses

// BAD - No risk management
td.trade.buy({ amountPercent: 100 });

// GOOD - Always use stop losses
td.trade.buy({
    amountPercent: 100,
    stopLoss: td.market.price * 0.98
});

Not Checking Position Status

// BAD - Might try to open multiple positions
if (rsi < 30) {
    td.trade.buy({ amountPercent: 100 });
}

// GOOD - Check if already in position
if (rsi < 30 && !td.position.hasPosition) {
    td.trade.buy({ amountPercent: 100 });
}

Next Steps