tradovate-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tradovate Patterns

Tradovate 开发模式

Lightweight scaffold for Tradovate JavaScript indicator development.
用于Tradovate JavaScript指标开发的轻量级脚手架。

File Conventions

文件命名规范

  • File naming:
    *LB.js
    or
    *ProLB.js
  • Tags: Must include "Luther Barnum"
  • 文件命名:
    *LB.js
    *ProLB.js
  • 标签:必须包含 "Luther Barnum"

Dependencies

依赖项

javascript
const predef = require("./tools/predef");
const meta = require("./tools/meta");
const { ParamType } = meta;
javascript
const predef = require("./tools/predef");
const meta = require("./tools/meta");
const { ParamType } = meta;

Class Structure

类结构

javascript
class IndicatorName {
    init() {
        // One-time initialization
        this.cumulativeValue = 0;
    }

    map(d, i, history) {
        // d = current bar { open, high, low, close, volume, timestamp }
        // i = bar index
        // history = historical data access

        const result = {};
        result.plotName = calculatedValue;
        return result;
    }

    filter() {
        // Optional validation
        return true;
    }
}
javascript
class IndicatorName {
    init() {
        // 一次性初始化
        this.cumulativeValue = 0;
    }

    map(d, i, history) {
        // d = 当前K线 { open, high, low, close, volume, timestamp }
        // i = K线索引
        // history = 历史数据访问接口

        const result = {};
        result.plotName = calculatedValue;
        return result;
    }

    filter() {
        // 可选的验证逻辑
        return true;
    }
}

Export Pattern

导出模式

javascript
module.exports = {
    name: "indicator-name",
    description: "Description of indicator",
    calculator: IndicatorName,
    params: {
        period: predef.paramSpecs.period(14),
        multiplier: {
            type: ParamType.NUMBER,
            def: 1.0,
            step: 0.1,
            min: 0.1,
            max: 10.0
        }
    },
    plots: {
        value: { title: "Value" },
        upperBand: { title: "Upper Band" }
    },
    inputType: meta.InputType.BARS,
    tags: ["Luther Barnum", "vwap", "trading"],
    schemeStyles: {
        dark: {
            value: predef.styles.plot({ color: "#00FF00" })
        }
    }
};
javascript
module.exports = {
    name: "indicator-name",
    description: "Description of indicator",
    calculator: IndicatorName,
    params: {
        period: predef.paramSpecs.period(14),
        multiplier: {
            type: ParamType.NUMBER,
            def: 1.0,
            step: 0.1,
            min: 0.1,
            max: 10.0
        }
    },
    plots: {
        value: { title: "Value" },
        upperBand: { title: "Upper Band" }
    },
    inputType: meta.InputType.BARS,
    tags: ["Luther Barnum", "vwap", "trading"],
    schemeStyles: {
        dark: {
            value: predef.styles.plot({ color: "#00FF00" })
        }
    }
};

Session Types

会话类型

Access via
this.props.type
:
  • "chart"
    - Reset per trading day
  • "session"
    - Reset at specific time
  • "rolling"
    - Reset per N-bar window
通过
this.props.type
访问:
  • "chart"
    - 每个交易日重置
  • "session"
    - 在特定时间重置
  • "rolling"
    - 每N根K线窗口重置

History Access

历史数据访问

javascript
// Previous bar
const prevBar = history.prior();

// Specific historical bar
const bar = history.get(i - 5);

// Direct array access
const data = history.data[i];
javascript
// 上一根K线
const prevBar = history.prior();

// 指定的历史K线
const bar = history.get(i - 5);

// 直接数组访问
const data = history.data[i];

Session Detection

会话检测

javascript
map(d, i, history) {
    const tradeDate = d.tradeDate();

    if (tradeDate !== this.lastTradeDate) {
        // New session - reset values
        this.cumulativeValue = 0;
        this.lastTradeDate = tradeDate;
    }
}
javascript
map(d, i, history) {
    const tradeDate = d.tradeDate();

    if (tradeDate !== this.lastTradeDate) {
        // 新会话 - 重置数值
        this.cumulativeValue = 0;
        this.lastTradeDate = tradeDate;
    }
}

Helper Functions

辅助函数

javascript
function number(defValue, step, min, max) {
    return { type: ParamType.NUMBER, def: defValue, step, min, max };
}
javascript
function number(defValue, step, min, max) {
    return { type: ParamType.NUMBER, def: defValue, step, min, max };
}

Complete Example

完整示例

