TRADEJS / STRATEGY SYSTEM

BUILDTypeScript Strategies

A TypeScript framework for building, backtesting, and running programmable trading strategies—with a self-hosted runtime you control

RUN IN YOUR TERMINAL
LOCAL SETUP
$npx create-tradejs
CREATE PROJECTSTART SERVICESOPEN DASHBOARD

The CLI scaffolds a local TradeJS project, starts the required services, and opens the dashboard.

TRADEJS APP / STRATEGY CHART
BACKTEST VIEW
TradeJS application showing a backtested strategy with entries, exits, take profit and stop loss on a market chart
01 / TRADING ARCHITECTURES

Four paths from backtest to live decisions

TradeJS supports all four. The architecture determines what enters the runtime decision path—and what must be validated before you trust it.

StrengthRequirementRisk
01

Classic trading

Backtest a deterministic strategy across a long history, then promote only pairs and configurations that survive multiple market regimes.

LONG BACKTEST
PAIR SELECTION
RUNTIME

Easy to explain and reproduce, but pair selection is still model selection: without out-of-sample checks, the best history can simply be overfit.

No model latency
Explicit strategy logic
Long history required
Pair-selection overfit risk
02

ML filter

Build a point-in-time dataset from backtest candidates, train on past windows, validate on holdout and walk-forward windows, then score new candidates locally.

BACKTEST DATA
TRAIN + VALIDATE
MODEL GATE
RUNTIME

Inference is fast. The operational burden moves to leakage prevention, drift monitoring, retraining, and explaining model decisions.

Fast local inference
Walk-forward + retraining
Harder to explain
Dataset leakage risk
03

AI at runtime

Send every candidate with its signal-time market context to an external model and use the answer as an allow-or-reject decision before the order.

SIGNAL
AI REQUEST
ALLOW / REJECT
ORDER

Latency, cost, model updates, and nondeterminism enter the execution path. Historical replay is comparable only when provider output is captured or re-run.

Forward testing required
Provider latency
Model / prompt drift
Expensive historical replay
04
RECOMMENDED DIRECTION

AI Gate

Use AI during research to discover candidate pockets in backtest exports. Validate them in time order, then encode the survivors as a local deterministic strategy wrapper.

BACKTEST EXPORT
AI POCKET SEARCH
LOCAL GATE
RUNTIME

Runtime uses only signal-time data and local rules. The same gate can be replayed in backtests, but still needs holdout and forward validation before promotion.

Provider outside decision path
Explicit, versioned rules
Reproducible backtests
Holdout + forward validation

Use AI to discover the rules. Keep runtime deterministic.

RESEARCH → RULES → RUNTIME
02 / THE SYSTEM

Built for TypeScript Developers

Use the language, tools, and infrastructure you already control

01AUTHOR

TypeScript-Native Strategies

Build typed strategy logic, indicators, and replayable state machines with IDE support and access to the npm ecosystem.

02REUSE

One Strategy Lifecycle

Use the same TypeScript strategy implementation to backtest historical data, generate runtime signals, and prepare controlled execution.

03OWN

Self-Hosted by Default

Keep strategy code, market data, exchange credentials, and execution on infrastructure you operate.

03 / CODE → RESULT

Developer Experience

A typed strategy API with npm packages, IDE support, and code you can test

MaStrategy/core.ts
TYPE SAFE
export const createMaStrategyCore: CreateStrategyCore<
  MaStrategyConfig,
  IndicatorsHistorySnapshot | undefined
