-- Id: 15643
-- More information about this indicator can be found at:
-- http://fxcodebase.com/code/viewtopic.php?f=31&t=63248

--+------------------------------------------------------------------+
--|                               Copyright © 2018, Gehtsoft USA LLC |
--|                                            http://fxcodebase.com |
--+------------------------------------------------------------------+
--|                                      Developed by : Mario Jemic  |
--|                                          mario.jemic@gmail.com   |
--+------------------------------------------------------------------+
--|                                 Support our efforts by donating  |
--|                                    Paypal: https://goo.gl/9Rj74e |
--+------------------------------------------------------------------+
--|                                Patreon :  https://goo.gl/GdXWeN  |
--|                    BitCoin : 15VCJTLaz12Amr7adHSBtL9v8XomURo9RF  |
--|                BitCoin Cash: 1BEtS465S3Su438Kc58h2sqvVvHK9Mijtg  |
--|           Ethereum : 0x8C110cD61538fb6d7A2B47858F0c0AaBd663068D  |
--|                   LiteCoin : LLU8PSY2vsq7B9kRELLZQcKf5nJQrdeqwD  |
--+------------------------------------------------------------------+

function Init() --The strategy profile initialization
    strategy:name("FX Prime Strategy")
    strategy:description("")
    strategy:setTag("Version", "2");
    strategy:setTag("NonOptimizableParameters", "Email,SendEmail,SoundFile,RecurrentSound,PlaySound, ShowAlert")

    strategy.parameters:addGroup("Price")
    strategy.parameters:addString("Type", "Price Type", "", "Bid")
    strategy.parameters:addStringAlternative("Type", "Bid", "", "Bid")
    strategy.parameters:addStringAlternative("Type", "Ask", "", "Ask")

    strategy.parameters:addGroup("1. Time Frame Calculation")

    strategy.parameters:addString("TF1", "Time frame", "", "H1")
    strategy.parameters:setFlag("TF1", core.FLAG_PERIODS)

    strategy.parameters:addDouble("AngleTreshold1", "AngleTreshold", "", 0.2)
    strategy.parameters:addInteger("RSI_Period1", "RSI_Period", "", 8)

    strategy.parameters:addString("RSI_Price1", "Price for RSI", "", "close")
    strategy.parameters:addStringAlternative("RSI_Price1", "open", "", "open")
    strategy.parameters:addStringAlternative("RSI_Price1", "open", "", "close")
    strategy.parameters:addStringAlternative("RSI_Price1", "high", "", "high")
    strategy.parameters:addStringAlternative("RSI_Price1", "low", "", "low")

    strategy.parameters:addString("chk_rsi1", "chk_rsi", "", "false")
    strategy.parameters:addStringAlternative("chk_rsi1", "true", "", "true")
    strategy.parameters:addStringAlternative("chk_rsi1", "false", "", "false")

    strategy.parameters:addString("check_ema_angle1", "check_ema_angle", "", "true")
    strategy.parameters:addStringAlternative("check_ema_angle1", "true", "", "true")
    strategy.parameters:addStringAlternative("check_ema_angle1", "false", "", "false")

    strategy.parameters:addString("display_fxprime_short1", "display_fxprime_short", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_short1", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_short1", "false", "", "false")

    strategy.parameters:addString("display_fxprime_long1", "display_fxprime_long", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_long1", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_long1", "false", "", "false")

    strategy.parameters:addString("display_fxprime_exit1", "display_fxprime_exit", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_exit1", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_exit1", "false", "", "false")

    strategy.parameters:addInteger("indicator_period1", "indicator_period", "", 0)
    strategy.parameters:addInteger("previous_shift1", "previous_shift", "", 1)
    strategy.parameters:addInteger("cci_period1", "cci_period", "", 50)
    strategy.parameters:addInteger("long_period1", "long_period", "", 170)
    strategy.parameters:addInteger("short_rsi1", "short_rsi", "", 8)
    strategy.parameters:addInteger("long_rsi1", "long_rsi", "", 14)
    strategy.parameters:addInteger("filter_out_cci1", "filter_out_cci", "", 5)
    strategy.parameters:addDouble("filter_out_long1", "filter_out_long", "", 165)
    strategy.parameters:addDouble("filter_out_short1", "filter_out_short", "", -165)

    strategy.parameters:addDouble("exit_cci_cross_long1", "exit_cci_cross_long", "", 0)
    strategy.parameters:addDouble("exit_cci_cross_short1", "exit_cci_cross_short", "", 0)
    strategy.parameters:addDouble("long_rsi_cross1", "long_rsi_cross", "", 55)
    strategy.parameters:addDouble("short_rsi_cross1", "short_rsi_cross", "", 45)

    strategy.parameters:addDouble("small_long_cci_cross1", "small_long_cci_cross", "", 30)
    strategy.parameters:addDouble("small_short_cci_cross1", "small_short_cci_cross", "", -30)
    strategy.parameters:addDouble("large_long_cci_cross1", "large_long_cci_cross", "", 25)
    strategy.parameters:addDouble("large_short_cci_cross1", "large_short_cci_cross", "", -25)

    strategy.parameters:addInteger("sto_K1", "sto_K", "", 5)
    strategy.parameters:addInteger("sto_D1", "sto_D", "", 3)
    strategy.parameters:addInteger("sto_S1", "sto_S", "", 3)
    strategy.parameters:addInteger("adx_period1", "adx_period", "", 20)
    strategy.parameters:addDouble("adx_level1", "adx_level", "", 15)

    strategy.parameters:addString("chk_adx1", "chk_adx", "", "false")
    strategy.parameters:addStringAlternative("chk_adx1", "true", "", "true")
    strategy.parameters:addStringAlternative("chk_adx1", "false", "", "false")

    strategy.parameters:addString("CCI_Price1", "Price for CCI", "", "typical")
    strategy.parameters:addStringAlternative("CCI_Price1", "open", "", "open")
    strategy.parameters:addStringAlternative("CCI_Price1", "open", "", "close")
    strategy.parameters:addStringAlternative("CCI_Price1", "high", "", "high")
    strategy.parameters:addStringAlternative("CCI_Price1", "low", "", "low")
    strategy.parameters:addStringAlternative("CCI_Price1", "low", "", "typical")

    strategy.parameters:addInteger("ea_EMAPeriod1", "ea_EMAPeriod", "", 34)
    strategy.parameters:addDouble("ea_AngleTreshold1", "ea_AngleTreshold", "", 0.2)
    strategy.parameters:addInteger("ea_StartEMAShift1", "ea_StartEMAShift", "", 6)
    strategy.parameters:addInteger("ea_EndEMAShift1", "ea_EndEMAShift", "", 0)

    strategy.parameters:addString("display_ema_angle1", "display_ema_angle", "", "false")
    strategy.parameters:addStringAlternative("display_ema_angle1", "true", "", "true")
    strategy.parameters:addStringAlternative("display_ema_angle1", "false", "", "false")

    strategy.parameters:addInteger("EMAPeriod1", "EMAPeriod", "", 34)
    strategy.parameters:addInteger("StartEMAShift1", "StartEMAShift", "", 6)
    strategy.parameters:addInteger("EndEMAShift1", "EndEMAShift", "", 0)

    strategy.parameters:addGroup("2. Time Frame Calculation")

    strategy.parameters:addString("TF2", "Time frame", "", "H4")
    strategy.parameters:setFlag("TF2", core.FLAG_PERIODS)

    strategy.parameters:addDouble("AngleTreshold2", "AngleTreshold", "", 0.2)
    strategy.parameters:addInteger("RSI_Period2", "RSI_Period", "", 8)

    strategy.parameters:addString("RSI_Price2", "Price for RSI", "", "close")
    strategy.parameters:addStringAlternative("RSI_Price2", "open", "", "open")
    strategy.parameters:addStringAlternative("RSI_Price2", "open", "", "close")
    strategy.parameters:addStringAlternative("RSI_Price2", "high", "", "high")
    strategy.parameters:addStringAlternative("RSI_Price2", "low", "", "low")

    strategy.parameters:addString("chk_rsi2", "chk_rsi", "", "false")
    strategy.parameters:addStringAlternative("chk_rsi2", "true", "", "true")
    strategy.parameters:addStringAlternative("chk_rsi2", "false", "", "false")

    strategy.parameters:addString("check_ema_angle2", "check_ema_angle", "", "true")
    strategy.parameters:addStringAlternative("check_ema_angle2", "true", "", "true")
    strategy.parameters:addStringAlternative("check_ema_angle2", "false", "", "false")

    strategy.parameters:addString("display_fxprime_short2", "display_fxprime_short", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_short2", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_short2", "false", "", "false")

    strategy.parameters:addString("display_fxprime_long2", "display_fxprime_long", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_long2", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_long2", "false", "", "false")

    strategy.parameters:addString("display_fxprime_exit2", "display_fxprime_exit", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_exit2", "true", "", "true")
    strategy.parameters:addStringAlternative("display_fxprime_exit2", "false", "", "false")

    strategy.parameters:addInteger("indicator_period2", "indicator_period", "", 0)
    strategy.parameters:addInteger("previous_shift2", "previous_shift", "", 1)
    strategy.parameters:addInteger("cci_period2", "cci_period", "", 50)
    strategy.parameters:addInteger("long_period2", "long_period", "", 170)
    strategy.parameters:addInteger("short_rsi2", "short_rsi", "", 8)
    strategy.parameters:addInteger("long_rsi2", "long_rsi", "", 14)
    strategy.parameters:addInteger("filter_out_cci2", "filter_out_cci", "", 5)
    strategy.parameters:addDouble("filter_out_long2", "filter_out_long", "", 165)
    strategy.parameters:addDouble("filter_out_short2", "filter_out_short", "", -165)

    strategy.parameters:addDouble("exit_cci_cross_long2", "exit_cci_cross_long", "", 0)
    strategy.parameters:addDouble("exit_cci_cross_short2", "exit_cci_cross_short", "", 0)
    strategy.parameters:addDouble("long_rsi_cross2", "long_rsi_cross", "", 55)
    strategy.parameters:addDouble("short_rsi_cross2", "short_rsi_cross", "", 45)

    strategy.parameters:addDouble("small_long_cci_cross2", "small_long_cci_cross", "", 30)
    strategy.parameters:addDouble("small_short_cci_cross2", "small_short_cci_cross", "", -30)
    strategy.parameters:addDouble("large_long_cci_cross2", "large_long_cci_cross", "", 25)
    strategy.parameters:addDouble("large_short_cci_cross2", "large_short_cci_cross", "", -25)

    strategy.parameters:addInteger("sto_K2", "sto_K", "", 5)
    strategy.parameters:addInteger("sto_D2", "sto_D", "", 3)
    strategy.parameters:addInteger("sto_S2", "sto_S", "", 3)
    strategy.parameters:addInteger("adx_period2", "adx_period", "", 20)
    strategy.parameters:addDouble("adx_level2", "adx_level", "", 15)

    strategy.parameters:addString("chk_adx2", "chk_adx2", "", "false")
    strategy.parameters:addStringAlternative("chk_adx2", "true", "", "true")
    strategy.parameters:addStringAlternative("chk_adx2", "false", "", "false")

    strategy.parameters:addString("CCI_Price2", "Price for CCI", "", "typical")
    strategy.parameters:addStringAlternative("CCI_Price2", "open", "", "open")
    strategy.parameters:addStringAlternative("CCI_Price2", "open", "", "close")
    strategy.parameters:addStringAlternative("CCI_Price2", "high", "", "high")
    strategy.parameters:addStringAlternative("CCI_Price2", "low", "", "low")
    strategy.parameters:addStringAlternative("CCI_Price2", "low", "", "typical")

    strategy.parameters:addInteger("ea_EMAPeriod2", "ea_EMAPeriod", "", 34)
    strategy.parameters:addDouble("ea_AngleTreshold2", "ea_AngleTreshold", "", 0.2)
    strategy.parameters:addInteger("ea_StartEMAShift2", "ea_StartEMAShift", "", 6)
    strategy.parameters:addInteger("ea_EndEMAShift2", "ea_EndEMAShift", "", 0)

    strategy.parameters:addString("display_ema_angle2", "display_ema_angle", "", "false")
    strategy.parameters:addStringAlternative("display_ema_angle2", "true", "", "true")
    strategy.parameters:addStringAlternative("display_ema_angle2", "false", "", "false")

    strategy.parameters:addInteger("EMAPeriod2", "EMAPeriod", "", 34)
    strategy.parameters:addInteger("StartEMAShift2", "StartEMAShift", "", 6)
    strategy.parameters:addInteger("EndEMAShift2", "EndEMAShift", "", 0)

    CreateTradingParameters()
end

function CreateTradingParameters()
    strategy.parameters:addGroup("Trading Parameters")

    strategy.parameters:addBoolean("AllowTrade", "Allow strategy to trade", "", false)
    strategy.parameters:setFlag("AllowTrade", core.FLAG_ALLOW_TRADE)

    strategy.parameters:addString("ExecutionType", "End of Turn / Live", "", "End of Turn")
    strategy.parameters:addStringAlternative("ExecutionType", "End of Turn", "", "End of Turn")
    strategy.parameters:addStringAlternative("ExecutionType", "Live", "", "Live")

    strategy.parameters:addBoolean("CloseOnOpposite", "Close On Opposite", "", true)
    strategy.parameters:addString(
        "CustomID",
        "Custom Identifier",
        "The identifier that can be used to distinguish strategy instances",
        "MTFTMA"
    )

    strategy.parameters:addInteger(
        "MaxNumberOfPositionInAnyDirection",
        "Max Number Of Open Position In Any Direction",
        "",
        2,
        1,
        100
    )
    strategy.parameters:addInteger("MaxNumberOfPosition", "Max Number Of Position In One Direction", "", 1, 1, 100)

    strategy.parameters:addString(
        "ALLOWEDSIDE",
        "Allowed side",
        "Allowed side for trading or signaling, can be Sell, Buy or Both",
        "Both"
    )
    strategy.parameters:addStringAlternative("ALLOWEDSIDE", "Both", "", "Both")
    strategy.parameters:addStringAlternative("ALLOWEDSIDE", "Buy", "", "Buy")
    strategy.parameters:addStringAlternative("ALLOWEDSIDE", "Sell", "", "Sell")

    strategy.parameters:addString("Direction", "Type of Signal / Trade", "", "direct")
    strategy.parameters:addStringAlternative("Direction", "Direct", "", "direct")
    strategy.parameters:addStringAlternative("Direction", "Reverse", "", "reverse")

    strategy.parameters:addString("Account", "Account to trade on", "", "")
    strategy.parameters:setFlag("Account", core.FLAG_ACCOUNT)
    strategy.parameters:addInteger("Amount", "Trade Amount in Lots", "", 1, 1, 1000000);
    strategy.parameters:addBoolean("SetLimit", "Set Limit Orders", "", false)
    strategy.parameters:addInteger("Limit", "Limit Order in pips", "", 30, 1, 10000)
    strategy.parameters:addBoolean("SetStop", "Set Stop Orders", "", false)
    strategy.parameters:addInteger("Stop", "Stop Order in pips", "", 30, 1, 10000)
    strategy.parameters:addBoolean("TrailingStop", "Trailing stop order", "", false)
    -- strategy.parameters:addBoolean("Exit", "Use Optional Exit", "", false);

    strategy.parameters:addGroup("Alerts")
    strategy.parameters:addBoolean("ShowAlert", "ShowAlert", "", true)
    strategy.parameters:addBoolean("PlaySound", "Play Sound", "", false)
    strategy.parameters:addFile("SoundFile", "Sound File", "", "")
    strategy.parameters:setFlag("SoundFile", core.FLAG_SOUND)
    strategy.parameters:addBoolean("RecurrentSound", "Recurrent Sound", "", true)
    strategy.parameters:addBoolean("SendEmail", "Send Email", "", false)
    strategy.parameters:addString("Email", "Email", "", "")
    strategy.parameters:setFlag("Email", core.FLAG_EMAIL)

    strategy.parameters:addGroup("Time Parameters")
    strategy.parameters:addInteger("ToTime", "Convert the date to", "", 6)
    strategy.parameters:addIntegerAlternative("ToTime", "EST", "", 1)
    strategy.parameters:addIntegerAlternative("ToTime", "UTC", "", 2)
    strategy.parameters:addIntegerAlternative("ToTime", "Local", "", 3)
    strategy.parameters:addIntegerAlternative("ToTime", "Server", "", 4)
    strategy.parameters:addIntegerAlternative("ToTime", "Financial", "", 5)
    strategy.parameters:addIntegerAlternative("ToTime", "Display", "", 6)

    strategy.parameters:addString("StartTime", "Start Time for Trading", "", "00:00:00")
    strategy.parameters:addString("StopTime", "Stop Time for Trading", "", "24:00:00")

    strategy.parameters:addBoolean("UseMandatoryClosing", "Use Mandatory Closing", "", false)
    strategy.parameters:addString("ExitTime", "Mandatory Closing  Time", "", "23:59:00")
    strategy.parameters:addInteger("ValidInterval", "Valid interval for operation in second", "", 60)
end

local Source1, Source2, TickSource
local MaxNumberOfPositionInAnyDirection, MaxNumberOfPosition
local SoundFile = nil
local RecurrentSound = false
local ALLOWEDSIDE
local AllowTrade
local Offer
local CanClose
local Account
local Amount
local SetLimit
local Limit
local SetStop
local Stop
local TrailingStop
local ShowAlert
local Email
local SendEmail
local BaseSize
local ExecutionType
local CloseOnOpposite
local first
local Direction
local CustomID

local LongColor
local ShortColor
local ExitColor
local NeutralColor

local Indicator1, Indicator2
local Parameters1 = {}
local Parameters2 = {}

local OpenTime, CloseTime, ExitTime
local ValidInterval, UseMandatoryClosing
local ToTime

function Add1()
    Parameters1[1] = instance.parameters.RSI_Price1
    Parameters1[2] = instance.parameters.chk_rsi1
    Parameters1[3] = instance.parameters.check_ema_angle1
    Parameters1[4] = instance.parameters.display_fxprime_short1
    Parameters1[5] = instance.parameters.display_fxprime_long1
    Parameters1[6] = instance.parameters.display_fxprime_exit1
    Parameters1[7] = instance.parameters.indicator_period1
    Parameters1[8] = instance.parameters.previous_shift1
    Parameters1[9] = instance.parameters.cci_period1
    Parameters1[10] = instance.parameters.long_period1
    Parameters1[11] = instance.parameters.short_rsi1
    Parameters1[12] = instance.parameters.long_rsi1
    Parameters1[13] = instance.parameters.filter_out_cci1
    Parameters1[14] = instance.parameters.filter_out_long1
    Parameters1[15] = instance.parameters.filter_out_short1
    Parameters1[16] = instance.parameters.exit_cci_cross_long1
    Parameters1[17] = instance.parameters.exit_cci_cross_short1
    Parameters1[18] = instance.parameters.long_rsi_cross1
    Parameters1[19] = instance.parameters.short_rsi_cross1
    Parameters1[20] = instance.parameters.small_long_cci_cross1
    Parameters1[21] = instance.parameters.small_short_cci_cross1
    Parameters1[22] = instance.parameters.large_long_cci_cross1
    Parameters1[23] = instance.parameters.large_short_cci_cross1
    Parameters1[24] = instance.parameters.sto_K1
    Parameters1[25] = instance.parameters.sto_D1
    Parameters1[26] = instance.parameters.sto_S1
    Parameters1[27] = instance.parameters.adx_period1
    Parameters1[28] = instance.parameters.adx_level1
    Parameters1[29] = instance.parameters.chk_adx1
    Parameters1[30] = instance.parameters.CCI_Price1
    Parameters1[31] = instance.parameters.ea_EMAPeriod1
    Parameters1[32] = instance.parameters.ea_AngleTreshold1
    Parameters1[33] = instance.parameters.ea_StartEMAShift1
    Parameters1[34] = instance.parameters.ea_EndEMAShift1
    Parameters1[35] = instance.parameters.display_ema_angle1
    Parameters1[36] = instance.parameters.EMAPeriod1
    Parameters1[37] = instance.parameters.StartEMAShift1
    Parameters1[38] = instance.parameters.EndEMAShift1

    Parameters1[39] = instance.parameters.AngleTreshold1
    Parameters1[40] = instance.parameters.RSI_Period1
end

function Add2()
    Parameters2[1] = instance.parameters.RSI_Price2
    Parameters2[2] = instance.parameters.chk_rsi2
    Parameters2[3] = instance.parameters.check_ema_angle2
    Parameters2[4] = instance.parameters.display_fxprime_short2
    Parameters2[5] = instance.parameters.display_fxprime_long2
    Parameters2[6] = instance.parameters.display_fxprime_exit2
    Parameters2[7] = instance.parameters.indicator_period2
    Parameters2[8] = instance.parameters.previous_shift2
    Parameters2[9] = instance.parameters.cci_period2
    Parameters2[10] = instance.parameters.long_period2
    Parameters2[11] = instance.parameters.short_rsi2
    Parameters2[12] = instance.parameters.long_rsi2
    Parameters2[13] = instance.parameters.filter_out_cci2
    Parameters2[14] = instance.parameters.filter_out_long2
    Parameters2[15] = instance.parameters.filter_out_short2
    Parameters2[16] = instance.parameters.exit_cci_cross_long2
    Parameters2[17] = instance.parameters.exit_cci_cross_short2
    Parameters2[18] = instance.parameters.long_rsi_cross2
    Parameters2[19] = instance.parameters.short_rsi_cross2
    Parameters2[20] = instance.parameters.small_long_cci_cross2
    Parameters2[21] = instance.parameters.small_short_cci_cross2
    Parameters2[22] = instance.parameters.large_long_cci_cross2
    Parameters2[23] = instance.parameters.large_short_cci_cross2
    Parameters2[24] = instance.parameters.sto_K2
    Parameters2[25] = instance.parameters.sto_D2
    Parameters2[26] = instance.parameters.sto_S2
    Parameters2[27] = instance.parameters.adx_period2
    Parameters2[28] = instance.parameters.adx_level2
    Parameters2[29] = instance.parameters.chk_adx2
    Parameters2[30] = instance.parameters.CCI_Price2
    Parameters2[31] = instance.parameters.ea_EMAPeriod2
    Parameters2[32] = instance.parameters.ea_AngleTreshold2
    Parameters2[33] = instance.parameters.ea_StartEMAShift2
    Parameters2[34] = instance.parameters.ea_EndEMAShift2
    Parameters2[35] = instance.parameters.display_ema_angle2
    Parameters2[36] = instance.parameters.EMAPeriod2
    Parameters2[37] = instance.parameters.StartEMAShift2
    Parameters2[38] = instance.parameters.EndEMAShift2

    Parameters2[39] = instance.parameters.AngleTreshold2
    Parameters2[40] = instance.parameters.RSI_Period2
end

function Prepare(nameOnly)
    CustomID = instance.parameters.CustomID
    ExecutionType = instance.parameters.ExecutionType
    CloseOnOpposite = instance.parameters.CloseOnOpposite
    MaxNumberOfPositionInAnyDirection = instance.parameters.MaxNumberOfPositionInAnyDirection
    MaxNumberOfPosition = instance.parameters.MaxNumberOfPosition
    Direction = instance.parameters.Direction == "direct"

    LongColor = core.rgb(0, 255, 0)
    ShortColor = core.rgb(255, 0, 0)
    ExitColor = core.rgb(0, 0, 255)
    NeutralColor = core.rgb(128, 128, 128)

    --parameters 1
    Add1()
    Add2()

    assert(instance.parameters.TF ~= "t1", "The time frame must not be tick")

    local name
    name = profile:id() .. "( " .. instance.bid:name() .. "," .. CustomID .. " )"
    instance:name(name)

    PrepareTrading()

    if nameOnly then
        return
    end

    assert(core.indicators:findIndicator("FXPRIMEBAR") ~= nil, "Please, download and install FXPRIMEBAR.LUA indicator")

    if ExecutionType == "Live" then
        TickSource = ExtSubscribe(1, nil, "t1", instance.parameters.Type == "Bid", "close")
    end

    Source1 = ExtSubscribe(2, nil, instance.parameters.TF1, instance.parameters.Type == "Bid", "bar")
    Source2 = ExtSubscribe(3, nil, instance.parameters.TF2, instance.parameters.Type == "Bid", "bar")
    Indicator1 =
        core.indicators:create(
        "FXPRIMEBAR",
        Source1,
        Parameters1[39],
        Parameters1[40],
        Parameters1[1],
        Parameters1[2],
        Parameters1[3],
        Parameters1[4],
        Parameters1[5],
        Parameters1[6],
        Parameters1[7],
        Parameters1[8],
        Parameters1[9],
        Parameters1[10],
        Parameters1[11],
        Parameters1[12],
        Parameters1[13],
        Parameters1[14],
        Parameters1[15],
        Parameters1[16],
        Parameters1[17],
        Parameters1[18],
        Parameters1[19],
        Parameters1[20],
        Parameters1[21],
        Parameters1[22],
        Parameters1[23],
        Parameters1[24],
        Parameters1[25],
        Parameters1[26],
        Parameters1[27],
        Parameters1[28],
        Parameters1[29],
        Parameters1[30],
        Parameters1[31],
        Parameters1[32],
        Parameters1[33],
        Parameters1[34],
        Parameters1[35],
        Parameters1[36],
        Parameters1[37],
        Parameters1[38],
        LongColor,
        ShortColor,
        ExitColor,
        NeutralColor
    )
    Indicator2 =
        core.indicators:create(
        "FXPRIMEBAR",
        Source2,
        Parameters2[39],
        Parameters2[40],
        Parameters2[1],
        Parameters2[2],
        Parameters2[3],
        Parameters2[4],
        Parameters2[5],
        Parameters2[6],
        Parameters2[7],
        Parameters2[8],
        Parameters2[9],
        Parameters2[10],
        Parameters2[11],
        Parameters2[12],
        Parameters2[13],
        Parameters2[14],
        Parameters2[15],
        Parameters2[16],
        Parameters2[17],
        Parameters2[18],
        Parameters2[19],
        Parameters2[20],
        Parameters2[21],
        Parameters2[22],
        Parameters2[23],
        Parameters2[24],
        Parameters2[25],
        Parameters2[26],
        Parameters2[27],
        Parameters2[28],
        Parameters2[29],
        Parameters2[30],
        Parameters2[31],
        Parameters2[32],
        Parameters2[33],
        Parameters2[34],
        Parameters2[35],
        Parameters2[36],
        Parameters2[37],
        Parameters2[38],
        LongColor,
        ShortColor,
        ExitColor,
        NeutralColor
    )

    ToTime = instance.parameters.ToTime
    ValidInterval = instance.parameters.ValidInterval
    UseMandatoryClosing = instance.parameters.UseMandatoryClosing

    if ToTime == 1 then
        ToTime = core.TZ_EST
    elseif ToTime == 2 then
        ToTime = core.TZ_UTC
    elseif ToTime == 3 then
        ToTime = core.TZ_LOCAL
    elseif ToTime == 4 then
        ToTime = core.TZ_SERVER
    elseif ToTime == 5 then
        ToTime = core.TZ_FINANCIAL
    elseif ToTime == 6 then
        ToTime = core.TZ_TS
    end

    local valid
    OpenTime, valid = ParseTime(instance.parameters.StartTime)
    assert(valid, "Time " .. instance.parameters.StartTime .. " is invalid")
    CloseTime, valid = ParseTime(instance.parameters.StopTime)
    assert(valid, "Time " .. instance.parameters.StopTime .. " is invalid")
    ExitTime, valid = ParseTime(instance.parameters.ExitTime)
    assert(valid, "Time " .. instance.parameters.ExitTime .. " is invalid")

    if UseMandatoryClosing then
        core.host:execute("setTimer", 100, math.max(ValidInterval / 2, 1))
    end
end

function ParseTime(time)
    local pos = string.find(time, ":")
    if pos == nil then
        return nil, false
    end
    local h = tonumber(string.sub(time, 1, pos - 1))
    time = string.sub(time, pos + 1)
    pos = string.find(time, ":")
    if pos == nil then
        return nil, false
    end
    local m = tonumber(string.sub(time, 1, pos - 1))
    local s = tonumber(string.sub(time, pos + 1))
    return (h / 24.0 + m / 1440.0 + s / 86400.0), ((h >= 0 and h < 24 and m >= 0 and m < 60 and s >= 0 and s < 60) or -- time in ole format
        (h == 24 and m == 0 and s == 0)) -- validity flag
end

function InRange(now, openTime, closeTime)
    if openTime < closeTime then
        return now >= openTime and now <= closeTime;
    end
    if openTime > closeTime then
        return now > openTime or now < closeTime;
    end

    return now == openTime;
end

function PrepareTrading()
    ALLOWEDSIDE = instance.parameters.ALLOWEDSIDE

    local PlaySound = instance.parameters.PlaySound
    if PlaySound then
        SoundFile = instance.parameters.SoundFile
    else
        SoundFile = nil
    end
    assert(not (PlaySound) or (PlaySound and SoundFile ~= ""), "Sound file must be chosen")

    ShowAlert = instance.parameters.ShowAlert
    RecurrentSound = instance.parameters.RecurrentSound

    SendEmail = instance.parameters.SendEmail

    if SendEmail then
        Email = instance.parameters.Email
    else
        Email = nil
    end
    assert(not (SendEmail) or (SendEmail and Email ~= ""), "E-mail address must be specified")

    AllowTrade = instance.parameters.AllowTrade
    Account = instance.parameters.Account
    Amount = instance.parameters.Amount
    BaseSize = core.host:execute("getTradingProperty", "baseUnitSize", instance.bid:instrument(), Account)
    Offer = core.host:findTable("offers"):find("Instrument", instance.bid:instrument()).OfferID
    CanClose = core.host:execute("getTradingProperty", "canCreateMarketClose", instance.bid:instrument(), Account)
    SetLimit = instance.parameters.SetLimit
    Limit = instance.parameters.Limit
    SetStop = instance.parameters.SetStop
    Stop = instance.parameters.Stop
    TrailingStop = instance.parameters.TrailingStop
end

local Last
local LAST
local ONE

function ExtUpdate(id, source, period) -- The method called every time when a new bid or ask price appears.
    now = core.host:execute("getServerTime")
    now = core.host:execute("convertTime", core.TZ_EST, ToTime, now)
    -- get only time
    now = now - math.floor(now)
    if not InRange(now, OpenTime, CloseTime) then
        return
    end

    if AllowTrade then
        if not (checkReady("trades")) or not (checkReady("orders")) then
            return
        end
    end

    if ExecutionType == "Live" and id == 1 then
        period1 = core.findDate(Source1.close, TickSource:date(period), false)
        period2 = core.findDate(Source2.close, TickSource:date(period), false)
    end

    if ExecutionType == "Live" then
        if ONE == Source1:serial(period1) then
            return
        end

        if id == 2 then
            return
        end
    else
        if id ~= 2 then
            return
        end
        period1 = period
        period2 = core.findDate(Source2.close, Source1:date(period1), false)
    end

    if (Indicator1.DATA:first()) > period1 or (Indicator2.DATA:first()) > period2 then
        return
    end

    -- update indicators.
    Indicator1:update(core.UpdateLast)
    Indicator2:update(core.UpdateLast)

    --[[
   	BUY; 
		H4 FX PRIME BAR IS HAVING GREEN IN PAST 3 BARS AND
		H1 FX PRIME BAR OF CLOSED CANDLE IS GREEN
		H1 FX PRIME BAR OF PREVIOUS CANDLE IS GREY OR BLUE.

		SELL:

		H4 FX PRIME BAR IS HAVING RED IN PAST 3 BARS AND
		H1 FX PRIME BAR OF CLOSED CANDLE IS RED
		H1 FX PRIME BAR OF PREVIOUS CANDLE IS GREY OR BLUE.

	]]
    -- only buy if we have a fast cross over slow and the price is above the moving averages.
    if
        Indicator2.DATA:colorI(period2) == LongColor and Indicator1.DATA:colorI(period1) == LongColor and
            Indicator1.DATA:colorI(period1 - 1) ~= LongColor
     then
        if Direction then
            BUY()
        else
            SELL()
        end
        ONE = Source1:serial(period1)
    elseif
        Indicator2.DATA:colorI(period2) == ShortColor and Indicator1.DATA:colorI(period1) == ShortColor and
            Indicator1.DATA:colorI(period1 - 1) ~= ShortColor
     then
        if Direction then
            SELL()
        else
            BUY()
        end
        ONE = Source1:serial(period1)
    end
end
-- NG: Introduce async function for timer/monitoring for the order results
function ExtAsyncOperationFinished(cookie, success, message)
    if cookie == 100 then
        -- timer
        if UseMandatoryClosing and AllowTrade then
            now = core.host:execute("getServerTime")
            now = core.host:execute("convertTime", core.TZ_EST, ToTime, now)
            -- get only time
            now = now - math.floor(now)

            -- check whether the time is in the exit time period
            if now >= ExitTime and now < ExitTime + (ValidInterval / 86400.0) then
                if not checkReady("trades") then
                    return
                end

                if haveTrades("B") then
                    exitSpecific("B")
                    Signal("Close Long")
                end

                if haveTrades("S") then
                    exitSpecific("S")
                    Signal("Close Short")
                end
            end
        end
    elseif cookie == 200 and not success then
        terminal:alertMessage(
            instance.bid:instrument(),
            instance.bid[instance.bid:size() - 1],
            "Open order failed" .. message,
            instance.bid:date(instance.bid:size() - 1)
        )
    elseif cookie == 201 and not success then
        terminal:alertMessage(
            instance.bid:instrument(),
            instance.bid[instance.bid:size() - 1],
            "Close order failed" .. message,
            instance.bid:date(instance.bid:size() - 1)
        )
    end
end
--===========================================================================--
--                    TRADING UTILITY FUNCTIONS                              --
--============================================================================--
function BUY()
    if AllowTrade then
        if CloseOnOpposite and haveTrades("S") then
            -- close on opposite signal
            exitSpecific("S")
            Signal("Close Short")
        end

        if ALLOWEDSIDE == "Sell" then
            -- we are not allowed buys.
            return
        end

        enter("B")
    else
        Signal("Buy Signal")
    end
end

function SELL()
    if AllowTrade then
        if CloseOnOpposite and haveTrades("B") then
            -- close on opposite signal
            exitSpecific("B")
            Signal("Close Long")
        end

        if ALLOWEDSIDE == "Buy" then
            -- we are not allowed sells.
            return
        end

        enter("S")
    else
        Signal("Sell Signal")
    end
end

function Signal(Label)
    if ShowAlert then
        terminal:alertMessage(instance.bid:instrument(), instance.bid[NOW], Label, instance.bid:date(NOW))
    end

    if SoundFile ~= nil then
        terminal:alertSound(SoundFile, RecurrentSound)
    end

    if Email ~= nil then
        terminal:alertEmail(
            Email,
            Label,
            profile:id() ..
                "(" ..
                    instance.bid:instrument() ..
                        ")" .. instance.bid[NOW] .. ", " .. Label .. ", " .. instance.bid:date(NOW)
        )
    end
end

function checkReady(table)
    local rc
    if Account == "TESTACC_ID" then
        -- run under debugger/simulator
        rc = true
    else
        rc = core.host:execute("isTableFilled", table)
    end

    return rc
end

function tradesCount(BuySell)
    local enum, row
    local count = 0
    enum = core.host:findTable("trades"):enumerator()
    row = enum:next()
    while row ~= nil do
        if
            row.AccountID == Account and row.OfferID == Offer and row.QTXT == CustomID and
                (row.BS == BuySell or BuySell == nil)
         then
            count = count + 1
        end

        row = enum:next()
    end

    return count
end

function haveTrades(BuySell)
    local enum, row
    local found = false
    enum = core.host:findTable("trades"):enumerator()
    row = enum:next()
    while (row ~= nil) do
        if
            row.AccountID == Account and row.OfferID == Offer and row.QTXT == CustomID and
                (row.BS == BuySell or BuySell == nil)
         then
            found = true
            break
        end

        row = enum:next()
    end

    return found
end

-- enter into the specified direction
function enter(BuySell)
    -- do not enter if position in the specified direction already exists
    if tradesCount(BuySell) >= MaxNumberOfPosition or ((tradesCount(nil)) >= MaxNumberOfPositionInAnyDirection) then
        return true
    end

    -- send the alert after the checks to see if we can trade.
    if (BuySell == "S") then
        Signal("Sell Signal")
    else
        Signal("Buy Signal")
    end

    return MarketOrder(BuySell)
end

-- enter into the specified direction
function MarketOrder(BuySell)
    local valuemap, success, msg
    valuemap = core.valuemap()

    valuemap.Command = "CreateOrder"
    valuemap.OrderType = "OM"
    valuemap.OfferID = Offer
    valuemap.AcctID = Account
    valuemap.Quantity = Amount * BaseSize
    valuemap.BuySell = BuySell
    valuemap.CustomID = CustomID

    -- add stop/limit
    valuemap.PegTypeStop = "O"
    if SetStop then
        if BuySell == "B" then
            valuemap.PegPriceOffsetPipsStop = -Stop
        else
            valuemap.PegPriceOffsetPipsStop = Stop
        end
    end
    if TrailingStop then
        valuemap.TrailStepStop = 1
    end

    valuemap.PegTypeLimit = "O"
    if SetLimit then
        if BuySell == "B" then
            valuemap.PegPriceOffsetPipsLimit = Limit
        else
            valuemap.PegPriceOffsetPipsLimit = -Limit
        end
    end

    if (not CanClose) then
        valuemap.EntryLimitStop = "Y"
    end

    success, msg = terminal:execute(200, valuemap)

    if not (success) then
        terminal:alertMessage(
            instance.bid:instrument(),
            instance.bid[instance.bid:size() - 1],
            "Open order failed" .. msg,
            instance.bid:date(instance.bid:size() - 1)
        )
        return false
    end

    return true
end

-- exit from the specified trade using the direction as a key
function exitSpecific(BuySell)
    -- we have to loop through to exit all trades in each direction instead
    -- of using the net qty flag because we may be running multiple strategies on the same account.
    local enum, row
    local found = false
    enum = core.host:findTable("trades"):enumerator()
    row = enum:next()
    while (not found) and (row ~= nil) do
        -- for every trade for this instance.
        if
            row.AccountID == Account and row.OfferID == Offer and row.QTXT == CustomID and
                (row.BS == BuySell or BuySell == nil)
         then
            exitTrade(row)
        end

        row = enum:next()
    end
end

-- exit from the specified direction
function exitTrade(tradeRow)
    if not (AllowTrade) then
        return true
    end

    local valuemap, success, msg
    valuemap = core.valuemap()

    -- switch the direction since the order must be in oppsite direction
    if tradeRow.BS == "B" then
        BuySell = "S"
    else
        BuySell = "B"
    end
    valuemap.OrderType = "CM"
    valuemap.OfferID = Offer
    valuemap.AcctID = Account
    if (CanClose) then
        -- Non-FIFO can close each trade independantly.
        valuemap.TradeID = tradeRow.TradeID
        valuemap.Quantity = tradeRow.Lot
    else
        -- FIFO.
        valuemap.NetQtyFlag = "Y" -- this forces all trades to close in the opposite direction.
    end
    valuemap.BuySell = BuySell
    valuemap.CustomID = CustomID
    success, msg = terminal:execute(201, valuemap)

    if not (success) then
        terminal:alertMessage(
            instance.bid:instrument(),
            instance.bid[instance.bid:size() - 1],
            "Close order failed" .. msg,
            instance.bid:date(instance.bid:size() - 1)
        )
        return false
    end

    return true
end

dofile(core.app_path() .. "\\strategies\\standard\\include\\helper.lua")
