-- More information about this indicator can be found at: -- http://fxcodebase.com/code/viewtopic.php?f=28&t=2712 --+------------------------------------------------------------------+ --| Copyright © 2016, Gehtsoft USA LLC | --| http://fxcodebase.com | --+------------------------------------------------------------------+ --| Support our efforts by donating | --| Paypal: https://goo.gl/9Rj74e | --| BitCoin : 15VCJTLaz12Amr7adHSBtL9v8XomURo9RF | --+------------------------------------------------------------------+ --| Developed by : Mario Jemic | --| mario.jemic@gmail.com | --+------------------------------------------------------------------+ local BAR = true; function Init() --The strategy profile initialization strategy:name("Entry Order Strategy"); strategy:description(""); -- NG: optimizer/backtester hint strategy:setTag("NonOptimizableParameters", "ShowAlert,PlaySound,SoundFile,RecurrentSound,SendMail,Email"); strategy.parameters:addGroup("Time Parameters"); 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); CreateTradingParameters(); end function CreateTradingParameters() strategy.parameters:addGroup("Trading Parameters"); strategy.parameters:addString("Account", "Account to trade", "", ""); strategy.parameters:setFlag("Account", core.FLAG_ACCOUNT); strategy.parameters:addInteger("Amount", "Amount in lots to trade", "", 1, 1, 100); strategy.parameters:addInteger("Distance", "Distance to market (in pips)", "", 100, -1000, 1000); strategy.parameters:addString("BuySell", "Buy or Sell?", "", "B"); strategy.parameters:addStringAlternative("BuySell", "Buy", "", "B"); strategy.parameters:addStringAlternative("BuySell", "Sell", "", "S"); 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:addGroup("Alerts"); strategy.parameters:addBoolean("ShowAlert", "ShowAlert", "", false); 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", "", false); strategy.parameters:addBoolean("SendEmail", "Send Email", "", false); strategy.parameters:addString("Email", "Email", "", ""); strategy.parameters:setFlag("Email", core.FLAG_EMAIL); end local offer; local account; local amount; local pipsize; local BuySell; local distance; local SoundFile = nil; local RecurrentSound = false; local SetLimit; local Limit; local SetStop; local Stop; local TrailingStop; local ShowAlert; local Email; local SendEmail; local BaseSize; local ValidInterval; local UseMandatoryClosing; local canClose; -- Don't need to store hour + minute + second for each time local OpenTime, CloseTime, ExitTime; -- function Prepare(nameOnly) UseMandatoryClosing = instance.parameters.UseMandatoryClosing; ValidInterval = instance.parameters.ValidInterval; local name; name = profile:id() .. "( " .. instance.bid:name(); local i; name = name .. " )"; instance:name(name); -- NG: parsing of the time is moved to separate function 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"); PrepareTrading(); if nameOnly then return ; end if UseMandatoryClosing then core.host:execute("setTimer", 1001, math.max(ValidInterval / 2, 1)); end end function PrepareTrading() 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"); account = instance.parameters.Account; BuySell = instance.parameters.BuySell; distance = instance.parameters.Distance; local lotSize = core.host:execute("getTradingProperty", "baseUnitSize", instance.bid:instrument(), account); amount = lotSize * instance.parameters.Amount; offer = core.host:findTable("offers"):find("Instrument", instance.bid:instrument()).OfferID; pipsize = instance.bid:pipSize(); BaseSize = core.host:execute("getTradingProperty", "baseUnitSize", instance.bid:instrument(), account); SetLimit = instance.parameters.SetLimit; Limit = instance.parameters.Limit; SetStop = instance.parameters.SetStop; Stop = instance.parameters.Stop; TrailingStop = instance.parameters.TrailingStop; canClose = core.host:execute("getTradingProperty", "canCreateMarketClose", instance.bid:instrument(), account); end -- NG: create a function to parse time function ParseTime(time) local Pos = string.find(time, ":"); local h = tonumber(string.sub(time, 1, Pos - 1)); time = string.sub(time, Pos + 1); Pos = string.find(time, ":"); 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), -- time in ole format ((h >= 0 and h < 24 and m >= 0 and m < 60 and s >= 0 and s < 60) or (h == 24 and m == 0 and s == 0)); -- validity flag end --function ExtUpdate(id, source, period) -- The method called every time when a new bid or ask price appears. local create = true; local trade = false; local requestId; function Update() if not(checkReady("trades")) or not(checkReady("orders")) then return ; end local now = core.host:execute("getServerTime"); now = now - math.floor(now); if now >= OpenTime and now <= CloseTime then Entry(); end end function Entry() if create then create = false; -- create order local valuemap = core.valuemap(); valuemap.Command = "CreateOrder"; -- get the order type if BuySell == "B" and distance < 0 then valuemap.OrderType = "LE"; elseif BuySell == "B" and distance > 0 then valuemap.OrderType = "SE"; elseif BuySell == "S" and distance < 0 then valuemap.OrderType = "SE"; elseif BuySell == "S" and distance > 0 then valuemap.OrderType = "LE"; end if instance.parameters.SetLimit then valuemap.PegTypeLimit = "M"; if BuySell == "B" then valuemap.PegPriceOffsetPipsLimit = instance.parameters.Limit; else valuemap.PegPriceOffsetPipsLimit = -instance.parameters.Limit; end end if instance.parameters.SetStop then valuemap.PegTypeStop = "M"; if BuySell == "B" then valuemap.PegPriceOffsetPipsStop = -instance.parameters.Stop; else valuemap.PegPriceOffsetPipsStop = instance.parameters.Stop; end if instance.parameters.TrailingStop then valuemap.TrailStepStop = 1; end end if not(canClose) and (instance.parameters.SetStop or instance.parameters.SetLimit) then -- if regular s/l orders aren't allowed - create ELS order valuemap.EntryLimitStop = "Y"; end if distance >= 0 then valuemap.Rate = instance.ask[NOW] + distance * pipsize; else valuemap.Rate = instance.bid[NOW] + distance * pipsize; end valuemap.OfferID = offer; valuemap.AcctID = account; valuemap.Quantity = amount; valuemap.BuySell = BuySell; local success, msg = terminal:execute(100, valuemap); if not (success) then else requestId = core.parseCsv(msg, ",")[0]; end elseif not(trade) then -- check whether trade has been created local row; row = core.host:findTable("trades"):find("OpenOrderReqID", requestId); if row ~= nil then trade = true; end end end -- NG: Introduce async function for timer/monitoring for the order results function AsyncOperationFinished(cookie, success, message) if cookie == 1001 then -- timer if UseMandatoryClosing then now = core.host:execute("getServerTime"); -- 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 core.host:execute ("stop") end end elseif cookie== 100 then executing = false; if not(success) then Signal("create order failed:" .. message); else Signal("order sent:" .. message); core.host:execute ("stop") end end end --===========================================================================-- -- TRADING UTILITY FUNCTIONS -- --============================================================================-- 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) return core.host:execute("isTableFilled", table); end --dofile(core.app_path() .. "\\strategies\\standard\\include\\helper.lua");