Home > SDK Trading

SDK Trading

Fintechee 2020-01-18

Fintechee provides SDK Trading which includes Algorithms for Trading. Automated Trading is based on SDK trading. Fintechee has RESTful API and JS API(running on the browser) which help traders monitor the market movements and trade Forex automatically.

Please use our WEB trader to implement your trading strategies.

More Materials

Constant Definition

var BROKER_NAME = {
	DEMO: "CC Demo"
}

var TIME_FRAME = {
	M1: "M1",
	M5: "M5",
	M15: "M15",
	M30: "M30",
	H1: "H1",
	H4: "H4",
	D: "D",
	W: "W",
	M: "M"
}

var ORDER_TYPE = {
	OP_BUY: "BUY",
	OP_SELL: "SELL",
	OP_BUYLIMIT: "BUY LIMIT",
	OP_SELLLIMIT: "SELL LIMIT",
	OP_BUYSTOP: "BUY STOP",
	OP_SELLSTOP: "SELL STOP"
}

var WHERE_TO_RENDER = {
	CHART_WINDOW: "CHART_WINDOW",
	SEPARATE_WINDOW: "SEPARATE_WINDOW"
}

var DATA_NAME = {
	TIME: "Time",
	OPEN: "Open",
	HIGH: "High",
	LOW: "Low",
	CLOSE: "Close",
	HL2: "HL2",
	HLC3: "HLC3",
	HLCC4: "HLCC4"
}

var RENDER_TYPE = {
	HISTOGRAM: "Histogram",
	LINE: "Line",
	ROUND: "Round",
	DASHARRAY: "Dasharray"
}

var PARAMETER_TYPE = {
	INTEGER: "Integer",
	NUMBER: "Number",
	BOOLEAN: "Boolean",
	STRING: "String"
}

Common Function

function sma (dataInput, dataOutput, calculatedLength, period) {
	var i = calculatedLength

	if (calculatedLength > 0) {
		i--
	} else {
		for (var j = 0; j < period - 1; j++) {
			dataOutput[j] = 0
		}

		i = period - 1
	}

	var sum = 0

	for (var j = i - period + 1; j < i; j++) {
		sum += dataInput[j]
	}

	for (var j = i; j < dataInput.length; j++) {
		sum += dataInput[j]
		dataOutput[j] = sum / period
		sum -= dataInput[j - period + 1]
	}
}

function ema (dataInput, dataOutput, calculatedLength, period) {
	var i = calculatedLength
	var smthFctr = 2.0 / (period + 1)

	if (i == 0) {
		dataOutput[0] = dataInput[0]
		i++
	} else if (i == 1) {
	} else {
		i--
	}

	while (i < dataInput.length) {
		dataOutput[i] = dataInput[i] * smthFctr + dataOutput[i - 1] * (1 - smthFctr)
		i++
	}
}

function smma (dataInput, dataOutput, calculatedLength, period) {
	var i = calculatedLength
	var sum = 0

	if (i > 0) {
		i--
	} else {
		i = period - 1

		for (var j = 1; j < period; j++) {
			dataOutput[i - j] = 0
			sum += dataInput[i - j]
		}

		sum += dataInput[i]
		dataOutput[i] = sum / period
		i++
	}

	while (i < dataInput.length) {
		sum = dataOutput[i - 1] * period - dataOutput[i - 1] + dataInput[i]
		dataOutput[i] = sum / period
		i++
	}
}

function lwma (dataInput, dataOutput, calculatedLength, period) {
	var i = calculatedLength

	if (i > 0) {
		i--
	} else {
		for (var j = 0; j < period - 1; j++) {
			dataOutput[j] = 0
		}

		i = period - 1
	}

	var sum = 0
	var diffsum = 0
	var weight = 0

	for (var j = 1; j < period; j++) {
		sum += dataInput[i - j] * (period - j)
		diffsum += dataInput[i - j]
		weight += j
	}
	weight += period

	while (i < dataInput.length) {
		sum += dataInput[i] * period
		dataOutput[i] = sum / weight
		diffsum += dataInput[i]
		sum -= diffsum
		diffsum -= dataInput[i - period + 1]
		i++
	}
}

Indicator Example

Simple Moving Average