Reference:
/Users/lgbarn/Personal/Indicators/Tradovate/LRBMACD.js
javascript
const predef = require("./tools/predef");
const meta = require("./tools/meta");
const SMA = require("./tools/SMA");

class SimpleMACD {
    init() {
        this.fastSMA = SMA(this.props.fast);
        this.slowSMA = SMA(this.props.slow);
        this.signalSMA = SMA(this.props.signal);
    }

    map(d, i) {
        const value = d.value();
        const macd = this.fastSMA(value) - this.slowSMA(value);

        let signal;
        let histogram;

        if (i >= this.props.slow - 1) {
            signal = this.signalSMA(macd);
            histogram = macd - signal;
        }

        return { macd, signal, histogram, zero: 0 };
    }

    filter(d) {
        return predef.filters.isNumber(d.histogram);
    }
}

module.exports = {
    name: "simple-macd-lb",
    description: "Simple MACD Indicator",
    calculator: SimpleMACD,
    params: {
        fast: predef.paramSpecs.period(3),
        slow: predef.paramSpecs.period(10),
        signal: predef.paramSpecs.period(16)
    },
    validate(obj) {
        if (obj.slow < obj.fast) {
            return meta.error("slow", "Slow must be >= fast");
        }
    },
    inputType: meta.InputType.BARS,
    plots: {
        macd: { title: "MACD" },
        signal: { title: "Signal" },
        histogram: { title: "Histogram" },
        zero: { displayOnly: true }
    },
    tags: ["Luther Barnum", predef.tags.Oscillators],
    schemeStyles: {
        dark: {
            macd: predef.styles.plot("#FFA500"),
            signal: predef.styles.plot("#0000FF"),
            histogram: predef.styles.plot("#FF3300"),
            zero: predef.styles.plot({ color: "#B5BAC2", lineStyle: 3 })
        }
    }
};
参考:
/Users/lgbarn/Personal/Indicators/Tradovate/LRBMACD.js
javascript
const predef = require("./tools/predef");
const meta = require("./tools/meta");
const SMA = require("./tools/SMA");

class SimpleMACD {
    init() {
        this.fastSMA = SMA(this.props.fast);
        this.slowSMA = SMA(this.props.slow);
        this.signalSMA = SMA(this.props.signal);
    }

    map(d, i) {
        const value = d.value();
        const macd = this.fastSMA(value) - this.slowSMA(value);

        let signal;
        let histogram;

        if (i >= this.props.slow - 1) {
            signal = this.signalSMA(macd);
            histogram = macd - signal;
        }

        return { macd, signal, histogram, zero: 0 };
    }

    filter(d) {
        return predef.filters.isNumber(d.histogram);
    }
}

module.exports = {
    name: "simple-macd-lb",
    description: "Simple MACD Indicator",
    calculator: SimpleMACD,
    params: {
        fast: predef.paramSpecs.period(3),
        slow: predef.paramSpecs.period(10),
        signal: predef.paramSpecs.period(16)
    },
    validate(obj) {
        if (obj.slow < obj.fast) {
            return meta.error("slow", "Slow must be >= fast");
        }
    },
    inputType: meta.InputType.BARS,
    plots: {
        macd: { title: "MACD" },
        signal: { title: "Signal" },
        histogram: { title: "Histogram" },
        zero: { displayOnly: true }
    },
    tags: ["Luther Barnum", predef.tags.Oscillators],
    schemeStyles: {
        dark: {
            macd: predef.styles.plot("#FFA500"),
            signal: predef.styles.plot("#0000FF"),
            histogram: predef.styles.plot("#FF3300"),
            zero: predef.styles.plot({ color: "#B5BAC2", lineStyle: 3 })
        }
    }
};

VWAP Calculation Pattern

VWAP 计算模式

javascript
class SessionVWAP {
    init() {
        this.cumVolume = 0;
        this.cumVwap = 0;
        this.cumVwap2 = 0;
        this.lastTradeDate = null;
    }

    map(d, i, history) {
        const currentDate = d.tradeDate();

        // Reset on new session
        if (currentDate !== this.lastTradeDate) {
            this.cumVolume = 0;
            this.cumVwap = 0;
            this.cumVwap2 = 0;
            this.lastTradeDate = currentDate;
        }

        const typicalPrice = (d.high() + d.low() + d.close()) / 3;
        const volume = d.volume();

        this.cumVolume += volume;
        this.cumVwap += volume * typicalPrice;
        this.cumVwap2 += volume * typicalPrice * typicalPrice;

        if (this.cumVolume === 0) {
            return { vwap: undefined, upper: undefined, lower: undefined };
        }

        const vwap = this.cumVwap / this.cumVolume;
        const variance = (this.cumVwap2 / this.cumVolume) - (vwap * vwap);
        const stdev = variance > 0 ? Math.sqrt(variance) : 0;

        return {
            vwap,
            upper: vwap + stdev,
            lower: vwap - stdev
        };
    }
}
javascript
class SessionVWAP {
    init() {
        this.cumVolume = 0;
        this.cumVwap = 0;
        this.cumVwap2 = 0;
        this.lastTradeDate = null;
    }

