Documents

Fintechee's SDK Integrated with the Frontend

API ( Fintechee Trading SDK )

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", 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", 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", 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", 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", 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: "fastEMA",
	visible: false
},{
	name: "slowEMA",
	visible: false
},{
    name: "main",
    visible: true,
    renderType: RENDER_TYPE.HISTOGRAM,
    color: "#4EC2B4"
},{
    name: "signal",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#CCCCCC"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Relative strength index

registerIndicator("rsi", "Relative strength index", function (context) {
		var dataInput = getDataInput(context, 0)
		var dataOutput = getDataOutput(context, "rsi")
		var gainTmp = getDataOutput(context, "gainTmp")
		var lossTmp = getDataOutput(context, "lossTmp")

		var period = getIndiParameter(context, "period")

		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
			}

			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)
			}
			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)
			}
			gainTmp[ptr] = gain
			lossTmp[ptr] = loss
			ptr++
		}
	},
[{
	name: "period",
	value: 14,
	required: true,
	type: "Integer",
	range: [1, 100]
}], [{
	name: "Close",
	index: 0
}], [{
	name: "rsi",
	visible: true,
	renderType: "Line",
	color: "steelblue"
}, {
	name: "gainTmp",
	visible: false,
	renderType: null,
	color: null
}, {
	name: "lossTmp",
	visible: false,
	renderType: null,
	color: null
}],
"SEPARATE_WINDOW")

Average true range

registerIndicator("atr", "Average true range", 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", 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: "tmp",
    visible: false
},{
    name: "plusSdiTmp",
    visible: false
},{
    name: "minusSdiTmp",
    visible: false
},{
    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"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Parabolic SAR

registerIndicator("sar", "Parabolic SAR", 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", 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 - 1; i++) {
			dataOutputMain[ptr - i] = 0
			highestTmp[ptr - i] = 0
			lowestTmp[ptr - i] = 0
		}
	}

	while (ptr < dataInputClose.length) {
		var tmp = null
		var highest = Number.MIN_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: "highestTmp",
    visible: false
},{
    name: "lowestTmp",
    visible: false
},{
    name: "main",
    visible: true,
    renderType: RENDER_TYPE.LINE,
    color: "#DE5029"
},{
    name: "signal",
    visible: true,
    renderType: RENDER_TYPE.DASHARRAY,
    color: "#4EC2B4"
}],
WHERE_TO_RENDER.SEPARATE_WINDOW)

Alligator

registerIndicator("alligator", "A series of Bill Williams' indicators", 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)

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, "")
	}
})