SDK Trading ~

WEB Trader Get it on Google Play
  • Post by Fintechee
  • Jan 18, 2020
Algorithmic Trading System Architecture is based on SDK trading and API Trading. Fintechee provides Algorithms for Trading

SDK Trading

Algorithmic Trading System Architecture is based on SDK trading and API Trading. 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: "Fintechee 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 isNumeric (number) {
	if (typeof number == "undefined" || number == null) return false

	return !isNaN(parseFloat(number)) && isFinite(number);
}

function isInteger (number) {
	return !isNaN(number) &&
		parseInt(Number(number)) == number &&
		!isNaN(parseInt(number, 10))
}

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.01)", 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, "fastEMA")
  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: "fastEMA",
  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.01)", function (context) {
  var dataInputHigh = getDataInput(context, 0)
  var dataInputLow = getDataInput(context, 1)

  var dataOutput = getDataOutput(context, "sar")
  var dataOutputIsLong = getDataOutput(context, "isLong")
  var dataOutputAf = getDataOutput(context, "af")
  var dataOutputEp = getDataOutput(context, "ep")

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

  var calculatedLength = getCalculatedLength(context)
  var i = calculatedLength

  var prevH = null
  var prevL = null
  var currH = null
  var currL = null
  var sar = null
  var isLong = null
  var af = acceleration
  var ep = null

  if (i > 0) {
    i -= 2
    prevH = dataInputHigh[i - 1]
    prevL = dataInputLow[i - 1]
    isLong = dataOutputIsLong[i]
    sar = dataOutput[i]
    af = dataOutputAf[i]
    ep = dataOutputEp[i]
  } else {
    dataOutput[i] = 0
    dataOutputIsLong[i] = true
    dataOutputAf[i] = af
    dataOutputEp[i] = 0

    i = 1

    prevH = dataInputHigh[i - 1]
    prevL = dataInputLow[i - 1]
    isLong = true
    sar = prevL
    ep = prevH
  }

  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
          if (af - dataOutputAf[i - 1] <= 0) {
            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
          if (af - dataOutputAf[i - 1] <= 0) {
            af += acceleration
          }
          if (af > afMax) {
            af = afMax
          }
        }
        sar = sar + af * (ep - sar)
        sar = Math.max(sar, currH, prevH)
      }
    }

    dataOutputIsLong[i] = isLong
    dataOutputAf[i] = af
    dataOutputEp[i] = ep

    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"
},{
  name: "isLong",
  visible: false
},{
  name: "af",
  visible: false
},{
  name: "ep",
  visible: false
}],
WHERE_TO_RENDER.CHART_WINDOW)

Stochastic Oscillator

registerIndicator("stochastic", "Stochastic Ocillator(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.01)", 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: [-30, 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: [-30, 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: [-30, 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(v1.02)",
  [{ // 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
    delete window.chartHandle
    delete window.indiHandle
  },
  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, "", 0, 0)
    } 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, "", 0, 0)
    }
  }
)

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.(v1.02)",
  [],// 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
    delete window.acc1
    delete window.acc2
  },
  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, "", 0, 0)
      } else {
        closeTrade(acc1.brokerName, acc1.accountId, acc1TradeId, 0, 0)
      }

      if (acc2TradeId == null) {
        sendOrder(acc2.brokerName, acc2.accountId, acc2.symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, 0, 0, "", 0, 0)
      } else {
        closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId, 0, 0)
      }
    } 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, "", 0, 0)
      } else {
        closeTrade(acc2.brokerName, acc2.accountId, acc2TradeId, 0, 0)
      }

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

Neural Network

registerEA(
  "sample_training_neuron_model",
  "A test EA to train neuron model(v1.02)",
  [{ // 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)

    // We use localstorage.reservedZone to store the neural network network.
    // Please don't change the name "reservedZone" or your data stored in this zone will be removed while the version is updated.
    if (typeof localStorage.reservedZone == "undefined") {
      localStorage.reservedZone = JSON.stringify({sample_training_neuron_model: myPerceptron.toJSON()})
    } else {
      var reservedZone = JSON.parse(localStorage.reservedZone)
      reservedZone.sample_training_neuron_model = myPerceptron.toJSON()
      localStorage.reservedZone = JSON.stringify(reservedZone)
    }

    printMessage(longCount + ", " + shortCount)
    printMessage(JSON.stringify(trainingSet))
    printMessage(JSON.stringify(myPerceptron.toJSON()))

    delete window.chartHandle
    delete window.indiHandle
  },
  function (context) { // OnTick()
  }
)

registerEA(
  "sample_run_neuron_model",
  "A test EA to run neuron model(v1.03)",
  [{ // 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()
    // We use localstorage.reservedZone to store the neural network network.
    // Please don't change the name "reservedZone" or your data stored in this zone will be removed while the version is updated.
    if (typeof localStorage.reservedZone == "undefined") return

    var reservedZone = JSON.parse(localStorage.reservedZone)
    if (typeof reservedZone.sample_training_neuron_model == "undefined") return
    window.myPerceptron = synaptic.Network.fromJSON(reservedZone.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
    delete window.chartHandle
    delete window.indiHandle
    delete window.myPerceptron
  },
  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, "", 0, 0)
    } else if (result > 0.5 + threshold) {
      sendOrder(brokerName, accountId, symbolName, ORDER_TYPE.OP_SELL, 0, 0, volume, bid-takeProfit, ask+3*takeProfit, "", 0, 0)
    }
  }
)