registerIndicator("sma", "Simple Moving Average(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "sma")
    var period = getIndiParameter(context, "period")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    sma(dataInput, dataOutput, calculatedLength, period)

    if (shift != null && calculatedLength == 0) {
        setIndiShift(context, "sma", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "shift",
    value: 0,
    required: false,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "sma",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Exponential Moving Average

registerIndicator("ema", "Exponential Moving Average(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "ema")
    var period = getIndiParameter(context, "period")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    ema(dataInput, dataOutput, calculatedLength, period)

    if (shift != null && calculatedLength == 0) {
        setIndiShift(context, "ema", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "shift",
    value: 0,
    required: false,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "ema",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Smoothed Moving Average

registerIndicator("smma", "Smoothed Moving Average(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "smma")
    var period = getIndiParameter(context, "period")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    smma(dataInput, dataOutput, calculatedLength, period)

    if (shift != null && calculatedLength == 0) {
        setIndiShift(context, "smma", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "shift",
    value: 0,
    required: false,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "smma",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Linear Weighted Moving Average

registerIndicator("lwma", "Linear Weighted Moving Average(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "lwma")
    var period = getIndiParameter(context, "period")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    lwma(dataInput, dataOutput, calculatedLength, period)

    if (shift != null && calculatedLength == 0) {
        setIndiShift(context, "lwma", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "shift",
    value: 0,
    required: false,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "lwma",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

MACD

registerIndicator("macd", "MACD(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataFEMA = getDataOutput(context, "fastEMA")
    var dataSEMA = getDataOutput(context, "slowEMA")
    var dataOutputMain = getDataOutput(context, "main")
    var dataOutputSignal = getDataOutput(context, "signal")

    var fEMA = getIndiParameter(context, "fasteEMA")
    var sEMA = getIndiParameter(context, "slowEMA")
    var sgnlSMA = getIndiParameter(context, "signalSMA")

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength

    if (i == 0) {
        dataFEMA[0] = dataInput[0]
        dataSEMA[0] = dataInput[0]
        dataOutputMain[0] = 0
        i++
    } else if (i == 1) {
    } else {
        i--
    }

    ema(dataInput, dataFEMA, calculatedLength, fEMA)
    ema(dataInput, dataSEMA, calculatedLength, sEMA)

    while (i < dataInput.length) {
        dataOutputMain[i] = dataFEMA[i] - dataSEMA[i]
        i++
    }

    sma(dataOutputMain, dataOutputSignal, calculatedLength, sgnlSMA)
},[{
    name: "fasteEMA",
    value: 12,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "slowEMA",
    value: 26,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "signalSMA",
    value: 9,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "main",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#4EC2B4"
},{
    name: "signal",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#CCCCCC"
},{
    name: "fastEMA",
    visible: false
},{
    name: "slowEMA",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Relative Strength Index

registerIndicator("rsi", "Relative Strength Index(v1.01)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "rsi")
    var dataOutputHL = getDataOutput(context, "rsiHighLevel")
    var dataOutputLL = getDataOutput(context, "rsiLowLevel")
    var gainTmp = getDataOutput(context, "gainTmp")
    var lossTmp = getDataOutput(context, "lossTmp")

    var period = getIndiParameter(context, "period")
    var highLevel = getIndiParameter(context, "highLevel")
    var lowLevel = getIndiParameter(context, "lowLevel")

    var calculatedLength = getCalculatedLength(context)

    var ptr = null
    var ptr2 = null

    var diff = null
    var gain = null
    var loss = null
    var gainSum = 0
    var lossSum = 0

    if (calculatedLength > 0) {
        ptr = calculatedLength - 1
        ptr2 = calculatedLength - period
    } else {
        for (var i = 0; i < period; i++) {
            dataOutput[i] = 0
            dataOutputHL[i] = highLevel
            dataOutputLL[i] = lowLevel
        }

        ptr = period
        ptr2 = 1

        while (ptr2 <= ptr) {
            diff = dataInput[ptr2] - dataInput[ptr2 - 1]
            if (0 < diff) {
                gainSum += diff
            } else {
                lossSum -= diff
            }
            ptr2++
        }
        gain = gainSum / period
        loss = lossSum / period
        if (0 == (gain + loss)) {
            dataOutput[ptr] = 0
        } else {
            dataOutput[ptr] = 100 * gain / (gain + loss)
        }
        dataOutputHL[ptr] = highLevel
        dataOutputLL[ptr] = lowLevel
        gainTmp[ptr] = gain
        lossTmp[ptr] = loss
        ptr++
    }

    while (ptr < dataInput.length) {
        gain = gainTmp[ptr - 1] * (period - 1)
        loss = lossTmp[ptr - 1] * (period - 1)

        diff = dataInput[ptr] - dataInput[ptr - 1]
        if (0 < diff) {
            gain += diff
        } else {
            loss -= diff
        }
        gain = gain / period
        loss = loss / period

        if (0 == (gain + loss)) {
            dataOutput[ptr] = 0
        } else {
            dataOutput[ptr] = 100 * gain / (gain + loss)
        }
        dataOutputHL[ptr] = highLevel
        dataOutputLL[ptr] = lowLevel
        gainTmp[ptr] = gain
        lossTmp[ptr] = loss
        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "highLevel",
    value: 70,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [1, 100]
},{
    name: "lowLevel",
    value: 30,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "rsi",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "rsiHighLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "rsiLowLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "gainTmp",
    visible: false
},{
    name: "lossTmp",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Average True Range

registerIndicator("atr", "Average True Range(v1.0)", function (context) {
    var dataInputClose = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataInputLow = getDataInput(context, 2)
    var tmpLine = getDataOutput(context, "tmp")
    var dataOutput = getDataOutput(context, "atr")

    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength
    var high = null
    var low = null
    var prevClose = null

    if (i > 0) {
        i--
    } else {
        tmpLine[i] = 0
        i = 1
    }

    while (i < dataInputClose.length) {
        high = dataInputHigh[i]
        low = dataInputLow[i]
        prevClose = dataInputClose[i - 1]

        tmpLine[i] = Math.max(high, prevClose) - Math.min(low, prevClose)

        i++
    }

    sma(tmpLine, dataOutput, calculatedLength, period)
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
},{
    name: DATA_NAME.LOW,
    index: 2
}],
[{
    name: "tmp",
    visible: false
},{
    name: "atr",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Average Directional Index

registerIndicator("adx", "Average Directional Index(v1.0)", function (context) {
    var dataInputClose = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataInputLow = getDataInput(context, 2)

    var tmpLine = getDataOutput(context, "tmp")
    var plusSdiTmp = getDataOutput(context, "plusSdiTmp")
    var minusSdiTmp = getDataOutput(context, "minusSdiTmp")

    var dataOutputAdx = getDataOutput(context, "adx")
    var dataOutputPlusDi = getDataOutput(context, "plusDi")
    var dataOutputMinusDi = getDataOutput(context, "minusDi")

    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength

    if (i > 0) {
        i--
    } else {
        plusSdiTmp[i] = 0
        minusSdiTmp[i] = 0
        i = 1
    }

    var plusDM = null
    var minusDM = null
    var trueRange = null
    var currH = null
    var currL = null
    var prevH = null
    var prevL = null
    var prevC = null

    while (i < dataInputClose.length) {
        currH = dataInputHigh[i]
        currL = dataInputLow[i]
        prevH = dataInputHigh[i - 1]
        prevL = dataInputLow[i - 1]
        prevC = dataInputClose[i - 1]

        plusDM = currH - prevH
        minusDM = prevL - currL
        if (0 > plusDM) {
            plusDM = 0
        }
        if (0 > minusDM) {
            minusDM = 0
        }
        if (plusDM == minusDM) {
            plusDM = 0
            minusDM = 0
        } else if (plusDM < minusDM) {
            plusDM = 0
        } else if (plusDM > minusDM) {
            minusDM = 0
        }

        trueRange = Math.max(Math.abs(currH - currL), Math.abs(currH - prevC))
        trueRange = Math.max(trueRange, Math.abs(currL - prevC))

        if (0 == trueRange) {
            plusSdiTmp[i] = 0
            minusSdiTmp[i] = 0
        }else{
            plusSdiTmp[i] = 100 * plusDM / trueRange
            minusSdiTmp[i] = 100 * minusDM / trueRange
        }

        i++
    }

    ema(plusSdiTmp, dataOutputPlusDi, calculatedLength, period)
    ema(minusSdiTmp, dataOutputMinusDi, calculatedLength, period)

    i = calculatedLength
    if (i > 0) {
        i--
    }

    while (i < dataInputClose.length) {
        var tmp = Math.abs(dataOutputPlusDi[i] + dataOutputMinusDi[i])

        if (0 == tmp) {
            tmpLine[i] = 0
        } else {
            tmpLine[i] = 100 * (Math.abs(dataOutputPlusDi[i] - dataOutputMinusDi[i]) / tmp)
        }

        i++
    }

    ema(tmpLine, dataOutputAdx, calculatedLength, period)
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
},{
    name: DATA_NAME.LOW,
    index: 2
}],
[{
    name: "adx",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#CCCCCC"
},{
    name: "plusDi",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#4EC2B4"
},{
    name: "minusDi",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#DE5029"
},{
    name: "tmp",
    visible: false
},{
    name: "plusSdiTmp",
    visible: false
},{
    name: "minusSdiTmp",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Parabolic SAR

registerIndicator("sar", "Parabolic SAR(v1.0)", function (context) {
    var dataInputHigh = getDataInput(context, 0)
    var dataInputLow = getDataInput(context, 1)

    var dataOutput = getDataOutput(context, "sar")

    var acceleration = getIndiParameter(context, "acceleration")
    var af = acceleration
    var afMax = getIndiParameter(context, "afMax")

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength

    if (i > 0) {
        i--
    } else {
        dataOutput[i] = 0
        i = 1
    }

    var prevH = dataInputHigh[i - 1]
    var prevL = dataInputLow[i - 1]
    var currH = null
    var currL = null

    var isLong = true
    var ep = prevH
    var sar = prevL

    while (i < dataInputHigh.length) {
        currH = dataInputHigh[i]
        currL = dataInputLow[i]

        if (isLong) {
            if (currL <= sar) {
                isLong = false
                sar = Math.max(ep, currH, prevH)

                dataOutput[i] = sar

                af = acceleration
                ep = currL
                sar = sar + af * (ep - sar)
                sar = Math.max(sar, currH, prevH)
            } else {
                dataOutput[i] = sar

                if (currH > ep) {
                    ep = currH
                    af += acceleration
                    if (af > afMax) {
                        af = afMax
                    }
                }
                sar = sar + af * (ep - sar)
                sar = Math.min(sar, currL, prevL)
            }
        } else {
            if (currH >= sar) {
                isLong = true
                sar = Math.min(ep, currL, prevL)

                dataOutput[i] = sar

                af = acceleration
                ep = currH
                sar = sar + af * (ep - sar)
                sar = Math.min(sar, currL, prevL)
            }else{
                dataOutput[i] = sar

                if (currL < ep) {
                    ep = currL
                    af += acceleration
                    if (af > afMax) {
                        af = afMax
                    }
                }
                sar = sar + af * (ep - sar)
                sar = Math.max(sar, currH, prevH)
            }
        }
        i++

        prevH = currH
        prevL = currL
    }
},[{
    name: "acceleration",
    value: 0.02,
    required: true,
    type: PARAMETER_TYPE.NUMBER,
    range: [0.01, 0.1]
},{
    name: "afMax",
    value: 0.2,
    required: true,
    type: PARAMETER_TYPE.NUMBER,
    range: [0.1, 1]
}],
[{
    name: DATA_NAME.HIGH,
    index: 0
},{
    name: DATA_NAME.LOW,
    index: 1
}],
[{
    name: "sar",
    visible: true,
    renderType: RENDER_TYPE.ROUND,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Stochastic Oscillator

registerIndicator("stochastic", "Stochastic Oscillator(v1.01)", function (context) {
    var dataInputClose = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataInputLow = getDataInput(context, 2)

    var highestTmp = getDataOutput(context, "highestTmp")
    var lowestTmp = getDataOutput(context, "lowestTmp")

    var dataOutputMain = getDataOutput(context, "main")
    var dataOutputSignal = getDataOutput(context, "signal")

    var kP = getIndiParameter(context, "KPeriod")
    var slowing = getIndiParameter(context, "slowing")
    var dP = getIndiParameter(context, "DPeriod")
    var method = getIndiParameter(context, "method")

    var calculatedLength = getCalculatedLength(context)
    var ptr = calculatedLength
    var maxParam = Math.max(kP + slowing - 1, dP)

    if (ptr > 0) {
        ptr--
    } else {
        ptr = maxParam - 1

        for (var i = 1; i < maxParam; i++) {
            dataOutputMain[ptr - i] = 0
            highestTmp[ptr - i] = 0
            lowestTmp[ptr - i] = 0
        }
    }

    while (ptr < dataInputClose.length) {
        var tmp = null
        var highest = -Number.MAX_VALUE
        var lowest = Number.MAX_VALUE

        for (var ptr2 = (ptr - kP + 1); ptr2 <= ptr; ptr2++){
            tmp = dataInputHigh[ptr2]
            if (highest < tmp) {
                highest = tmp
            }

            tmp = dataInputLow[ptr2]
            if (lowest > tmp) {
                lowest = tmp
            }
        }

        highestTmp[ptr] = highest
        lowestTmp[ptr] = lowest

        ptr++
    }

    ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = maxParam - 1
    }

    while (ptr < dataInputClose.length) {
        var highestSum = 0
        var lowestSum = 0

        for (var ptr2 = ptr - slowing + 1; ptr2 <= ptr; ptr2++) {
            highestSum += highestTmp[ptr2] - lowestTmp[ptr2]
            lowestSum += dataInputClose[ptr2] - lowestTmp[ptr2]
        }

        if (0 == highestSum) {
            dataOutputMain[ptr] = 100
        }else{
            dataOutputMain[ptr] = lowestSum / highestSum * 100
        }

        ptr++
    }

    if ("sma" == method) {
        sma(dataOutputMain, dataOutputSignal, calculatedLength, dP)
    } else if ("ema" == method) {
        ema(dataOutputMain, dataOutputSignal, calculatedLength, dP)
    } else if ("smma" == method) {
        smma(dataOutputMain, dataOutputSignal, calculatedLength, dP)
    } else {
        lwma(dataOutputMain, dataOutputSignal, calculatedLength, dP)
    }
},[{
    name: "KPeriod",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "slowing",
    value: 3,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "DPeriod",
    value: 3,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "method",
    value: "sma",
    required: true,
    type: PARAMETER_TYPE.STRING
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
},{
    name: DATA_NAME.LOW,
    index: 2
}],
[{
    name: "main",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#DE5029"
},{
    name: "signal",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#4EC2B4"
},{
    name: "highestTmp",
    visible: false
},{
    name: "lowestTmp",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Alligator

registerIndicator("alligator", "A series of Bill Williams' indicators(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutputJaws = getDataOutput(context, "jaws")
    var dataOutputTeeth = getDataOutput(context, "teeth")
    var dataOutputLips = getDataOutput(context, "lips")

    var method = getIndiParameter(context, "method")
    var jawsPeriod = getIndiParameter(context, "jawsPeriod")
    var jawsShift = getIndiParameter(context, "jawsShift")
    var teethPeriod = getIndiParameter(context, "teethPeriod")
    var teethShift = getIndiParameter(context, "teethShift")
    var lipsPeriod = getIndiParameter(context, "lipsPeriod")
    var lipsShift = getIndiParameter(context, "lipsShift")

    var calculatedLength = getCalculatedLength(context)

    if ("smma" == method) {
        smma(dataInput, dataOutputJaws, calculatedLength, jawsPeriod)
        smma(dataInput, dataOutputTeeth, calculatedLength, teethPeriod)
        smma(dataInput, dataOutputLips, calculatedLength, lipsPeriod)
    } else if ("sma" == method) {
        sma(dataInput, dataOutputJaws, calculatedLength, jawsPeriod)
        sma(dataInput, dataOutputTeeth, calculatedLength, teethPeriod)
        sma(dataInput, dataOutputLips, calculatedLength, lipsPeriod)
    } else if("ema" == method) {
        ema(dataInput, dataOutputJaws, calculatedLength, jawsPeriod)
        ema(dataInput, dataOutputTeeth, calculatedLength, teethPeriod)
        ema(dataInput, dataOutputLips, calculatedLength, lipsPeriod)
    } else {
        lwma(dataInput, dataOutputJaws, calculatedLength, jawsPeriod)
        lwma(dataInput, dataOutputTeeth, calculatedLength, teethPeriod)
        lwma(dataInput, dataOutputLips, calculatedLength, lipsPeriod)
    }

    if (calculatedLength == 0) {
        setIndiShift(context, "jaws", jawsShift)
        setIndiShift(context, "teeth", teethShift)
        setIndiShift(context, "lips", lipsShift)
    }
},[{
    name: "jawsPeriod",
    value: 13,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "jawsShift",
    value: 8,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [0, 30]
},{
    name: "teethPeriod",
    value: 8,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "teethShift",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [0, 30]
},{
    name: "lipsPeriod",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "lipsShift",
    value: 3,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [0, 30]
},{
    name: "method",
    value: "smma",
    required: true,
    type: PARAMETER_TYPE.STRING
}],
[{
    name: DATA_NAME.HL2,
    index: 0
}],
[{
    name: "jaws",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "teeth",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#4EC2B4"
},{
    name: "lips",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#DE5029"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Fractals

registerIndicator("fractals", "Fractals(v1.0)", function (context) {
    var dataInputHigh = getDataInput(context, 0)
    var dataInputLow = getDataInput(context, 1)
    var dataOutputUp = getDataOutput(context, "fractalsUp")
    var dataOutputDown = getDataOutput(context, "fractalsDown")

    var calculatedLength = getCalculatedLength(context)

    var ptr = null

    if (calculatedLength > 0) {
        ptr = calculatedLength - 3
    } else {
        for (var i = 0; i < dataInputHigh.length; i++) {
            dataOutputUp[i] = 0
            dataOutputDown[i] = 0
        }

        ptr = 2
    }

    var bFound = false
    var highest = null
    var lowest = null

    while (ptr < dataInputHigh.length - 2) {
        bFound = false
        highest = dataInputHigh[ptr]

        if (highest > dataInputHigh[ptr - 1] && highest > dataInputHigh[ptr - 2] && highest > dataInputHigh[ptr + 1] && highest > dataInputHigh[ptr + 2]) {
            bFound = true
            dataOutputUp[ptr] = highest
        }
        if (!bFound && ptr >= 3) {
            if (highest > dataInputHigh[ptr - 1] && highest > dataInputHigh[ptr - 2] && highest > dataInputHigh[ptr - 3] && highest > dataInputHigh[ptr + 1] && highest > dataInputHigh[ptr + 2]) {
                bFound = true
                dataOutputUp[ptr] = highest
            }
        }
        if (!bFound && ptr >= 4) {
            if (highest > dataInputHigh[ptr - 1] && highest > dataInputHigh[ptr - 2] && highest > dataInputHigh[ptr - 3] && highest > dataInputHigh[ptr - 4] && highest > dataInputHigh[ptr + 1] && highest > dataInputHigh[ptr + 2]) {
                bFound = true
                dataOutputUp[ptr] = highest
            }
        }
        if (!bFound && ptr >= 5) {
            if (highest > dataInputHigh[ptr - 1] && highest > dataInputHigh[ptr - 2] && highest > dataInputHigh[ptr - 3] && highest > dataInputHigh[ptr - 4] && highest > dataInputHigh[ptr - 5] && highest > dataInputHigh[ptr + 1] && highest > dataInputHigh[ptr + 2]) {
                bFound = true
                dataOutputUp[ptr] = highest
            }
        }
        if (!bFound && ptr >= 6) {
            if (highest > dataInputHigh[ptr - 1] && highest > dataInputHigh[ptr - 2] && highest > dataInputHigh[ptr - 3] && highest > dataInputHigh[ptr - 4] && highest > dataInputHigh[ptr - 5] && highest > dataInputHigh[ptr - 6] && highest > dataInputHigh[ptr + 1] && highest > dataInputHigh[ptr + 2]) {
                bFound = true
                dataOutputUp[ptr] = highest
            }
        }

        bFound = false
        lowest = dataInputLow[ptr]

        if (lowest < dataInputLow[ptr - 1] && lowest < dataInputLow[ptr - 2] && lowest < dataInputLow[ptr + 1] && lowest < dataInputLow[ptr + 2]) {
            bFound = true
            dataOutputDown[ptr] = lowest
        }
        if (!bFound && ptr >= 3) {
            if (lowest < dataInputLow[ptr - 1] && lowest < dataInputLow[ptr - 2] && lowest < dataInputLow[ptr - 3] && lowest < dataInputLow[ptr + 1] && lowest < dataInputLow[ptr + 2]) {
                bFound = true
                dataOutputDown[ptr] = lowest
            }
        }
        if (!bFound && ptr >= 4) {
            if (lowest < dataInputLow[ptr - 1] && lowest < dataInputLow[ptr - 2] && lowest < dataInputLow[ptr - 3] && lowest < dataInputLow[ptr - 4] && lowest < dataInputLow[ptr + 1] && lowest < dataInputLow[ptr + 2]) {
                bFound = true
                dataOutputDown[ptr] = lowest
            }
        }
        if (!bFound && ptr >= 5) {
            if (lowest < dataInputLow[ptr - 1] && lowest < dataInputLow[ptr - 2] && lowest < dataInputLow[ptr - 3] && lowest < dataInputLow[ptr - 4] && lowest < dataInputLow[ptr - 5] && lowest < dataInputLow[ptr + 1] && lowest < dataInputLow[ptr + 2]) {
                bFound = true
                dataOutputDown[ptr] = lowest
            }
        }
        if (!bFound && ptr >= 6) {
            if (lowest < dataInputLow[ptr - 1] && lowest < dataInputLow[ptr - 2] && lowest < dataInputLow[ptr - 3] && lowest < dataInputLow[ptr - 4] && lowest < dataInputLow[ptr - 5] && lowest < dataInputLow[ptr - 6] && lowest < dataInputLow[ptr + 1] && lowest < dataInputLow[ptr + 2]) {
                bFound = true
                dataOutputDown[ptr] = lowest
            }
        }

        ptr++
    }
},[],
[{
    name: DATA_NAME.HIGH,
    index: 0
},{
    name: DATA_NAME.LOW,
    index: 1
}],
[{
    name: "fractalsUp",
    visible: true,
    renderType: RENDER_TYPE.ROUND,
    color: "green"
},{
    name: "fractalsDown",
    visible: true,
    renderType: RENDER_TYPE.ROUND,
    color: "red"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Bollinger Bands

registerIndicator("bands", "Bollinger Bands(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "ma")
    var dataOutputUpper = getDataOutput(context, "upper")
    var dataOutputLower = getDataOutput(context, "lower")

    var method = getIndiParameter(context, "method")
    var period = getIndiParameter(context, "period")
    var deviations = getIndiParameter(context, "deviations")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    if ("smma" == method) {
        smma(dataInput, dataOutput, calculatedLength, period)
    } else if("ema" == method) {
        ema(dataInput, dataOutput, calculatedLength, period)
    } else if ("lwma" == method) {
        lwma(dataInput, dataOutput, calculatedLength, period)
    } else {
        sma(dataInput, dataOutput, calculatedLength, period)
    }

    var ptr = null
    var ptr2 = null

    if (calculatedLength > 0) {
        ptr = calculatedLength - 1
    } else {
        for (var i = 0; i < period - 1; i++) {
            dataOutputUpper[i] = 0
            dataOutputLower[i] = 0
        }

        ptr = period - 1
    }

    var devVal, sum, midVal, tmp

    while (ptr < dataInput.length) {
        sum = 0
        ptr2 = ptr - period + 1
        midVal = dataOutput[ptr]
        while (ptr2 <= ptr) {
            tmp = dataInput[ptr2] - midVal
            sum += tmp * tmp
            ptr2++
        }
        devVal = deviations * Math.sqrt(sum / period)
        dataOutputUpper[ptr] = midVal + devVal
        dataOutputLower[ptr] = midVal - devVal

        ptr++
    }

    if (calculatedLength == 0) {
        setIndiShift(context, "ma", shift)
        setIndiShift(context, "upper", shift)
        setIndiShift(context, "lower", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "deviations",
    value: 2.0,
    required: true,
    type: PARAMETER_TYPE.NUMBER,
    range: [0, 10]
},{
    name: "shift",
    value: 0,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
},{
    name: "method",
    value: "sma",
    required: true,
    type: PARAMETER_TYPE.STRING
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "ma",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "upper",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "steelblue"
},{
    name: "lower",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Envelopes

registerIndicator("envelopes", "Envelopes(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "ma")
    var dataOutputUpper = getDataOutput(context, "upper")
    var dataOutputLower = getDataOutput(context, "lower")

    var method = getIndiParameter(context, "method")
    var period = getIndiParameter(context, "period")
    var deviations = getIndiParameter(context, "deviations")
    var shift = getIndiParameter(context, "shift")

    var calculatedLength = getCalculatedLength(context)

    if ("smma" == method) {
        smma(dataInput, dataOutput, calculatedLength, period)
    } else if("ema" == method) {
        ema(dataInput, dataOutput, calculatedLength, period)
    } else if ("lwma" == method) {
        lwma(dataInput, dataOutput, calculatedLength, period)
    } else {
        sma(dataInput, dataOutput, calculatedLength, period)
    }

    var ptr = null

    if (calculatedLength > 0) {
        ptr = calculatedLength - 1
    } else {
        for (var i = 0; i < period - 1; i++) {
            dataOutputUpper[i] = 0
            dataOutputLower[i] = 0
        }

        ptr = period - 1
    }

    while (ptr < dataInput.length) {
        dataOutputUpper[ptr] = (1 + deviations / 100) * dataOutput[ptr]
        dataOutputLower[ptr] = (1 - deviations / 100) * dataOutput[ptr]

        ptr++
    }

    if (calculatedLength == 0) {
        setIndiShift(context, "ma", shift)
        setIndiShift(context, "upper", shift)
        setIndiShift(context, "lower", shift)
    }
},[{
    name: "period",
    value: 5,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "deviations",
    value: 0.05,
    required: true,
    type: PARAMETER_TYPE.NUMBER,
    range: [0, 10]
},{
    name: "shift",
    value: 0,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [-30, 30]
},{
    name: "method",
    value: "sma",
    required: true,
    type: PARAMETER_TYPE.STRING
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "ma",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "upper",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "steelblue"
},{
    name: "lower",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "steelblue"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Accelerator Oscillator

registerIndicator("ac", "Accelerator Oscillator(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataUp = getDataOutput(context, "up")
    var dataDown = getDataOutput(context, "down")
    var dataFSMA = getDataOutput(context, "fastSMA")
    var dataSSMA = getDataOutput(context, "slowSMA")
    var dataOutputMain = getDataOutput(context, "main")
    var dataOutputSignal = getDataOutput(context, "signal")

    var fSMA = 5
    var sSMA = 34
    var sgnlSMA = 5

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength

    if (i == 0) {
        dataFSMA[0] = dataInput[0]
        dataSSMA[0] = dataInput[0]
        dataOutputMain[0] = 0
        i++
    } else if (i == 1) {
    } else {
        i--
    }

    sma(dataInput, dataFSMA, calculatedLength, fSMA)
    sma(dataInput, dataSSMA, calculatedLength, sSMA)

    while (i < dataInput.length) {
        dataOutputMain[i] = dataFSMA[i] - dataSSMA[i]
        i++
    }

    sma(dataOutputMain, dataOutputSignal, calculatedLength, sgnlSMA)

    i = calculatedLength

    if (i == 0) {
        i++
    } else if (i == 1) {
    } else {
        i--
    }

    var prev, curr

    while (i < dataInput.length) {
        prev = dataOutputMain[i - 1] - dataOutputSignal[i - 1]
        curr = dataOutputMain[i] - dataOutputSignal[i]

        if (prev <= curr) {
            dataUp[i] = curr
            dataDown[i] = 0
        } else {
            dataUp[i] = 0
            dataDown[i] = curr
        }

        i++
    }
},[],
[{
    name: DATA_NAME.HL2,
    index: 0
}],
[{
    name: "up",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#6CBA81"
},{
    name: "down",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#ECAE93"
},{
    name: "fastSMA",
    visible: false
},{
    name: "slowSMA",
    visible: false
},{
    name: "main",
    visible: false
},{
    name: "signal",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Awesome Oscillator

registerIndicator("ao", "Awesome Oscillator(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataUp = getDataOutput(context, "up")
    var dataDown = getDataOutput(context, "down")
    var dataFSMA = getDataOutput(context, "fastSMA")
    var dataSSMA = getDataOutput(context, "slowSMA")

    var fSMA = 5
    var sSMA = 34
    var sgnlSMA = 5

    var calculatedLength = getCalculatedLength(context)
    var i = calculatedLength

    if (i == 0) {
        dataFSMA[0] = dataInput[0]
        dataSSMA[0] = dataInput[0]
        i++
    } else if (i == 1) {
    } else {
        i--
    }

    sma(dataInput, dataFSMA, calculatedLength, fSMA)
    sma(dataInput, dataSSMA, calculatedLength, sSMA)

    var prev, curr

    while (i < dataInput.length) {
        prev = dataFSMA[i - 1] - dataSSMA[i - 1]
        curr = dataFSMA[i] - dataSSMA[i]

        if (prev <= curr) {
            dataUp[i] = curr
            dataDown[i] = 0
        } else {
            dataUp[i] = 0
            dataDown[i] = curr
        }

        i++
    }
},[],
[{
    name: DATA_NAME.HL2,
    index: 0
}],
[{
    name: "up",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#6CBA81"
},{
    name: "down",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#ECAE93"
},{
    name: "fastSMA",
    visible: false
},{
    name: "slowSMA",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Ichimoku Kinko Hyo

registerIndicator("ichimoku", "Ichimoku Kinko Hyo(v1.0)", function (context) {
    var dataInputHigh = getDataInput(context, 0)
    var dataInputLow = getDataInput(context, 1)
    var dataInputClose = getDataInput(context, 2)
    var dataOutputTenkan = getDataOutput(context, "tenkan")
    var dataOutputKijun = getDataOutput(context, "kijun")
    var dataOutputChikou = getDataOutput(context, "chikou")
    var dataOutputSpanA = getDataOutput(context, "spana")
    var dataOutputSpanB = getDataOutput(context, "spanb")

    var tenkan = getIndiParameter(context, "tenkan")
    var kijun = getIndiParameter(context, "kijun")
    var senkou = getIndiParameter(context, "senkou")
    var spanA;
    if (kijun < tenkan) {
        spanA = tenkan;
    }else{
        spanA = kijun;
    }

    var calculatedLength = getCalculatedLength(context)
    var ptr = calculatedLength
    var maxParam = Math.max(tenkan, kijun, spanA, senkou)

    if (ptr > 0) {
        ptr--
    } else {
        ptr = maxParam - 1

        for (var i = 1; i < maxParam; i++) {
            dataOutputTenkan[ptr - i] = 0
            dataOutputKijun[ptr - i] = 0
            dataOutputChikou[ptr - i] = 0
            dataOutputSpanA[ptr - i] = 0
            dataOutputSpanB[ptr - i] = 0
        }
    }

    var ptr2, tmp, highest, lowest

    while (ptr < dataInputHigh.length) {
        tmp = null
        highest = -Number.MAX_VALUE
        lowest = Number.MAX_VALUE

        ptr2 = ptr - tenkan + 1

        while (ptr2 <= ptr) {
            tmp = dataInputHigh[ptr2]
            if (highest < tmp) {
                highest = tmp
            }

            tmp = dataInputLow[ptr2]
            if (lowest > tmp) {
                lowest = tmp
            }

            ptr2++
        }

        dataOutputTenkan[ptr] = (highest + lowest) / 2

        tmp = null
        highest = -Number.MAX_VALUE
        lowest = Number.MAX_VALUE

        ptr2 = ptr - kijun + 1

        while (ptr2 <= ptr) {
            tmp = dataInputHigh[ptr2]
            if (highest < tmp) {
                highest = tmp
            }

            tmp = dataInputLow[ptr2]
            if (lowest > tmp) {
                lowest = tmp
            }

            ptr2++
        }

        dataOutputKijun[ptr] = (highest + lowest) / 2

        dataOutputSpanA[ptr] = (dataOutputTenkan[ptr] + dataOutputKijun[ptr]) / 2

        tmp = null
        highest = -Number.MAX_VALUE
        lowest = Number.MAX_VALUE

        ptr2 = ptr - senkou + 1

        while (ptr2 <= ptr) {
            tmp = dataInputHigh[ptr2]
            if (highest < tmp) {
                highest = tmp
            }

            tmp = dataInputLow[ptr2]
            if (lowest > tmp) {
                lowest = tmp
            }

            ptr2++
        }

        dataOutputSpanB[ptr] = (highest + lowest) / 2

        dataOutputChikou[ptr] = dataInputClose[ptr]

        ptr++
    }

    if (calculatedLength == 0) {
        setIndiShift(context, "chikou", -kijun)
        setIndiShift(context, "spana", kijun)
        setIndiShift(context, "spanb", kijun)
    }
},[{
    name: "tenkan",
    value: 9,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "kijun",
    value: 26,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "senkou",
    value: 52,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.HIGH,
    index: 0
},{
    name: DATA_NAME.LOW,
    index: 1
},{
    name: DATA_NAME.CLOSE,
    index: 2
}],
[{
    name: "tenkan",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#DE5029"
},{
    name: "kijun",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "chikou",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#4EC2B4"
},{
    name: "spana",
    visible: true,
    renderType: RENDER_TYPE.ROUND,
    color: "steelblue"
},{
    name: "spanb",
    visible: true,
    renderType: RENDER_TYPE.ROUND,
    color: "#CCCCCC"
}],
WHERE_TO_RENDER.CHART_WINDOW)

Bears Power

registerIndicator("bears", "Bears Power(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataInputLow = getDataInput(context, 1)
    var dataOutput = getDataOutput(context, "bears")
    var dataOutputEma = getDataOutput(context, "ema")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
        }
    }

    ema(dataInput, dataOutputEma, calculatedLength, period)

    while (ptr < dataInput.length) {
        dataOutput[ptr] = dataInputLow[ptr] - dataOutputEma[ptr]
        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.LOW,
    index: 1
}],
[{
    name: "bears",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "steelblue"
},{
    name: "ema",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Bulls Power

registerIndicator("bulls", "Bulls Power(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataOutput = getDataOutput(context, "bulls")
    var dataOutputEma = getDataOutput(context, "ema")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
        }
    }

    ema(dataInput, dataOutputEma, calculatedLength, period)

    while (ptr < dataInput.length) {
        dataOutput[ptr] = dataInputHigh[ptr] - dataOutputEma[ptr]
        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
}],
[{
    name: "bulls",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "steelblue"
},{
    name: "ema",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Momentum

registerIndicator("momentum", "Momentum(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "momentum")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
        }
    }

    while (ptr < dataInput.length) {
        dataOutput[ptr] = dataInput[ptr] * 100 / dataInput[ptr - period]
        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
}],
[{
    name: "momentum",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Commodity Channel Index

registerIndicator("cci", "Commodity Channel Index(v1.0)", function (context) {
    var dataInput = getDataInput(context, 0)
    var dataOutput = getDataOutput(context, "cci")
    var dataOutputHL = getDataOutput(context, "cciHighLevel")
    var dataOutputLL = getDataOutput(context, "cciLowLevel")
    var dataOutputSma = getDataOutput(context, "sma")
    var highLevel = getIndiParameter(context, "highLevel")
    var lowLevel = getIndiParameter(context, "lowLevel")
    var period = getIndiParameter(context, "period")
    var cciFactor = 0.015 / period;

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
            dataOutputHL[i] = highLevel
            dataOutputLL[i] = lowLevel
        }
    }

    sma(dataInput, dataOutputSma, calculatedLength, period)

    var sum, tmp, ptr2

    while (ptr < dataInput.length) {
        sum = 0
        ptr2 = ptr - period + 1
        while (ptr2 <= ptr) {
            sum += Math.abs(dataInput[ptr2] - dataOutputSma[ptr])
            ptr2++
        }
        tmp = sum * cciFactor

        if (0 == tmp) {
            dataOutput[ptr] = 0
        } else {
            dataOutput[ptr] = (dataInput[ptr] - dataOutputSma[ptr]) / tmp
        }

        dataOutputHL[ptr] = highLevel
        dataOutputLL[ptr] = lowLevel

        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "highLevel",
    value: 100,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [1, 200]
},{
    name: "lowLevel",
    value: -100,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [-200, -1]
}],
[{
    name: DATA_NAME.HLC3,
    index: 0
}],
[{
    name: "cci",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "cciHighLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "cciLowLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "sma",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

DeMarker

registerIndicator("demarker", "DeMarker(v1.0)", function (context) {
    var dataInputHigh = getDataInput(context, 0)
    var dataInputLow = getDataInput(context, 1)
    var dataOutput = getDataOutput(context, "demarker")
    var dataOutputHL = getDataOutput(context, "highLevel")
    var dataOutputLL = getDataOutput(context, "lowLevel")
    var dataOutputMax = getDataOutput(context, "max")
    var dataOutputMin = getDataOutput(context, "min")
    var dataOutputMaMax = getDataOutput(context, "maMax")
    var dataOutputMaMin = getDataOutput(context, "maMin")
    var highLevel = getIndiParameter(context, "highLevel")
    var lowLevel = getIndiParameter(context, "lowLevel")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = 1

        dataOutputMax[0] = 0;
        dataOutputMin[0] = 0;
    }

    var tmp = 0

    while (ptr < dataInputHigh.length) {
        tmp = dataInputHigh[ptr] - dataInputHigh[ptr - 1]
        if (0 > tmp) {
            tmp = 0
        }
        dataOutputMax[ptr] = tmp

        tmp = dataInputLow[ptr - 1] - dataInputLow[ptr]
        if (0 > tmp) {
            tmp = 0
        }
        dataOutputMin[ptr] = tmp

        ptr++
    }

    sma(dataOutputMax, dataOutputMaMax, calculatedLength, period)
    sma(dataOutputMin, dataOutputMaMin, calculatedLength, period)

    ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
            dataOutputHL[i] = highLevel
            dataOutputLL[i] = lowLevel
        }
    }

    while (ptr < dataInputHigh.length) {
        tmp = dataOutputMaMax[ptr] + dataOutputMaMin[ptr]

        if (0 == tmp) {
            dataOutput[ptr] = 0
        } else {
            dataOutput[ptr] = dataOutputMaMax[ptr] / tmp
        }

        dataOutputHL[ptr] = highLevel
        dataOutputLL[ptr] = lowLevel

        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "highLevel",
    value: 0.7,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [0, 1]
},{
    name: "lowLevel",
    value: 0.3,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [0, 1]
}],
[{
    name: DATA_NAME.HIGH,
    index: 0
},{
    name: DATA_NAME.LOW,
    index: 1
}],
[{
    name: "demarker",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "highLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "lowLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "max",
    visible: false
},{
    name: "min",
    visible: false
},{
    name: "maMax",
    visible: false
},{
    name: "maMin",
    visible: false
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Williams’ Percent Range

registerIndicator("wpr", "Williams' Percent Range(v1.0)", function (context) {
    var dataInputClose = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataInputLow = getDataInput(context, 2)
    var dataOutput = getDataOutput(context, "wpr")
    var dataOutputHL = getDataOutput(context, "wprHighLevel")
    var dataOutputLL = getDataOutput(context, "wprLowLevel")
    var highLevel = getIndiParameter(context, "highLevel")
    var lowLevel = getIndiParameter(context, "lowLevel")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period - 1

        for (var i = 0; i < period - 1; i++) {
            dataOutput[i] = 0
            dataOutputHL[i] = highLevel
            dataOutputLL[i] = lowLevel
        }
    }

    while (ptr < dataInputClose.length) {
        var maxArr = []

        for (var i = 0; i < period; i++) {
            maxArr.push(dataInputHigh[ptr - i])
        }

        var highest = Math.max.apply(null, maxArr)

        var minArr = []
        for (var i = 0; i < period; i++) {
            minArr.push(dataInputLow[ptr - i])
        }

        var lowest = Math.min.apply(null, minArr)

        if (0 == highest - lowest) {
            dataOutput[ptr] = 0
        } else {
            dataOutput[ptr] = -100 * (highest - dataInputClose[ptr]) / (highest - lowest)
        }

        dataOutputHL[ptr] = highLevel
        dataOutputLL[ptr] = lowLevel

        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
},{
    name: "highLevel",
    value: -20,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [-100, 0]
},{
    name: "lowLevel",
    value: -80,
    required: false,
    type: PARAMETER_TYPE.NUMBER,
    range: [-100, 0]
}],
[{
    name: DATA_NAME.CLOSE,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
},{
    name: DATA_NAME.LOW,
    index: 2
}],
[{
    name: "wpr",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "steelblue"
},{
    name: "wprHighLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
},{
    name: "wprLowLevel",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#AAAAAA"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Relative Vigor Index

registerIndicator("rvi", "Relative Vigor Index(v1.0)", function (context) {
    var dataInputOpen = getDataInput(context, 0)
    var dataInputHigh = getDataInput(context, 1)
    var dataInputLow = getDataInput(context, 2)
    var dataInputClose = getDataInput(context, 3)
    var dataOutputMain = getDataOutput(context, "main")
    var dataOutputSignal = getDataOutput(context, "signal")
    var period = getIndiParameter(context, "period")

    var calculatedLength = getCalculatedLength(context)

    var ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period + 2

        for (var i = 0; i < period + 2; i++) {
            dataOutputMain[i] = 0
            dataOutputSignal[i] = 0
        }
    }

    var upTmp, downTmp, tmp, dTmp

    while (ptr < dataInputOpen.length) {
        tmp = 0
        dTmp = 0

        for (var i = ptr; i > ptr - period; i--) {
            upTmp = ((dataInputClose[i] - dataInputOpen[i]) + 2 * (dataInputClose[i - 1] - dataInputOpen[i - 1]) + 2 * (dataInputClose[i - 2] - dataInputOpen[i - 2]) + (dataInputClose[i - 3] - dataInputOpen[i - 3])) / 6
            downTmp = ((dataInputHigh[i] - dataInputLow[i]) + 2 * (dataInputHigh[i - 1] - dataInputLow[i - 1]) + 2 * (dataInputHigh[i - 2] - dataInputLow[i - 2]) + (dataInputHigh[i - 3] - dataInputLow[i - 3])) / 6

            tmp += upTmp
            dTmp += downTmp
        }

        if (0 == dTmp) {
            dataOutputMain[ptr] = tmp
        } else {
            dataOutputMain[ptr] = tmp / dTmp
        }

        ptr++
    }

    ptr = calculatedLength

    if (ptr > 0) {
        ptr--
    } else {
        ptr = period + 2
    }

    while (ptr < dataInputOpen.length) {
        dataOutputSignal[ptr] = (dataOutputMain[ptr] + 2 * dataOutputMain[ptr - 1] + 2 * dataOutputMain[ptr - 2] + dataOutputMain[ptr - 3]) / 6

        ptr++
    }
},[{
    name: "period",
    value: 14,
    required: true,
    type: PARAMETER_TYPE.INTEGER,
    range: [1, 100]
}],
[{
    name: DATA_NAME.OPEN,
    index: 0
},{
    name: DATA_NAME.HIGH,
    index: 1
},{
    name: DATA_NAME.LOW,
    index: 2
},{
    name: DATA_NAME.CLOSE,
    index: 3
}],
[{
    name: "main",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#6CBA81"
},{
    name: "signal",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#ECAE93"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

EA Example

A test EA based on SMA

registerEA(
"sample_using_sma",
"A test EA based on sma",
[{ // parameters
	name: "period",
	value: 20,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
}],
function (context) { // Init()
	var account = getAccount(context, 0)
	var brokerName = getBrokerNameOfAccount(account)
	var accountId = getAccountIdOfAccount(account)
	var symbolName = "EUR/USD"

	getQuotes (context, brokerName, accountId, symbolName)
	window.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1)
	var period = getEAParameter(context, "period")
	window.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "sma", [{
		name: "period",
		value: period
	}])
},
function (context) { // Deinit()
	delete window.currTime
},
function (context) { // OnTick()
	var arrTime = getData(context, window.chartHandle, DATA_NAME.TIME)
	if (typeof window.currTime == "undefined") {
		window.currTime = arrTime[arrTime.length - 1]
	} else if (window.currTime != arrTime[arrTime.length - 1]) {
		window.currTime = arrTime[arrTime.length - 1]
	} else {
		return
	}

	var account = getAccount(context, 0)
	var brokerName = getBrokerNameOfAccount(account)
	var accountId = getAccountIdOfAccount(account)
	var symbolName = "EUR/USD"

	var arrClose = getData(context, window.chartHandle, DATA_NAME.CLOSE)
	var arrSma = getData(context, window.indiHandle, "sma")

	var ask = getAsk(context, brokerName, accountId, symbolName)
	var bid = getBid(context, brokerName, accountId, symbolName)
	var limitPrice = 0.0003
	var stopPrice = 0.0003
	var volume = 0.01

	if (arrClose[arrClose.length - 3] < arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] > arrSma[arrSma.length - 2]) {
		sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUYLIMIT, ask-limitPrice, 0, volume, ask+limitPrice, bid-3*stopPrice, "")
	} else if (arrClose[arrClose.length - 3] > arrSma[arrSma.length - 3] && arrClose[arrClose.length - 2] < arrSma[arrSma.length - 2]) {
		sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELLLIMIT, bid+limitPrice, 0, volume, bid-limitPrice, ask+3*stopPrice, "")
	}
})

Trading Arbitrage

registerEA(
"sample_trading_arbitrage",
"Two accounts signed up on the different servers are required to trade arbitrage. Additionally please make sure that you have signed in to both accounts and logged out from the accounts in investor mode.",
[],// parameters
function (context) { // Init()
	var account1 = getAccount(context, 0)
	var account2 = getAccount(context, 1)

	var acc1 = {
		brokerName: getBrokerNameOfAccount(account1),
		accountId: getAccountIdOfAccount(account1),
		symbolName: "EUR/USD"
	}
	var acc2 = {
		brokerName: getBrokerNameOfAccount(account2),
		accountId: getAccountIdOfAccount(account2),
		symbolName: "EUR/USD"
	}

	getQuotes (context, acc1.brokerName, acc1.accountId, acc1.symbolName)
	getQuotes (context, acc2.brokerName, acc2.accountId, acc2.symbolName)

	window.acc1 = acc1
	window.acc2 = acc2
},
function (context) { // Deinit()
	delete window.currTime
},
function (context) { // OnTick()
	var currTime = new Date().getTime()
	if (typeof window.currTime == "undefined") {
		window.currTime = currTime
	} else if (window.currTime <= currTime - 1000) {
		window.currTime = currTime
	} else {
		return
	}

	var acc1 = window.acc1
	var acc2 = window.acc2

	var ask1 = getAsk(context, acc1.brokerName, acc1.accountId, acc1.symbolName)
	var ask2 = getAsk(context, acc2.brokerName, acc2.accountId, acc2.symbolName)
	var bid1 = getBid(context, acc1.brokerName, acc1.accountId, acc1.symbolName)
	var bid2 = getBid(context, acc2.brokerName, acc2.accountId, acc2.symbolName)

	var volume = 0.01

	if (ask1 < bid2) {
		var tradeNum = getOpenTradesListLength(context)

		var acc1TradeId = null
		var acc2TradeId = null

		for (var i = tradeNum - 1; i >= 0; i--) {
			var trade = getOpenTrade(context, i)
			var brokerName = getBrokerName(trade)
			var accountId = getAccountId(trade)
			var tradeId = getTradeId(trade)
			var orderType = getOrderType(trade)
			if (brokerName == acc1.brokerName && accountId == acc1.accountId && orderType == ORDER_TYPE.OP_SELL) {
				acc1TradeId = tradeId
			}
			if (brokerName == acc2.brokerName && accountId == acc2.accountId && orderType == ORDER_TYPE.OP_BUY) {
				acc2TradeId = tradeId
			}
		}

		if (acc1TradeId == null) {
			sendOrder(acc1.brokerName, acc1.accountId, acc1.symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "")
		} else {
			closeTrade(acc1.brokerName, acc1.accountId, acc1TradeId)
		}

		if (acc2TradeId == null) {
			sendOrder(acc2.brokerName, acc2.accountId, acc2.symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "")
		} else {
			closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId)
		}
	} else if (ask2 < bid1) {
		var tradeNum = getOpenTradesListLength(context)

		var acc1TradeId = null
		var acc2TradeId = null

		for (var i = tradeNum - 1; i >= 0; i--) {
			var trade = getOpenTrade(context, i)
			var brokerName = getBrokerName(trade)
			var accountId = getAccountId(trade)
			var tradeId = getTradeId(trade)
			var orderType = getOrderType(trade)
			if (brokerName == acc2.brokerName && accountId == acc2.accountId && orderType == ORDER_TYPE.OP_SELL) {
				acc2TradeId = tradeId
			}
			if (brokerName == acc1.brokerName && accountId == acc1.accountId && orderType == ORDER_TYPE.OP_BUY) {
				acc1TradeId = tradeId
			}
		}

		if (acc2TradeId == null) {
			sendOrder(acc2.brokerName, acc2.accountId, acc2.symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, 0, 0, "")
		} else {
			closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId)
		}

		if (acc1TradeId == null) {
			sendOrder(acc1.brokerName, acc1.accountId, acc1.symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "")
		} else {
			closeTrade(acc1.brokerName, acc1.accountId, acc1TradeId)
		}
	}
})

Neural Network

registerEA(
"sample_training_neuron_model",
"A test EA to train neuron model",
[{ // parameters
	name: "period",
	value: 20,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
},{
	name: "inputNum",
	value: 20,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
},{
	name: "hiddenNum",
	value: 50,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
},{
	name: "diffPrice",
	value: 0.0001,
	required: true,
	type: PARAMETER_TYPE.NUMBER,
	range: [0, 10]
}],
function (context) { // Init()
	var account = getAccount(context, 0)
	var brokerName = getBrokerNameOfAccount(account)
	var accountId = getAccountIdOfAccount(account)
	var symbolName = "EUR/USD"

	window.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1)
	var period = getEAParameter(context, "period")
	window.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "rsi", [{
		name: "period",
		value: period
	}])
},
function (context) { // Deinit()
	var period = getEAParameter(context, "period")
	var inputNum = getEAParameter(context, "inputNum")
	var hiddenNum = getEAParameter(context, "hiddenNum")
	var arrOpen = getData(context, window.chartHandle, DATA_NAME.OPEN)
	var arrClose = getData(context, window.chartHandle, DATA_NAME.CLOSE)
	var arrRsi = getData(context, window.indiHandle, "rsi")

	if (arrRsi.length <= period + 1) return
	if (inputNum + period - 1 > arrRsi.length) throw new Error("No enough data.")

	// extend the prototype chain
	Perceptron.prototype = new synaptic.Network()
	Perceptron.prototype.constructor = Perceptron

	var myPerceptron = new Perceptron(inputNum, hiddenNum, 1)
	var myTrainer = new synaptic.Trainer(myPerceptron)

	var diffPrice = getEAParameter(context, "diffPrice")
	var trainingSet = []
	var longCount = 0
	var shortCount = 0

	for (var i = period - 1; i < arrRsi.length - inputNum; i++) {
		if (arrClose[i * inputNum + inputNum] - arrOpen[i * inputNum + inputNum] > diffPrice) {
			var input = []

			for (var j = 0; j < inputNum; j++) {
				input.push(arrRsi[i * inputNum + j] / 100)
			}

			trainingSet.push({
				input: input,
				output: [0]
			})

			longCount++
		} else if (arrOpen[i * inputNum + inputNum] - arrClose[i * inputNum + inputNum] > diffPrice) {
			var input = []

			for (var j = 0; j < inputNum; j++) {
				input.push(arrRsi[i * inputNum + j] / 100)
			}

			trainingSet.push({
				input: input,
				output: [1]
			})

			shortCount++
		}
	}

	myTrainer.train(trainingSet)
	localStorage.sample_training_neuron_model = JSON.stringify(myPerceptron.toJSON())
	printMessage(longCount + ", " + shortCount)
	printMessage(JSON.stringify(trainingSet))
	printMessage(JSON.stringify(myPerceptron.toJSON()))
},
function (context) { // OnTick()
})

registerEA(
"sample_run_neuron_model",
"A test EA to run neuron model",
[{ // parameters
	name: "period",
	value: 20,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
},{
	name: "inputNum",
	value: 20,
	required: true,
	type: PARAMETER_TYPE.INTEGER,
	range: [1, 100]
},{
	name: "threshold",
	value: 0.3,
	required: true,
	type: PARAMETER_TYPE.NUMBER,
	range: [0, 1]
},{
	name: "takeProfit",
	value: 0.0001,
	required: true,
	type: PARAMETER_TYPE.NUMBER,
	range: [0, 100]
}],
function (context) { // Init()
	if (typeof localStorage.sample_training_neuron_model == "undefined") return

	window.myPerceptron = synaptic.Network.fromJSON(JSON.parse(localStorage.sample_training_neuron_model))

	var account = getAccount(context, 0)
	var brokerName = getBrokerNameOfAccount(account)
	var accountId = getAccountIdOfAccount(account)
	var symbolName = "EUR/USD"

	getQuotes (context, brokerName, accountId, symbolName)
	window.chartHandle = getChartHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1)
	var period = getEAParameter(context, "period")
	window.indiHandle = getIndicatorHandle(context, brokerName, accountId, symbolName, TIME_FRAME.M1, "rsi", [{
		name: "period",
		value: period
	}])
},
function (context) { // Deinit()
	delete window.currTime
},
function (context) { // OnTick()
	var arrTime = getData(context, window.chartHandle, DATA_NAME.TIME)
	if (typeof window.currTime == "undefined") {
		window.currTime = arrTime[arrTime.length - 1]
	} else if (window.currTime != arrTime[arrTime.length - 1]) {
		window.currTime = arrTime[arrTime.length - 1]
	} else {
		return
	}

	var account = getAccount(context, 0)
	var brokerName = getBrokerNameOfAccount(account)
	var accountId = getAccountIdOfAccount(account)
	var symbolName = "EUR/USD"

	var period = getEAParameter(context, "period")
	var inputNum = getEAParameter(context, "inputNum")
	var threshold = getEAParameter(context, "threshold")
	var takeProfit = getEAParameter(context, "takeProfit")
	var arrRsi = getData(context, window.indiHandle, "rsi")

	if (inputNum + period - 1 > arrRsi.length) throw new Error("No enough data.")

	var input = []

	for (var i = arrRsi.length - inputNum - 1; i < arrRsi.length - 1; i++) {
		input.push(arrRsi[i] / 100)
	}

	var result = window.myPerceptron.activate(input)[0]
	printMessage(result)

	var ask = getAsk(context, brokerName, accountId, symbolName)
	var bid = getBid(context, brokerName, accountId, symbolName)
	var volume = 0.01

	if (result < 0.5 - threshold) {
		sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_BUY, 0, 0, volume, ask+takeProfit, bid-3*takeProfit, "")
	} else if (result > 0.5 + threshold) {
		sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, bid-takeProfit, ask+3*takeProfit, "")
	}
})
We are going IEO
2020-01-10 Bounty News
Brokerless.CC
Sponsored by Fintech Angel Investors Network