Zone Recovery Bot Hedge SMOD

stable
By smokyho in Trading Bots Published February 2024 👁 1,918 views 💬 0 comments

Description

My modification for Haasonline's original Zone Recovery Bot for HEDGE trading mode. The bot use balance ratio as stop loss and not position size like the original bot. "Closing all positions when working balance (total used margin - total unrealized profit) / bot balance (starting balance + realized profit) > value." The TP % is minimum. The end % is dynamic calculated using formula i steal from Pshai's SMM 2.0. Hedging TP (when bot has both direction open) is the % of used margin. Have fun with it and may the profits be with you! More questions ? Find me in Haasonline Discord. If you would like to buy me a cup of coffee or diamond: ENS: smokyho.eth
HaasScript
--If you would like to buy me a cup of coffee or diamond:
--ENS: smokyho.eth

EnableHighSpeedUpdates()
HideTradeAmountSettings()

-- Inputfields
    InputGroupHeader('Bot Settings')
        local startingBalance = Input('Starting Balance '..ProfitLabel(), 0)
        local startingAmount = Input('Starting exposure '..AmountLabel(), 1)
        local amountFactor = Input('Trade amount factor', 2)
        local zoneFactor = Input('Zone factor', 1)
    InputGroupHeader('Backtest Settings')
        local wtfBalRatio = Input('Stop at Bal. Ratio Limit', false, 'Stop backtest when balance ratio limit below reached.')
    InputGroupHeader('Safety Settings')
        local balRatioLimit = Input("Balance Ratio Limit", 0.25, "Closing all positions when working balance (total used margin - total unrealized profit) / bot balance (starting balance + realized profit) > value.")
    InputGroupHeader('Profit Settings')
        local minProfit = Input('Min. Percentage profits', 0.5)
    
    local market = PriceMarket()
    local leverage = GetLeverage()
    local mainInterval = CurrentInterval()
    local cp = CurrentPrice()
    local report = GetTradingReport()
    local tpTrigger = minProfit

    local h, l, c, basePrice, tpTrigger = OptimizedForInterval(0, function()
        local h = HighPrices()
        local l = LowPrices()
        local c = ClosePrices()
        local basePrice = HLCPrices()

        local tr = TRANGE(h, l, c)
        local diff = Max(tr, DEMA(tr, 7), SMA(tr, 7), TRIMA(tr, 7)) / c * 100
        local rsi = RSI(c, 14)
        local skew = Max(Abs(50 - rsi) / 50, DEMA(Abs(50 - rsi) / 50, 20))
        local tpTrigger = Max(minProfit, diff) + skew

        return h, l, c, basePrice, tpTrigger
    end) 
    
---------------------
-- PERSISTENT STORAGE
    if not inited then
        bot = Load('bot', {})
 
        if Count(bot) == 0 then
            -- positions
            bot.longPosId = NewGuid()
            bot.shortPosId = NewGuid()

            -- stats 
            bot.reset  = true 
            bot.basePrice = basePrice 
            bot.targetSide = SignalExitPosition 
            bot.startingAmount = startingAmount
            bot.targetAmount = startingAmount

            bot.highestBalRatio = 0
        end
 
        inited = true
    end

---------------------
-- DATA 
    local pamt_l = GetPositionAmount(bot.longPosId)
    local pamt_s = GetPositionAmount(bot.shortPosId)
    local aep_l = AverageEnterPrice(bot.longPosId)
    local aep_s = AverageEnterPrice(bot.shortPosId)

    local usedLong = aep_l > 0 and UsedMargin(market, aep_l, pamt_l, leverage) or 0
    local usedShort = aep_s > 0 and UsedMargin(market, aep_s, pamt_s, leverage) or 0
    local usedTotal = usedLong + usedShort

    local profitLong = aep_l > 0 and GetPositionProfit(bot.longPosId) or 0
    local profitShort = aep_s > 0 and GetPositionProfit(bot.shortPosId) or 0
    local profitTotal = profitLong + profitShort

    local botProfit = GetBotProfit(market)
    local netBotProfit = GetBotProfit(market, true)
    local unrealizedBotProfit = netBotProfit - botProfit
    
    local botBalance = startingBalance + botProfit 
    local workingBalance = usedTotal - profitTotal
    local balRatio = workingBalance / botBalance

    local highestBal = startingBalance + report.highestPointInProfit 
    local lowestBal = startingBalance + report.lowestPointInProfit

    -- Side Check 
        if bot.targetSide == SignalLong then 
            PlotSignalEnum(-2, SignalLong) 
        elseif bot.targetSide == SignalShort then
            PlotSignalEnum(-2, SignalShort)
        elseif bot.targetSide == SignalExitPosition then 
            PlotSignalEnum(-2, SignalExitPosition)
        end