> = async ({ config, strategyApi }) => {
  const { FEE_PERCENT, MAX_LOSS_VALUE, TRADE_COOLDOWN_MS, LONG, SHORT } =
    config;

  const lastTradeController = strategyApi.createLastTradeController({
    enabled: Number(TRADE_COOLDOWN_MS ?? 0) > 0,
    cooldownMs: Number(TRADE_COOLDOWN_MS ?? 0),
  });

  return async () => {
    const { indicators } = strategyApi.getCurrentIndicatorsContext();
    if (!indicators) {
      return strategyApi.skip('NO_INDICATORS');
    }

    const maFast = Array.isArray(indicators.maFast) ? indicators.maFast : [];
    const maSlow = Array.isArray(indicators.maSlow) ? indicators.maSlow : [];
    if (maFast.length < 2 || maSlow.length < 2) {
      return strategyApi.skip('WAIT_MA_DATA');
    }

    const cross = detectCross(maFast, maSlow);
    const position = await strategyApi.getCurrentPosition();
    const positionExists = Boolean(
      position && typeof position.qty === 'number' && position.qty > 0,
    );

    if (positionExists && position) {
      if (
        (position.direction === 'LONG' && cross?.kind === 'bearish') ||
        (position.direction === 'SHORT' && cross?.kind === 'bullish')
      ) {
        return strategyApi.exit({
          code: 'CLOSE_BY_OPPOSITE_MA_CROSS',
          direction: position.direction,
        });
      }

      return strategyApi.skip('POSITION_HELD');
    }

    if (!cross) {
      return strategyApi.skip('NO_CROSS');
    }

    const modeConfig = cross.kind === 'bullish' ? LONG : SHORT;
    if (!modeConfig.enable) {
      return strategyApi.skip('STRATEGY_DISABLED');
    }

    const { timestamp, currentPrice, candle } =
      await strategyApi.getDecisionPriceContext();
    if (lastTradeController.isInCooldown(timestamp)) {
      return strategyApi.skip('TRADE_COOLDOWN');
    }

    const { stopLossPrice, takeProfitPrice, riskRatio, qty } =
      strategyApi.getDirectionalTpSlPrices({
        price: currentPrice,
        direction: modeConfig.direction,
        takeProfitDelta: modeConfig.TP,
        stopLossDelta: modeConfig.SL,
        unit: 'percent',
        maxLossValue: MAX_LOSS_VALUE,
        feePercent: Number(FEE_PERCENT ?? 0),
      });

    if (!qty || !Number.isFinite(qty) || qty <= 0) {
      return strategyApi.skip('INVALID_QTY');
    }

    if (riskRatio <= modeConfig.minRiskRatio) {
      return strategyApi.skip(`RISK_RATIO:${round(riskRatio)}`);
    }

    const correlation = getIndicatorsCorrelation(indicators);
    const figureCandles = Array.isArray(indicators.candles15m)
      ? (indicators.candles15m as KlineChartData)
      : candle
        ? ([candle] as KlineChartData)
        : [];

    lastTradeController.markTrade(timestamp);

    return strategyApi.entry({
      code: cross.kind === 'bullish' ? 'MA_BULLISH_CROSS' : 'MA_BEARISH_CROSS',
      direction: modeConfig.direction,
      figures: buildMaStrategyFigures({
        candles: figureCandles,
        maFast,
        maSlow,
        crossTimestamp: timestamp,
        crossPrice: currentPrice,
        crossKind: cross.kind,
      }),
      indicators,
      additionalIndicators: {
        crossKind: cross.kind,
        maFastPrev: cross.maFastPrev,
        maFastCurrent: cross.maFastCurrent,
        maSlowPrev: cross.maSlowPrev,
        maSlowCurrent: cross.maSlowCurrent,
        maGap: cross.maFastCurrent - cross.maSlowCurrent,
        correlation,
      },
      orderPlan: {
        qty,
        stopLossPrice,
        takeProfits: [{ rate: 1, price: takeProfitPrice }],
      },
    });
  };
};
packages/strategies/src/MaStrategy/core.tsExplore TypeScript API
TradeJS runtime dashboard showing strategy performance, drawdown, orders and win rate
TradeJS strategy statistics with closed orders, win rate, profit and loss, drawdown and performance metrics
04 / PROVE & PROMOTE

From Backtest to Runtime

Move one TypeScript strategy through research, comparison, signals, and controlled execution

01 / REPLAY

Backtest & Compare

Run deterministic backtests and parameter grids, then inspect metrics and artifacts before selecting a configuration.

TRADEJS APP / BACKTEST RUNNER
RUNNING
TradeJS backtest runner with strategy, date window, connector and parallel execution settings
02 / PROMOTE

Promote & Run

Promote a selected result into runtime configuration, evaluate closed candles, and optionally automate execution.

TRADEJS APP / RUNTIME PERFORMANCE
LIVE METRICS
TradeJS runtime dashboard showing strategy performance, drawdown, orders and win rate
TRADEJS / NEXT RUN
READY
DEPLOY YOUR IDEA

Build Your Strategy in TypeScript

Start with the real example, run a historical replay, and inspect your first result before changing the strategy.

WRITE / TYPESCRIPT
TEST / HISTORICAL DATA
RUN / SELF-HOSTED