[DMcL] Kernel Trading Machine

beta
By dmaclennan in Trading Bots Published June 2023 👁 1,342 views 💬 0 comments

Description

"the trend is your friend" Rather than a mean-reverting strategy, I wanted something that goes all-in once (instead of doubling down on losing entry) and then captures profits in layers. It doesnt trade often when using good settings - maybe once every week or two - but can lock in those profits to keep gains consistent.
HaasScript
-- Author: DMcL
-- original indicator by jdehorty
-- https://www.tradingview.com/script/AWNvbPRM-Nadaraya-Watson-Rational-Quadratic-Kernel-Non-Repainting/

EnableHighSpeedUpdates(true)
HideOrderSettings()
HideTradeAmountSettings()
SetFee(-0.025) -- for backtesting

OptimizedForInterval(60, 
    function()

local trade_margin = Input('Trade Margin', 100, 'Total margin used of quote currency (e.g. USDT)', 'Bet Size')
local h = Input('Lookback Window', 6, 'The number of bars used for the estimation. This is a sliding value that represents the most recent historical bars. Recommended range: 3-50', 'Kernel Settings')
local r = Input('Relative Weighting', 25, 'Relative weighting of time frames. As this value approaches zero, the longer time frames will exert more influence on the estimation. As this value approaches infinity, the behavior of the Rational Quadratic Kernel will become identical to the Gaussian kernel. Recommended range: 0.25-25', 'Kernel Settings')
local x_0 = Input("Start Regression at Bar", 17, 'Bar index on which to start regression. The first bars of a chart are often highly volatile, and omission of these initial bars often leads to a better overall fit. Recommended range: 5-25', 'Kernel Settings')
local close = ClosePrices()
local high = HighPrices()
local low = LowPrices()
local ohlc = OHLCPrices()


-- inputs
    local emaFilter = Input('Use EMA Filter', true, 'If true, will only take long trades when price is above ema, and short when below', 'EMA settings')
    local emaLength = Input('EMA Length', 150, '', 'EMA settings')
    local oppSig = Input('Opposite signal acts as Stop Loss', true, 'If true, change of signal will exit', 'EMA settings')
    local layers = Input('Take Profit Layers', 6, 'How many exit orders to create. Must be greater than 1', 'Take Profit & Stop Loss')
    local atrPeriod = 20
    local atrpMult = Input('Take Profit gaps ATR multiplier', 0.1, 'Recommended range: 0-0.5. The ATR as a percentage, multiplied by this number, will be added to each take profit layer. Use to make take profit layers size dynamic. 0 will disable', 'Take Profit & Stop Loss')
    local natr = (ATR(high, low, close, atrPeriod)/close)*100
    local natrScaled = natr*atrpMult
    local tpGaps = Input('Take Profit gaps %', 0.9, 'Recommended range: 0.5-3. This exact value, as a percentage, will be added to each take profit layer. 0 will disable', 'Take Profit & Stop Loss')
    local follow = Input('Trailing Stop Loss Follows Take Profit Reached',0, 'MUST be integer. If set to 0, the stop loss will move to break even when take profit 1 is filled, move to take profit 1 when take profit 2 is filled and so on. If set to 1, stop loss will move to break even once take profit 2 is reached, move to take profit 1 once take profit 3 is reached and so on.', 'Take Profit & Stop Loss')
    local stoploss = Input("Stop Loss %", 20, 'Percent where stop loss is set at beginning of position ', 'Take Profit & Stop Loss')
    local stopTrailLimit = Input("Limit Trailing Stop-loss to break-even", true, 'If true, trailing stop loss will stop trailing at break even level.', 'Take Profit & Stop Loss')
    local forceExitPos = Input("Force Exit Position", false, 'manually exit position', 'Take Profit & Stop Loss')
-- data
    local ema = EMA(close, emaLength)
    local cp = CurrentPrice()
    local ob = GetOrderbook()
    local cv = ContractValue()
    local profit = GetBotProfit()
    local tradeAmount = trade_margin/cv * Leverage()


-- position
    local posId = Load('posId', NewGuid())
    local position = PositionContainer(posId)


-- useful values
    local entryPrice = position.enterPrice
    local posAmount = position.amount
    local tpAmount = (posAmount/layers)
    local shutdownTypes = {
        stoploss = 1,
        fliplong = 2,
        flipshort = 3
        }

-- new array function
    function newArray(size, def_val)
        local arr = {}
        for i = 1, size do
            arr[i] = def_val
        end
        return arr
    end

-- memory
    local leid = Load('leid', '')
    local seid = Load('seid', '')
    local lxeid = Load('lxeid', '')
    local sxeid = Load('sxeid', '')
    local xeid = Load('xeid', '')
    local changeLong = Load('changeLong', false)
    local changeShort = Load('changeShort', false)
    local stopOrder = Load('stopOrder', false)
    local index = Load('index', 0)
    local TPidL = Load('TPidL', newArray(layers, ''))



-- new position function
    function newPosition()
        leid = ''
        seid = ''
        lxeid = ''
        sxeid = ''
        xeid = ''
        changeLong = false
        changeShort = false
        stopOrder = false
        index = 0
        TPidL = newArray(layers, '')
        posId = NewGuid()
    end

-- stop-loss function
    function execStopLossExit(type)
        if IsAnyOrderOpen(posId) then
            CancelAllOrders(posId)
            LogWarning('cancelling tp orders...')
            stopOrder = true
        end

        if type == shutdownTypes.fliplong then
            LogWarning('--- flip direction long')
        elseif type == shutdownTypes.flipshort then
            LogWarning('--- flip direction short')
        elseif type == shutdownTypes.stoploss then
            LogWarning('--- stop loss cutoff')
        elseif type == shutdownTypes.force then
            LogWarning('--- manual exit')
        end
    end

-- stop-loss order function
    if stopOrder then
        if not IsAnyOrderOpen(posId) then
            Log('All Take Profits cancelled...')
            PlaceExitPositionOrder(posId, {type = MarketOrderType, note = 'Stoploss Exit position order exec..'})
            newPosition()
        end
    end




-- set the stop loss price
    function updateOrders(isLong)
            slPrice = isLong
                and SubPerc(entryPrice, stoploss)
                or AddPerc(entryPrice, stoploss)

            brEven = isLong
                and AddPerc(entryPrice, 0.00)
                or SubPerc(entryPrice, 0.00)

        -- loop for updating take profit filled index for trailing stop loss 
            for z=1, (layers - 1) do
                    if TPidL[z] != '' and IsOrderFilled(TPidL[z]) then
                        index = (z - follow)
                    end
            -- stop loss price
                    if index <= 0 then
                        SL = slPrice
                    elseif index == 1 then
                        SL = brEven
                    elseif index > 1 and stopTrailLimit == false then
                        SL = OrderContainer(TPidL[(index - 1)]).price
                    end
            end
            -- plot stop loss in red
            if isLong then
                Plot(0, 'SL', SL, {c=Red, id=leid})
            else
                Plot(0, 'SL', SL, {c=Red, id=seid})
            end

        -- checking if stop loss triggered
            if (position.isLong and cp.bid < SL) 
            or (position.isShort and cp.ask > SL)
            then
                execStopLossExit(shutdownTypes.stoploss)
            end
    end 



-- take profit orders 
    -- loop to create desired (layers) amount of take profit orders
    for z = 1, layers do

        -- setting take profits
        if (leid != '' and (TPidL[z] == '' or not TPidL[z])) then
            TPidL[z] = PlaceExitLongOrder(AddPerc(OrderContainer(leid).price, ((tpGaps+natrScaled) * z)), tpAmount,{type=LimitOrderType, note='Take Profit L'..z, timeout=-1, positionId=posId})
        end
        if (seid != '' and (TPidL[z] == '' or not TPidL[z])) then
            TPidL[z] = PlaceExitShortOrder(SubPerc(OrderContainer(seid).price, ((tpGaps+natrScaled) * z)), tpAmount,{type=LimitOrderType, note='Take Profit S'..z, timeout=-1, positionId=posId})
        end

        -- plotting
        if TPidL[z] != '' and IsOrderOpen(TPidL[z]) then
            Plot(0, 'TPidL'..z, OrderContainer(TPidL[z]).price, {c=Yellow, id = TPidL[z]})
        end

    end

-- checking if last take profit hit
    if TPidL[layers] != '' and IsOrderFilled(TPidL[layers]) then
        Log('All Take Profits Hit')
        PlaceExitPositionOrder(posId, {type = MarketOrderType, note = 'Exit position in full..'})
        newPosition()
    end

-- entry functions
    function goLong()
        if (leid == '' or not leid)then
            leid = PlaceGoLongOrder(cp, tradeAmount,{type=MarketOrderType, note='Long Entry', timeout=-1, positionId = posId})
        end
    end

    function goShort()
        if (seid == '' or not seid)then
            seid = PlaceGoShortOrder(cp, tradeAmount,{type=MarketOrderType, note='Short Entry', timeout=-1, positionId = posId})
        end
    end

-- ema trend

    local emaUptrend = close > ema
    local emaDowntrend = close < ema

    local emaAllowLong = (emaUptrend and emaFilter) or not emaFilter
    local emaAllowShort = (emaDowntrend and emaFilter) or not emaFilter




local signal = CC_Nadaraya_Watson_Kernel(2, h, r, x_0)


-- trading
    if TradeOncePerBar() and not forceExitPos then
        if signal == SignalLong then 
            Log("SIGNAL LONG")
            if emaAllowLong then
                if (position.isShort and not position.isLong) and IsAnyOrderOpen(posId) then
                    LogWarning("flipping long...")
                    CancelAllOrders(posId)
                    changeLong = true
                elseif not (position.isLong or position.isShort) then
                        goLong()
                end
            elseif (position.isShort and not position.isLong) and oppSig then
                execStopLossExit(shutdownTypes.stoploss)
            end
        end
    end

    if TradeOncePerBar() and not forceExitPos then
        if signal == SignalShort then
            Log("SIGNAL SHORT")
            if emaAllowShort then
                if (position.isLong and not position.isShort) and IsAnyOrderOpen(posId) then
                    LogWarning("flipping short...")
                    CancelAllOrders(posId)
                    changeShort = true
                elseif not (position.isLong or position.isShort) then
                        goShort()
                end
            elseif (position.isLong and not position.isShort) and oppSig then
                execStopLossExit(shutdownTypes.stoploss)
            end
        end
    end



-- flipping position
    if changeLong and not IsAnyOrderOpen(posId) then
        Log('all tps cancelled')
        sxeid = PlaceExitPositionOrder(posId, {type = MarketOrderType, note = 'Change to Long...'})
        changeLong = false
    end
    if sxeid != '' and IsOrderFilled(sxeid) then
        Log('Short exit filled')
        newPosition()
        goLong()
    end

    if changeShort and not IsAnyOrderOpen(posId) then
        Log('all tps cancelled')
        lxeid = PlaceExitPositionOrder(posId, {type = MarketOrderType, note = 'Change to Short...'})
        changeShort = false
    end
    if lxeid != '' and IsOrderFilled(lxeid) then
        Log('Long exit filled')
        newPosition()
        goShort()
    end




    
    if position.isLong then
        updateOrders(true)
        
    elseif position.isShort then
        updateOrders(false)
    end

    if forceExitPos == true then
        execStopLossExit(shutdownTypes.force)
    end




-- plot
Plot(0, "EMA", ema, Yellow(10))

prof_plot = Plot(2, "PnL", profit, Green(40))
PlotDoubleColor(prof_plot, 0, Red)
Plot(2, "", 0, White)


-- saving order ids
Save('posId', posId)
Save('leid', leid)
Save('lxeid', lxeid)
Save('seid', seid)
Save('sxeid', sxeid)
Save('xeid', xeid)
Save('changeLong', changeLong)
Save('changeShort', changeShort)
Save('stopOrder', stopOrder)
Save('index', index)
Save('TPidL', TPidL)


end)



local roi = GetBotROI()
local pfac = (GetTradingReport().profitFactor)
local winPrc = GetTradingReport().winPercentage

local factor = Load('factor', pfac)

if pfac == 1 then
    factor = 99
else
    factor = pfac
end

Save('factor', factor)

Finalize(function()
CustomReport('win %', winPrc, '', true)

end)

0 Comments

Sign in to leave a comment.

No comments yet. Be the first!