---------------------
-- CALCULATE ENTRY PRICE
    if IsAnyOrderOpen() == false and bot.targetSide == SignalExitPosition then
        -- We dont have open orders.
        -- Reset base price if we dont have a position and are resetting.
        if pamt_l + pamt_s == 0 and bot.reset then
            zoneTrigger = tpTrigger
            bot.reset = false
            bot.basePrice = basePrice
            bot.longPosId = NewGuid()
            bot.shortPosId = NewGuid()
        end
    end

    local zoneSize = (bot.basePrice / 100) * zoneTrigger / zoneFactor
    local goLongPrice = bot.basePrice + zoneSize
    local goShortPrice = bot.basePrice - zoneSize

---------------------
-- EXECUTION
    if IsAnyOrderOpen() == false then
        if pamt_l > 0 and pamt_s > 0 
            and profitTotal > usedTotal * tpTrigger / 100 then
            --and profitTotal > (usedLong * TakersFee() * 2) + (usedShort * TakersFee() * 2) then
                PlotSignalBar(-2, White)
                PlaceExitShortOrder(cp.bid, pamt_s, {positionId = bot.shortPosId, type = MarketOrderType, note = 'Hedge Exit'})
                PlaceExitLongOrder(cp.ask, pamt_l, {positionId = bot.longPosId, type = MarketOrderType, note = 'Hedge Exit'})
                bot.targetSide = SignalExitPosition
                bot.reset = true

        elseif bot.targetSide == SignalExitPosition and pamt_l + pamt_s == 0 and MinutesTillCandleClose(mainInterval) == 0 then
            -- Do we want to go long?
            if cp.close > goLongPrice then
                bot.targetSide = SignalLong
                bot.targetAmount = bot.startingAmount
                PlaceGoLongOrder(cp.bid, bot.startingAmount, {positionId = bot.longPosId, timeout  = mainInterval * 60, note = "1st Order"})

            -- Or do we want to go short?
            elseif cp.close < goShortPrice then
                bot.targetSide = SignalShort
                bot.targetAmount = bot.startingAmount
                PlaceGoShortOrder(cp.ask, bot.startingAmount, {positionId = bot.shortPosId, timeout  = mainInterval * 60, note = "1st Order"})

            end

        elseif bot.targetSide == SignalLong then 
            -- Are we fully in the long and out the short?
            if pamt_l < bot.targetAmount then
                local theNote = pamt_s == 0 and "1st Side Order" or "Hedge Order"
                PlaceGoLongOrder(cp.bid, bot.targetAmount - pamt_l, {positionId = bot.longPosId, note = theNote})

            -- Go short price reached?
            elseif cp.close < goShortPrice then
                bot.targetSide = SignalExitPosition
                -- Maximum amount check
                amount = pamt_l * amountFactor

                -- Checking working balance
                if balRatio < balRatioLimit then 
                    -- Open short with a higher amount
                    bot.targetSide = SignalShort
                    bot.targetAmount = amount
                    PlaceGoShortOrder(cp.ask, amount, {positionId = bot.shortPosId, note = "Hedge Order"})
                end
            
            --Take profit price reached?
            elseif pamt_s == 0 and cp.close > AddPerc(aep_l, tpTrigger) then
                PlaceExitLongOrder(cp.ask, pamt_l, {type = MarketOrderType, positionId = bot.longPosId, note = 'Long TP'})
                bot.targetSide = SignalExitPosition
                bot.reset = true--]]

            end

        elseif bot.targetSide == SignalShort then
            -- Are we in the short and out the long?
            if pamt_s < bot.targetAmount then--or pamt_l > 0 then
                local theNote = pamt_l == 0 and "1st Side Order" or "Hedge Order"
                PlaceGoShortOrder(cp.ask, bot.targetAmount - pamt_s, {positionId = bot.shortPosId, note = theNote})

            -- Go long price reached?
            elseif cp.close > goLongPrice then
                bot.targetSide = SignalExitPosition
                -- Maximum amount check
                amount = pamt_s * amountFactor

                -- Checking working balance
                if balRatio < balRatioLimit then 
                    -- Open long with a higher amount
                    bot.targetSide = SignalLong
                    bot.targetAmount = amount
                    PlaceGoLongOrder(cp.bid, amount, {positionId = bot.longPosId, note = "Hedge Order"})
                end

            --Take profit price reached?
            elseif pamt_l == 0 and cp.close < SubPerc(aep_s, tpTrigger) then
                PlaceExitShortOrder(cp.bid, pamt_s, {type = MarketOrderType, positionId = bot.shortPosId, note = 'Short TP'})
                bot.targetSide = SignalExitPosition
                bot.reset = true

            end
        end
    end

