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