    map(d, i, history) {
        const currentDate = d.tradeDate();

        // 新会话时重置
        if (currentDate !== this.lastTradeDate) {
            this.cumVolume = 0;
            this.cumVwap = 0;
            this.cumVwap2 = 0;
            this.lastTradeDate = currentDate;
        }

        const typicalPrice = (d.high() + d.low() + d.close()) / 3;
        const volume = d.volume();

        this.cumVolume += volume;
        this.cumVwap += volume * typicalPrice;
        this.cumVwap2 += volume * typicalPrice * typicalPrice;

        if (this.cumVolume === 0) {
            return { vwap: undefined, upper: undefined, lower: undefined };
        }

        const vwap = this.cumVwap / this.cumVolume;
        const variance = (this.cumVwap2 / this.cumVolume) - (vwap * vwap);
        const stdev = variance > 0 ? Math.sqrt(variance) : 0;

        return {
            vwap,
            upper: vwap + stdev,
            lower: vwap - stdev
        };
    }
}

Error Handling Patterns

错误处理模式

Validation function

验证函数

javascript
validate(obj) {
    if (obj.period < 1) {
        return meta.error("period", "Period must be >= 1");
    }
    if (obj.slow <= obj.fast) {
        return meta.error("slow", "Slow must be greater than fast");
    }
}
javascript
validate(obj) {
    if (obj.period < 1) {
        return meta.error("period", "Period must be >= 1");
    }
    if (obj.slow <= obj.fast) {
        return meta.error("slow", "Slow must be greater than fast");
    }
}

Check history in map()

在map()中检查历史数据

javascript
map(d, i, history) {
    // Not enough history
    if (i < this.props.period - 1) {
        return { value: undefined };
    }

    // Check previous bar exists
    const prev = history.prior();
    if (!prev) {
        return { value: undefined };
    }
}
javascript
map(d, i, history) {
    // 历史数据不足
    if (i < this.props.period - 1) {
        return { value: undefined };
    }

    // 检查上一根K线是否存在
    const prev = history.prior();
    if (!prev) {
        return { value: undefined };
    }
}

Safe division

安全除法

javascript
const divisor = d.high() - d.low();
const result = divisor === 0 ? 0 : (d.close() - d.low()) / divisor;
javascript
const divisor = d.high() - d.low();
const result = divisor === 0 ? 0 : (d.close() - d.low()) / divisor;

Filter invalid data

过滤无效数据

javascript
filter(d) {
    return predef.filters.isNumber(d.value);
}

// Or multiple checks
filter(d) {
    return predef.filters.isNumber(d.value) &&
           predef.filters.isNumber(d.signal);
}
javascript
filter(d) {
    return predef.filters.isNumber(d.value);
}

// 或者多条件检查
filter(d) {
    return predef.filters.isNumber(d.value) &&
           predef.filters.isNumber(d.signal);
}

Undefined checks

未定义值检查

javascript
map(d, i, history) {
    const prev = history.prior();
    const prevClose = prev ? prev.close() : d.close();
}
javascript
map(d, i, history) {
    const prev = history.prior();
    const prevClose = prev ? prev.close() : d.close();
}

Trading Context

交易场景

  • Focus: /ES, /NQ futures
  • Timeframe: 5-minute
  • Key concepts: VWAP, Session detection, Cumulative calculations
  • Location:
    /Users/lgbarn/Personal/Indicators/Tradovate/
  • 关注品种:/ES、/NQ 期货
  • 时间周期:5分钟
  • 核心概念:VWAP、会话检测、累计计算
  • 文件位置:
    /Users/lgbarn/Personal/Indicators/Tradovate/

Documentation Sources

文档来源

Use WebSearch to find Tradovate indicator documentation:
  • Tradovate Community Forum (community.tradovate.com)
  • Tradovate Indicator API examples
使用网络搜索查找Tradovate指标相关文档:
  • Tradovate 社区论坛 (community.tradovate.com)
  • Tradovate 指标API示例