---------------------
-- BALANCE RATIO CHECKING 
    if balRatio > balRatioLimit then
        LogWarning('Maximum Balance Ratio reached. Closing all position and restarting')
        PlotSignalBar(-2, Orange)
        if wtfBalRatio then 
            DeactivateBot('Maximum Balance Ratio Reached', true)
        end
        PlaceExitShortOrder(cp.bid, pamt_s, {positionId = bot.shortPosId, type = MarketOrderType, note = 'Hedge SL'})
        PlaceExitLongOrder(cp.ask, pamt_l, {positionId = bot.longPosId, type = MarketOrderType, note = 'Hedge SL'})
        bot.reset = true
    end

    if balRatio > bot.highestBalRatio then 
        bot.highestBalRatio = balRatio 
    end

---------------------
-- Lets draw the target prices
    Plot(0, 'Go long', goLongPrice, DarkGreen)
    Plot(0, 'Go Short', goShortPrice, Red)
    Plot(0, "Base", bot.basePrice, DarkGray)

---------------------
-- CHARTS
    ChartSetOptions(2, 'Exposure')
        Plot(2, 'Long', pamt_l, {c=Green, s=Step})
        Plot(2, 'Short', pamt_s, {c=Red, s=Step})
        Plot(2, 'Starting Amount', bot.startingAmount, {c=DarkGray, s=Step})
    
    ChartSetOptions(8, 'Balance Monitor')
        --Plot(8, 'Net Balance', netBalance, {c=Orange, s=Step})
        Plot(8, 'Working Balance', workingBalance, {c=White, s=Step})
        Plot(8, 'Unrealized Bot Profit', unrealizedBotProfit, {c=Red, s=Step})
        Plot(8, 'Realized Bot Profit', botProfit, {c=DarkGreen, s=Step})
        Plot(8, 'Bot Balance', botBalance, {c=Yellow, s=Step})
        Plot(8, 'Highest Balance', highestBal, {c=Green, s=Step})
        Plot(8, 'Lowest Balance', lowestBal, {c=Fuchsia, s=Step})

Save('bot', bot)

---------------------
-- REPORT
Finalize(function() 
    local profitPerc = botProfit / startingBalance * 100
    local runProfitPerc = netBotProfit / startingBalance * 100
    
    CustomReport('Running Profit %', runProfitPerc..' %')
    CustomReport('Realized Profit %', profitPerc..' %')
    CustomReport('Highest Bal Ratio', Round(bot.highestBalRatio, 2))
    
end)

0 Comments

Sign in to leave a comment.

No comments yet. Be the first!