-- More information about this indicator can be found at: -- http://fxcodebase.com/code/viewtopic.php?f=27&t=13413 function Init() strategy:name("Fractal Gains Strategy") strategy:description("Fractal Gains Strategy") strategy.parameters:addGroup("D oscillator parameters") strategy.parameters:addString("TF", "Time Frame", "", "m1") strategy.parameters:setFlag("TF", core.FLAG_PERIODS) strategy.parameters:addInteger("RSI_Period", "RSI_Period", "", 14) strategy.parameters:addInteger("D_Period", "D_Period", "", 14) strategy.parameters:addInteger("CCI_Period", "CCI_Period", "", 14) strategy.parameters:addDouble("CCI_Coeff", "CCI_Coeff", "", 0.1) strategy.parameters:addInteger("Smooth", "Smooth", "", 14) strategy.parameters:addGroup("Margin Requirements") strategy.parameters:addBoolean("UseMargin", "Use Margin To Control Trades", "", true) strategy.parameters:addInteger("StopMargin", "Percentage to stop adding new trades", "", 90, 1, 100) strategy.parameters:addGroup("Trading Parameters") strategy.parameters:addBoolean("AllowTrade", "Allow strategy to trade", "", true) strategy.parameters:addString("Period", "Chart Time Frame", "", "m1") strategy.parameters:setFlag("Period", core.FLAG_PERIODS) strategy.parameters:addString("Account", "Account to trade on", "", "") strategy.parameters:setFlag("Account", core.FLAG_ACCOUNT) strategy.parameters:addString("TradeType", "Use Balance or Fixed Lot", "", "Bal") strategy.parameters:addStringAlternative("TradeType", " FixedLot ", "", "FL") strategy.parameters:addStringAlternative("TradeType", "Balance", "", "Bal") strategy.parameters:addInteger("Amount", "Trade Amount in Lots", "", 1, 1, 1000) strategy.parameters:addInteger("DividedBy", "Amount Of Account To Use", "", 3, .1, 50) strategy.parameters:addBoolean("SetLimit", "Set Limit Orders", "", true) strategy.parameters:addInteger("Limit", "Limit Order in pips", "", 30, 1, 10000) strategy.parameters:addGroup("Fractal Parameters") strategy.parameters:addInteger("Frame", "Number of bars for fractals (Odd)", "", 5, 3, 99) strategy.parameters:addGroup("Stop Parameters") strategy.parameters:addInteger("Indent", "Indent from fractal", "", 10, 0, 1000) strategy.parameters:addBoolean("MoveBack", "Move stop back", "", false) strategy.parameters:addString("Type", "Price type", "", "Auto") strategy.parameters:addStringAlternative("Type", "Bid", "", "Bid") strategy.parameters:addStringAlternative("Type", "Ask", "", "Ask") strategy.parameters:addStringAlternative("Type", "Auto", "", "Auto") strategy.parameters:addString("FPeriod", "Fractal Time Frame", "", "m1") strategy.parameters:setFlag("FPeriod", core.FLAG_PERIODS) strategy.parameters:addGroup("Notification") strategy.parameters:addBoolean("ShowAlert", "Show Alert", "", false) strategy.parameters:addBoolean("PlaySound", "Play Sound", "", false) strategy.parameters:addBoolean("RecurSound", "Recurrent Sound", "", false) strategy.parameters:addString("SoundFile", "Sound File", "", "") strategy.parameters:setFlag("SoundFile", core.FLAG_SOUND) strategy.parameters:addBoolean("SendEmail", "Send Email", "", false) strategy.parameters:addString("Email", "Email", "", "") strategy.parameters:setFlag("Email", core.FLAG_EMAIL) end local ShowAlert local SoundFile local RecurrentSound local SendEmail, Email local DO = nil local openLevel = 0 local closeLevel = 0 local confirmTrend local AllowTrade = nil local Account = nil local Amount = nil local BaseSize = nil local PipSize local CanClose = nil local Shift local UpFrValue, DnFrValue local FirstStart function Prepare() ShowAlert = instance.parameters.ShowAlert local PlaySound = instance.parameters.PlaySound if PlaySound then SoundFile = instance.parameters.SoundFile else SoundFile = nil end assert(not (PlaySound) or SoundFile ~= "", "Sound file must be chosen") RecurrentSound = instance.parameters.Recurrent local SendEmail = instance.parameters.SendEmail if SendEmail then Email = instance.parameters.Email else Email = nil end assert(not (SendEmail) or Email ~= "", "Email address must be specified") assert(instance.parameters.TF ~= "t1", "The time frame must not be tick") local name name = profile:id() .. "(" .. instance.bid:name() .. "." .. instance.parameters.TF .. "," .. "DO(" .. instance.parameters.RSI_Period .. ", " .. instance.parameters.D_Period .. ", " .. instance.parameters.CCI_Period .. ", " .. instance.parameters.CCI_Coeff .. ", " .. instance.parameters.Smooth .. "))" instance:name(name) AllowTrade = instance.parameters.AllowTrade if AllowTrade then 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) PipSize = instance.bid:pipSize() SetLimit = instance.parameters.SetLimit Limit = instance.parameters.Limit end Source_DO = ExtSubscribe(2, nil, instance.parameters.TF, true, "bar") Source_Entry = ExtSubscribe(3, nil, instance.parameters.Period, true, "bar") Source_SL = ExtSubscribe(4, nil, instance.parameters.FPeriod, true, "bar") Source_Tick = ExtSubscribe(5, nil, "t1", true, "bar") DO = core.indicators:create( "D_OSCILLATOR", Source_DO, instance.parameters.RSI_Period, instance.parameters.D_Period, instance.parameters.CCI_Period, instance.parameters.CCI_Coeff, instance.parameters.Smooth ) Shift = math.floor(instance.parameters.Frame / 2) UpFrValue, DnFrValue = nil, nil ExtSetupSignal(profile:id() .. ":", ShowAlert) ExtSetupSignalMail(name) FirstStart = true end function IsFractal(source, period) local Up = true local Dn = true local i for i = 1, Shift, 1 do if source.high[period - 2 - i] >= source.high[period - 2] or source.high[period - 2 + i] >= source.high[period - 2] then Up = false end if source.low[period - 2 - i] <= source.low[period - 2] or source.low[period - 2 + i] <= source.low[period - 2] then Dn = false end end return Up, Dn end function FindLastFractals(source, period) local UpPos, DnPos = nil, nil local UpValue, DnValue = 0, 0 local i = period local first = source:first() + instance.parameters.Frame while (UpPos == nil or DnPos == nil) and i >= first do local Up, Dn = IsFractal(source, i) if Up and UpPos == nil then UpPos = i - Shift UpValue = source.high[UpPos] end if Dn and DnPos == nil then DnPos = i - Shift DnValue = source.low[DnPos] end i = i - 1 end return UpValue, DnValue end function CheckMargin() return false end function setStop(trade, stopValue, stopSide) if CanClose then if trade.StopOrderID == "" or trade.StopOrderID == nil then valuemap = core.valuemap() valuemap.Command = "CreateOrder" valuemap.OrderType = "S" valuemap.OfferID = trade.OfferID valuemap.AcctID = trade.AccountID valuemap.TradeID = trade.TradeID valuemap.Quantity = trade.Lot valuemap.Rate = stopValue valuemap.BuySell = stopSide executing = true success, msg = terminal:execute(200, valuemap) if not (success) then executing = false terminal:alertMessage( instance.bid:instrument(), instance.bid[NOW], "Failed create stop " .. msg, instance.bid:date(NOW) ) end else if instance.parameters.MoveBack == false then if trade.BS == "B" then if stopValue <= trade.Stop then return end else if stopValue >= trade.Stop then return end end end valuemap = core.valuemap() valuemap.Command = "EditOrder" valuemap.AcctID = trade.AccountID valuemap.OrderID = trade.StopOrderID valuemap.Rate = stopValue executing = true success, msg = terminal:execute(200, valuemap) if not (success) then executing = false terminal:alertMessage( instance.bid:instrument(), instance.bid[NOW], "Failed change stop " .. msg, instance.bid:date(NOW) ) end end else local order = nil local rate local enum, row enum = core.host:findTable("orders"):enumerator() row = enum:next() while (row ~= nil) do if row.OfferID == trade.OfferID and row.AccountID == trade.AccountID and row.BS == stopSide and row.NetQuantity and row.Type == "SE" then order = row.OrderID rate = row.Rate end row = enum:next() end if order == nil then valuemap = core.valuemap() valuemap.Command = "CreateOrder" valuemap.OrderType = "SE" valuemap.OfferID = trade.OfferID valuemap.AcctID = trade.AccountID valuemap.TradeID = trade.TradeID valuemap.NetQtyFlag = "y" valuemap.Rate = stopValue valuemap.BuySell = stopSide executing = true success, msg = terminal:execute(200, valuemap) if not (success) then executing = false terminal:alertMessage( instance.bid:instrument(), instance.bid[NOW], "Failed create stop " .. msg, instance.bid:date(NOW) ) end else if instance.parameters.MoveBack == false then if trade.BS == "B" then if stopValue <= rate then return end else if stopValue >= rate then return end end end valuemap = core.valuemap() valuemap.Command = "EditOrder" valuemap.OfferID = trade.OfferID valuemap.AcctID = trade.AccountID valuemap.OrderID = order valuemap.Rate = stopValue executing = true success, msg = terminal:execute(200, valuemap) if not (success) then executing = false terminal:alertMessage( instance.bid:instrument(), instance.bid[NOW], "Failed change stop " .. msg, instance.bid:date(NOW) ) end end end end function ExtUpdate(id, source, period) if id == 2 then return end if period < Shift + 2 then return; end local pipSize = instance.bid:pipSize() local FractalPrice local SL local stopValue local stopSide if id == 4 then UpFrValue, DnFrValue = FindLastFractals(source, period) if UpFrValue ~= nil or DnFrValue ~= nil then local trades = core.host:findTable("trades") local enum = trades:enumerator() while true do local trade = enum:next() if trade == nil then break end if trade.BS == "B" then if DnFrValue ~= nil then stopValue = DnFrValue - instance.parameters.Indent * instance.bid:pipSize() setStop(trade, stopValue, "S") end else if UpFrValue ~= nil then stopValue = UpFrValue + instance.parameters.Indent * instance.bid:pipSize() setStop(trade, stopValue, "B") end end end end return end if (id == 5 and FirstStart) or id == 3 then FirstStart = false if id == 5 then source = Source_Entry period = source:size() - 1 end core.host:trace("FirstStart") UpFrValue, DnFrValue = FindLastFractals(source, period) if UpFrValue ~= nil and DnFrValue ~= nil then core.host:trace("1") local UpSlValue, DnSlValue = FindLastFractals(Source_SL, Source_SL:size() - 2) DO:update(core.UpdateLast) local _period = Source_DO:size() - 2 if not DO.Buff1:hasData(_period - 1) or not DO.Buff2:hasData(period - 1) then return; end if DO.Buff1[_period - 1] < DO.Buff2[_period - 1] and DO.Buff1[_period] > DO.Buff2[_period] then core.host:trace("2") FractalPrice = UpFrValue + instance.parameters.Indent * instance.bid:pipSize() SL = DnSlValue - instance.parameters.Indent * instance.bid:pipSize() if FractalPrice > instance.ask[NOW] + core.host:execute( "getTradingProperty", "conditionalDistanceEntryStop", instance.bid:instrument(), Account ) then if ShowAlert then ExtSignal( source, period, "Place entry BUY to " .. FractalPrice, SoundFile, Email, RecurrentSound ) end if AllowTrade then Open("B", FractalPrice, SL) end end end if DO.Buff2[_period - 1] < DO.Buff1[_period - 1] and DO.Buff2[_period] > DO.Buff1[_period] then FractalPrice = DnFrValue - instance.parameters.Indent * instance.bid:pipSize() SL = UpSlValue + instance.parameters.Indent * instance.bid:pipSize() if FractalPrice < instance.bid[NOW] - core.host:execute( "getTradingProperty", "conditionalDistanceEntryStop", instance.bid:instrument(), Account ) then if ShowAlert then ExtSignal( source, period, "Place entry SELL to " .. FractalPrice, SoundFile, Email, RecurrentSound ) end if AllowTrade then Open("S", FractalPrice, SL) end end end end end end function ReleaseInstance() end function Open(side, Open_Price, SL_Price) local valuemap local Fractal valuemap = core.valuemap() valuemap.OfferID = Offer valuemap.AcctID = Account valuemap.Quantity = Amount * BaseSize valuemap.CustomID = CID valuemap.BuySell = side valuemap.OrderType = "SE" valuemap.Rate = Open_Price if SetLimit then valuemap.PegTypeLimit = "O" if side == "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) assert(success, msg) end function AsyncOperationFinished(cookie, successful, message) if not successful then core.host:trace("Error: " .. message) end end dofile(core.app_path() .. "\\strategies\\standard\\include\\helper.lua")