Smokybot MK2

stable
By smokyho in Trading Bots Published May 2022 👁 2,704 views 💬 3 comments ★ Staff Pick

Description

-- This bot is optimized for HEDGE mode. -- Suggested main interval is 15 minutes and 1 hour for momentum or ratio 1:4 or 1:6. -- Using 1:1 time interval also works. Who knows might give your better profit. -- Always start with ALL Trade Settings options UN-TICKED to let the bot preparing values. -- Test with default values before changing anything to understand the bot. -- PAY ATTENTION to the log warning if you feel something is off before screaming the bot is not working. -- Do your own test. Testing is time consuming but also rewarding. Short descriptions: 1. Net Balance = Trading balance entry + realized bot PNL + unrealized bot positions PNL 2. Stop at loss = Stop the bot when Net Balance at certain % loss value. 3. Stop at profit = Stop the bot when Net Balance at certain % profit value. 4. Derisking = Reducing the size of position. Kind of stop loss. 5. Trading Balance = Part of total wallet balance allocated for bot to trade. There are 2 ways to use this bot. 1. Not using derisking feature. For this you will never have a realized loss. Bot will keep counter trade while also trading the trend if you do HEDGE mode. You need large value in Balance Divider to hold the position from Balance Ratio reduction. 2. Using derisking feature. Counter trade position will be reduce to the extend being closed depends on your Size Reduction setting and price movement. Bot will have realized loss. TIPS: Every trading pair needs different setting. Even if you find a good setting there is a chance that setting is not working in long term. This is why i put loss limit and profit limit. Here is a tip if you are using derisking: 1. Have a profit limit in mind. For example 10%. Then you 2. Do 4 weeks backtest with profit limit 10% and derisking ON and find a setting that can achieve it in the shortest time. Then run it. When bot reach the profit limit, it will stop. Clean the bot, then start again. Repeat. With this you set aside the profit from each run. If you want to compound you can add some of it to Trading balance. In other word, manual compounding. Hope this bot helps. May the profits be with you!
HaasScript
Log('Tip wallet ERC20/BSC: 0xaa28dE4372CA0a8BC36722886E9749f70DF32382')
EnableHighSpeedUpdates(true)
HideOrderSettings()
HideTradeAmountSettings()

-- This bot is optimized for HEDGE mode. 
-- Suggested main interval is 15 minutes and 1 hour for momentum or ratio 1:4 or 1:6.
-- Using 1:1 time interval also works. Who knows might give your better profit.
-- Always start with ALL Trade Settings options UN-TICKED to let the bot preparing values.
-- Test with default values before changing anything to understand the bot.
-- PAY ATTENTION to the log warning if you feel something is off before screaming the bot is not working.
 
-- Check Market
    local getMarket = PriceMarket()

-- inputs
    InputGroupHeader('Trade Settings')
    local customInterval = InputInterval('00. Momentum Interval', 60, 'Interval for Squeeze Momentum')
    local okLong = Input('01A. Long Entry', false, 'Allow bot to open Long')
    local okProfitL = Input('01B. Long Exit', false, 'Allow bot to exit Long')
    local okShort = Input('02A. Short Entry', false, 'Allow bot to open Short')
    local okProfitS = Input('02B. Short Exit', false, 'Allow bot to exit Short')
    local okReduce = Input('03. BalRatio Reduction', false, 'Allow Bal Ratio based size reduction')
    local okDerisk = Input('04. Risk Reduction', false, 'Allow Signal based size reduction')
    local oneWay = Input('05. Not Hedge', false, 'Select this if the market is NOT HEDGE mode')
    local onlyWeekdays = Input('06. Only Weekdays', false, 'Bot will close any position and not trading during weekend')

    InputGroupHeader('Bot Settings')
    local wtfStop = Input('01. Stop at no position', false, 'Deactivate bot when there is no open position.')
    local clearSlot = Input('02. Recalculate Slot Size', false, 'If activated will ALWAYS calculating slot size. If not activatated slot size will only calculated when there is no open position.')
    local FEL = Input('03. Force Exit Long', false, 'Force exit LONG position')
    local FES = Input('04. Force Exit Short', false, 'Force exit SHORT position')
    local wtfLoss = Input('05. Stop at % LOSS', 0, 'Exit and cancel orders when Net Balance LOSS % below this. 0 is disalbe.')
    local wtfProfit = Input('06. Stop at % PROFIT', 0, 'Stop and exit and cancel orders when Net Balance PROFIT % above this. 0 is disable.')
 
    InputGroupHeader('Backtest Settings')
    local wtfBal = Input('01. Deactivate on Over Budget', false, 'ONLY FOR BACKTEST. Disable bot when Bal. Ratio hit trigger')
    
    InputGroupHeader('Custom Wallet')
    local testWallet = Input('01. Activate Custom Wallet', false, 'Use custom wallet amount. A must in Haaslab')
    local compound = Input('02. Add profit into balance', false, 'Add bot profit into custom wallet balance')
    local testBal = Input('03. Custom Wallet Balance', 0, 'Amount of custom wallet')
 
    InputGroupHeader('Budget')
    local maxCostD = Input('01. Trading Balance ', 0, 'Maximum COST to limit working balance (margin cost + unrealised loss)')
    local leverage = Input('02. Leverage', 50, 'MUST be filled and same as in exchange setting. Important for trading budget')
    local contVal = Input('03. Inverse Contract Value', 10, 'ONLY if bot trading on INVERSE Futures then enter the Contract Value. Ignore if not') 
    
    InputGroupHeader('Safety')
    local reduceTrigger = Input('01. Bal Ratio Trigger', 0.8, 'Ratio between working balance and trading balance to trigger size reduction')
    local reduceSize = Input('02. Size Reduction %', 25, 'SHOULD BE factors of 100. In risk reduction: 1st reduction 25%, 2nd reduction 50% and so on. In balance ratio reduction: balRatio > Bal. Ratio Trigger then fixed 25% reduction')
    local reduceOrderType = InputOrderType('03. Reduction Order Type', MakerOrCancelOrderType, 'The order type for size reduction')
    local profitOut = Input('04. Profit Hodl %', 50, '% of the bot profit taken out or not compounded into trading balance calculation')
 
    InputGroupHeader('Slot Settings')
    local slotCount = Input('01. Slot Count', 1, 'How many orders are constantly kept open on both long and short side')
    local slotSpreadD = Input('02. Slot Spread %', 3, '% based spread value between entry orders if Slot Count > 1')
    local slotSizeD = Input('03. Slot Size ', 0, 'Minimum slot size if Dynamic Slot Size activated. Static amount if Dynamic Slot Size disabled.')
    local autoSlot = Input('04A. Dynamic Slot Size', true, 'DSSize - Dynamically change slot size. Calculated IF there is no position or Recalculate Slot Size ticked.')
    local slotBudget = Input('04B. Balance Divider', 100, 'DSSize - Trading Balance divider to calculate slot size') 
    local slotSizeM = Input('05. Slot Size Multiplier', 1, 'Multiplier for slot size value. Active at a certain condition w/wo DSS')
    local priceDistance = Input('06. Price Distance %', 3, 'Minimum % price distance from filled order to the next. Also % unrealised loss for slot spread modifier if Slot Count > 1.')
    
    InputGroupHeader('Profit Settings')
    local minProfit = Input('01. Minimum Profit %', 0.5, 'Minimum price change % when price movement counter trending position. ')
    local targetProfit = Input('02. Target Profit %', 3, 'Minimum price change % when price movement trending position. ')
    local tpOrderType = InputOrderType('02. TP Order Type', MakerOrCancelOrderType, 'The order type for take-profit')
 

---------------------
-- DATA
    local cp = CurrentPrice()
    local today = CurrentDay()
    local mainInterval = CurrentInterval()

    -- counters 
        local highestP = Load('highestP', 0)
        local lowestP = Load('lowestP', 0)
        local SRCounter = Load('SRCounter', 0)

    -- Current Interval
        local h, l, c, pivot = OptimizedForInterval(mainInterval, function()
            local h = HighPrices(mainInterval)
            local l = LowPrices(mainInterval)
            local c = ClosePrices(mainInterval)
            local pivot = (h + l + c) / 3
 
            return h, l, c, pivot
            end)
        
        local fastOSCI = ArrayGet(RSI(pivot, 13), 1) 
        local slowOSCI = ArrayGet(RSI(pivot, 55), 1)
        local mAVG = ArrayGet(EMA(pivot, 21), 1) 
        local atr = ArrayGet(ATR(h, l, c, 21), 1)
    
    -- Custom Interval
        local cCustom = ClosePrices(customInterval)
        local sqz = CC_SQZMOM_LB_Ext(cCustom, 20, 2, 20, 1.5)
        local sqz1 = ArrayGet(sqz, 1)
        local sqz2 = ArrayGet(sqz, 2)
        
        local osciUP = fastOSCI > slowOSCI 
        local osciTOP = fastOSCI / slowOSCI > 1.236
        local osciDOWN = slowOSCI > fastOSCI
        local osciBTM = slowOSCI / fastOSCI > 1.236
        local sqzUP = sqz1 > sqz2
        local sqzDOWN = sqz1 < sqz2
 

---------------------
-- POSITIONS
            local hedge_longPosId = Load('hedge_longPosId', NewGuid())
            local hedge_shortPosId = Load('hedge_shortPosId', NewGuid())
 
            local dir_l = GetPositionDirection(hedge_longPosId)
            local aep_l = GetPositionEnterPrice(hedge_longPosId)
            local pamt_l = GetPositionAmount(hedge_longPosId)
            local delta_l = pamt_l > 0 and (cp.close - aep_l) / aep_l * 100 or 0
            local proi_l = delta_l * leverage 
 
            local dir_s = GetPositionDirection(hedge_shortPosId)
            local aep_s = GetPositionEnterPrice(hedge_shortPosId)
            local pamt_s = GetPositionAmount(hedge_shortPosId)
            local delta_s = pamt_s > 0 and (aep_s - cp.close) / aep_s * 100 or 0
            local proi_s = delta_s * leverage
 
        -- manage position ids
            if pamt_l == 0 and IsPositionClosed(hedge_longPosId) then
                if IsAnyOrderOpen(hedge_longPosId) then
                    CancelAllOrders(hedge_longPosId)
                else
                    hedge_longPosId = NewGuid()
                    dir_l = GetPositionDirection(hedge_longPosId)
                    aep_l = GetPositionEnterPrice(hedge_longPosId)
                    pamt_l = GetPositionAmount(hedge_longPosId)
                    proi_l = delta_l * leverage 
                end
            end
            
            if pamt_s == 0 and IsPositionClosed(hedge_shortPosId) then
                if IsAnyOrderOpen(hedge_shortPosId) then
                    CancelAllOrders(hedge_shortPosId)
                else
                    hedge_shortPosId = NewGuid()
                    dir_s = GetPositionDirection(hedge_shortPosId)
                    aep_s = GetPositionEnterPrice(hedge_shortPosId)
                    pamt_s = GetPositionAmount(hedge_shortPosId)
                    proi_s = delta_s * leverage
                end
            end
        
        -- get pos id
            local getPositionId = function(isLong)
                return isLong and hedge_longPosId or hedge_shortPosId
            end
 
---------------------
-- WALLET CHECK
    local profitLabel = ProfitLabel()
    if profitLabel == nil then profitLabel = QuoteCurrency() end
 
    -- inverse or not
        if profitLabel == 'USD' or profitLabel == 'USDT' or profitLabel == 'BUSD' then
            isInverse = false 
        else
            isInverse = true 
        end
 
    -- check balance usage
        if pamt_l > 0 then
            usedLong = isInverse and ((pamt_l * contVal) / leverage) / cp.close or (pamt_l * aep_l) / leverage
            getProfitL = isInverse and (cp.close - aep_l) * (leverage * usedLong) / cp.close or (cp.close - aep_l) * pamt_l
        else 
            getProfitL = 0
            usedLong = 0
        end
 
        if pamt_s > 0 then
            usedShort = isInverse and ((pamt_s * contVal) / leverage) / cp.close or (pamt_s * aep_s) / leverage
            getProfitS = isInverse and (aep_s - cp.close) * (leverage * usedShort) / cp.close or (aep_s - cp.close) * pamt_s
        else 
            getProfitS = 0
            usedShort = 0
        end
 
        local getProfit = getProfitL + getProfitS
        local botProfit = GetBotProfit()
    
    -- balance warning
        local xchangeBal = testWallet and testBal or WalletAmount(AccountGuid(), profitLabel)
        local walletBal = compound and (xchangeBal + botProfit) or xchangeBal
        local workBal = usedLong + usedShort - getProfit
        local botBalance = maxCostD + botProfit
        local balRatio = maxCostD > 0 and workBal / botBalance or 0
        local netBalance = maxCostD + botProfit + getProfit
        if balRatio > 0.5 and balRatio < 0.8 then LogWarning('Working balance is > 50% of Budget!!!') end
        if balRatio > 0.8 then LogWarning('Working balance is > 80% of Budget!!!') end
 
        local BRCounter = Load('BRCounter', 0)
        if balRatio > BRCounter then Save('BRCounter', balRatio) end
 

---------------------        
-- WTF
    if onlyWeekdays then
        if today == 1 or today == 7 then 
            FEL = true 
            FES = true
            Log('Not trading on weekend')
        end
        Log('Bot will not trading on weekend', Yellow)
    end

    if wtfBal then
        if balRatio > reduceTrigger then
            DeactivateBot('Deactivated because over budget', true)
        end
        Log('STOP at over budget safety activated. Is this a backtest ?', Yellow)
    end

    if wtfLoss > 0 then
        local lossLimit = SubPerc(maxCostD, wtfLoss)
        if netBalance <= lossLimit then
            wtfStop = true
            FEL = true 
            FES = true
            LogWarning('Loss < Limit. Stopping soon.') 
        end
        Log('Loss limit activated at '..wtfLoss..'% or Net Balance '..lossLimit..' '..profitLabel, DarkGreen)
    end

    if wtfProfit > 0 then 
        local profitLimit = AddPerc(maxCostD, wtfProfit)
        if netBalance >= profitLimit then
            wtfStop = true
            FEL = true 
            FES = true
            LogWarning('Profit > Limit. Stopping soon.') 
        end
        Log('Profit limit activated at '..wtfProfit..'% or Net Balance '..profitLimit..' '..profitLabel, DarkGreen)
    end

    if wtfStop then
        local longNull = pamt_l == 0
        local shortNull = pamt_s == 0
        if longNull and shortNull then
            DeactivateBot('Deactivated by No Position', true)
        else
            LogWarning('Will deactivate on No Position, waiting...maybe next second, maybe never :)')
        end
        Log('Deactivate on No Position is active.', Yellow)
    end

    if FEL then 
        okLong = false
        okProfitL = false
        Log('FORCE EXIT LONG POSITION ACTIVATED', Red) 
    end 
    
    if FES then
        okShort = false
        okProfitS = false
        Log('FORCE EXIT SHORT POSITION ACTIVATED', Red) 
    end


---------------------
-- DYNAMICS
    local LLP = LastLongPrice()
    local longDeriskM = IfElse(Load('longDerisk', 1) > 100 / reduceSize, 100 / reduceSize, Load('longDerisk', 1)) 
 
    local LSP = LastShortPrice()    
    local shortDeriskM = IfElse(Load('shortDerisk', 1) > 100 / reduceSize, 100 / reduceSize, Load('shortDerisk', 1))
  
    -- entry exit price 
        local longPrice = c - ((h - c) * 0.275)
        local shortPrice = c + ((h - c) * 0.275)
    
        local exitPriceL = c + ((h - c) * 0.275) 
        local exitPriceS = c - ((h - c) * 0.275)
 
        --Log('Last Price Long: '..LLP..' | Short: '..LSP)
        --Log('Exit Price -> Long: '..exitPriceL..' | Short: '..exitPriceS)
        --Log('Enter Price -> Long: '..longPrice..' | Short: '..shortPrice)
 
    -- trading balance
        local maxCost = botProfit > 0 
                        and botBalance - (SubPerc(botProfit, profitOut))
                        or botBalance  
 
        local okBalance = walletBal >= maxCost          
    
    -- slot size
        if autoSlot then
            local costCalc = maxCost / slotBudget
 
            if pamt_l == 0 or clearSlot then
                local slotSize = isInverse and costCalc * 0.5 * longPrice * leverage / contVal or costCalc * leverage / longPrice
                slotSizeL = slotSize > slotSizeD and slotSize or slotSizeD
                Save('slotSizeL', slotSizeL)
            else 
                slotSizeL = Load('slotSizeL', 0)
            end
 
            if pamt_s == 0 or clearSlot then
                local slotSize = isInverse and costCalc * shortPrice* leverage / contVal or costCalc * leverage / shortPrice
                slotSizeS = slotSize > slotSizeD and slotSize or slotSizeD
                Save('slotSizeS', slotSizeS)
            else
                slotSizeS = Load('slotSizeS', 0)                               
            end
        else
            slotSizeL = slotSizeD 
            slotSizeS = slotSizeD 
        end
 
    -- slot size modifier
        if fastOSCI < 50 and slowOSCI < 50 then
            slotSizeL = slotSizeL * slotSizeM
        else
            slotSizeL = slotSizeL
        end
 
        if fastOSCI > 50 and slowOSCI > 50 then
            slotSizeS = slotSizeS * slotSizeM
        else
            slotSizeS = slotSizeS
        end
    
    -- TP % modifier
        if osciUP and sqzUP then
            TPL = targetProfit
        else
            TPL = minProfit
        end
 
        if osciDOWN and sqzDOWN then
            TPS = targetProfit
        else
            TPS = minProfit
        end
 
        --Log('Slot Size -> Long: '..slotSizeL..' | Short: '..slotSizeS)
 
    -- spread 
        if slotCount > 1 then
            -- long spread
            if delta_l < (-priceDistance) then
                slotSpreadL = slotSpreadD * 2
            else
                slotSpreadL = slotSpreadD
            end
 
            --short spread
            if delta_s < (-priceDistance) then
                slotSpreadS = slotSpreadD * 2
            else
                slotSpreadS = slotSpreadD
            end
            --Log('Slot Spread Long: '..Round(slotSpreadL, 2)..'% | Short: '..Round(slotSpreadS, 2)..'%')
        else 
            slotSpreadL = slotSpreadD
            slotSpreadS = slotSpreadD
        end
 

---------------------
-- EXECUTION
    --LONG
        local mustLong = okLong
                            and okBalance
                            and sqzUP
                            and osciUP
                            and IfElse(oneWay, pamt_s == 0, true) 

        local longOpen = mustLong 
                            and cp.close > longPrice  
                            and c > longPrice 
 
        local okLongDerisk = okDerisk
                                and pamt_l > 0
                                and sqzDOWN
 
        local longExit = okProfitL
                            and pamt_l > 0
                            and exitPriceL >= AddPerc(aep_l, TPL)
                            and exitPriceL >= aep_l + atr
                            and cp.close < exitPriceL
                            
    --SHORT
        local mustShort = okShort
                            and okBalance
                            and sqzDOWN
                            and osciDOWN
                            and IfElse(oneWay, pamt_l == 0, true)

        local shortOpen = mustShort
                            and cp.close < shortPrice
                            and c < shortPrice
 
        local okShortDerisk = okDerisk
                                and pamt_s > 0
                                and sqzUP
 
        local shortExit = okProfitS
                            and pamt_s > 0
                            and exitPriceS <= SubPerc(aep_s, TPS)
                            and exitPriceS <= aep_s - atr
                            and cp.close > exitPriceS


---------------------
-- CORE LOGIC HEDGE MODE
        -- ENTRY
            local slot = function(isLong, index, amount, spread, canPlace)
                local prefix = isLong and 'L' or 'S'
                local name = prefix .. index
                local cmd = isLong and PlaceGoLongOrder or PlaceGoShortOrder
                local price = isLong
                        and longPrice
                        or shortPrice
                local spr = spread * (index - 1)
                local posId = getPositionId(isLong)
                local aep = isLong and aep_l or aep_s
                local TOPB = TradeOncePerBar(mainInterval, posId)
 
                -- get price                    
                    if aep > 0 then
                        if isLong and longPrice >= SubPerc(LLP, priceDistance) then 
                            canPlace = false 
                        end 
 
                        if not isLong and shortPrice <= AddPerc(LSP, priceDistance) then 
                            canPlace = false 
                        end
                    end
 
                if index != 1 then 
                    price = isLong
                                and SubPerc(price, spr)
                                or AddPerc(price, spr)
                end
 
                local oid = Load(name..'oid', '') -- order id
 
                if oid != '' then
                    local order = OrderContainer(oid)
 
                    if order.isOpen then
                        if not canPlace then
                            CancelOrder(oid)
                            LogWarning('Not allowed right now '..name)
                        end
                    else 
                        oid = '' 
                    end
                else
                    if canPlace and TOPB then
                        SetFee(MakersFee())
                        oid = cmd(price, amount, {type = MakerOrCancelOrderType, note = name, timeout = mainInterval * 60, positionId = posId})
                    end
                end
 
                Save(name..'oid', oid)
            end            
 
            -- variables
                for i = 1, slotCount do
                    slot(true, i, slotSizeL, slotSpreadL, longOpen) -- long slot
                end
    
                for i = 1, slotCount do
                    slot(false, i, slotSizeS, slotSpreadS, shortOpen) -- short slot
                end
 
        -- EXIT
            local updateTakeProfit = function(isLong, currentSize, canExit)        
                local prefix = isLong and 'Long' or 'Short'
                local name = prefix .. ' Exit'
                local oid = Load(prefix .. 'tp_oid', '')
                local posId = getPositionId(isLong)
 
                if oid != '' then
                    local order = OrderContainer(oid)
 
                    if order.isOpen then
                        if not canExit then
                            CancelOrder(oid)
                            LogWarning('Exit cancelled '..name)
                        end
                    else
                        oid = ''
                    end
                else
                    if isLong and canExit then
                        SetFee(tpOrderType == MarketOrderType and TakersFee() or MakersFee())
                        oid = PlaceExitPositionOrder({price = exitPriceL, type = tpOrderType, note = name, timeout = mainInterval * 60, positionId = hedge_longPosId})
                    end
                    
                    if not isLong and canExit then
                        SetFee(tpOrderType == MarketOrderType and TakersFee() or MakersFee())
                        oid = PlaceExitPositionOrder({price = exitPriceS, type = tpOrderType, note = name, timeout = mainInterval * 60, positionId = hedge_shortPosId})  
                    end
                end
 
                Save(prefix .. 'tp_oid', oid)
            end
 
            -- variables
                updateTakeProfit(true, pamt_l, longExit or FEL)
                updateTakeProfit(false, pamt_s, shortExit or FES)
 
        -- Balance Ratio REDUCTION
            local updatePositionManagement = function(isLong, currentSize, sizeLimit, canReduce)
                local prefix = isLong and 'Long' or 'Short'
                local name = prefix .. ' Size Reduction'
                local oid = Load(prefix .. 'pos_oid', '')
                local posId = getPositionId(isLong)
                local amount = SubPerc(currentSize, 100 - reduceSize) -- take X% of position
                local price = isLong
                        and cp.ask
                        or cp.bid
                local cmd = isLong
                        and PlaceExitLongOrder
                        or PlaceExitShortOrder
                local timer = Load(prefix .. 'pos_timer', Time())
 
                if oid != '' then
                    local order = OrderContainer(oid)
 
                    if order.isOpen then                        
                        if not canReduce then
                            CancelOrder(oid)
                            LogWarning('Reduction cancelled '..name)
                        end
                    else
                        sizeRed = 1
                        Save('SRCounter', SRCounter + sizeRed)
                        oid = ''
                    end
                else
                    if canReduce and Time() >= timer then
                        CancelAllOrders()
                        SetFee(reduceOrderType == MarketOrderType and TakersFee() or MakersFee())
                            oid = cmd(price, amount, {type = reduceOrderType, note = name, timeout = 6000, positionId = posId})
                        timer = Time() + 60 -- 1min   
                    end
                end
 
                Save(prefix .. 'pos_oid', oid)
                Save(prefix .. 'pos_timer', timer)
            end
 
            -- variables
                updatePositionManagement(true, pamt_l, maxCost, okReduce and pamt_l > 0 and balRatio > reduceTrigger and delta_l < delta_s)
                updatePositionManagement(false, pamt_s, maxCost, okReduce and pamt_s > 0 and balRatio > reduceTrigger and delta_s < delta_l)
 
        -- Derisking REDUCTION
            local derisking = function(isLong, currentSize, reduceM, prevLP, canReduce)
                local prefix = isLong and 'Long '..longDeriskM or 'Short '..shortDeriskM
                local name = prefix .. ' Size Derisking'
                local oid = Load(prefix .. 'derisk_oid', '')
                local posId = getPositionId(isLong)
                local amount = SubPerc(currentSize, 100 - (reduceM * reduceSize)) -- take X% of position
                local price = isLong
                        and cp.ask
                        or cp.bid
                local cmd = isLong
                        and PlaceExitLongOrder
                        or PlaceExitShortOrder
                local TOPB = TradeOncePerBar(mainInterval, posId)
 
                -- amount check 
                    if amount < MinimumTradeAmount(getMarket, cp.close) then 
                        canReduce = false 
                    end
 
                if oid != '' then
                    local order = OrderContainer(oid)
                     
                    if order.isOpen then
                        if not canReduce then
                            CancelOrder(oid)
                            LogWarning('Reduction cancelled '..name)
                        end
                    else
                        if isLong then 
                            Save('longDerisk', longDeriskM + 1)
                        else 
                            Save('shortDerisk', shortDeriskM + 1)
                        end
                        oid = '' 
                    end
                else
                    if canReduce and TOPB then
                        CancelAllOrders()
                        SetFee(reduceOrderType == MarketOrderType and TakersFee() or MakersFee())
                        if isLong then 
                            oid = cmd(price, amount, {type = reduceOrderType, note = name, timeout = mainInterval * 60, positionId = hedge_longPosId})
                        elseif not isLong then    
                            oid = cmd(price, amount, {type = reduceOrderType, note = name, timeout = mainInterval * 60, positionId = hedge_shortPosId})
                        end                        
                    end
                end
                
                if currentSize == 0 then 
                    if isLong then 
                        Save('longDerisk', 1) 
                    else 
                        Save('shortDerisk', 1)
                    end 
                end 
 
                Save(prefix .. 'derisk_oid', oid)
            end
 
            -- variables
                derisking(true, pamt_l, longDeriskM, LLP, okLongDerisk)
                derisking(false, pamt_s, shortDeriskM, LSP, okShortDerisk)
 
    -- Positions Data
        if pamt_l > 0 then
            Log('LONG Data > ROI: '..Round(GetPositionROI(hedge_longPosId, exitPriceL), 2)..'% | Entry: '..aep_l..' | Exit: '..exitPriceL)
        end
        if pamt_s > 0 then 
            Log('SHORT Data > ROI: '..Round(GetPositionROI(hedge_shortPosId, exitPriceS), 2)..'% | Entry: '..aep_s..' | Exit: '..exitPriceS)
        end
 
 
---------------------
-- DATA SAVING
    Save('hedge_longPosId', hedge_longPosId)
    Save('hedge_shortPosId', hedge_shortPosId)
 
    if botProfit > highestP then 
        Save('highestP', botProfit)
    elseif botProfit < lowestP then 
        Save('lowestP', botProfit) 
    end

 
--------------------- 
-- PLOT
    -- AEP Plot
        if aep_l > 0 then
            local posId = getPositionId(true)
            Plot(0, 'AvgEP Long', aep_l, {c=Teal, id=posId, w=2})
        end
    
        if aep_s > 0 then
            local posId = getPositionId(false)
            Plot(0, 'AvgEP Short', aep_s, {c=Purple, id=posId, w=2})
        end
 
    Plot(0, 'mAVG', mAVG, {c=White})  
    Plot(0, 'Long', SubPerc(mAVG, priceDistance), {c=DarkGray})  
    Plot(0, 'Short', AddPerc(mAVG, priceDistance), {c=DarkGray})    
    
    ChartSetOptions(1, 'Exposure')
    local lineLong = IfElse(pamt_l > 0, pamt_l, 0)
    local lineShort = IfElse(pamt_s > 0, -pamt_s, 0)
    Plot(1, 'Longs', lineLong, {c=Green, s=Step})
    Plot(1, 'Shorts', lineShort, {c=Red, s=Step})
    
    ChartSetOptions(2, 'Balance Monitor')
    Plot(2, 'Net Balance', netBalance, {c=Orange, s=Step})
    Plot(2, 'Trading Balance', maxCost, {c=White, s=Step})
    Plot(2, 'WorkBal', workBal, {c=Red, s=Step})
    Plot(2, 'Bot Profit', botProfit, {c=DarkGreen, s=Step})
    Plot(2, 'Bot Balance', botBalance, {c=Yellow, s=Step})
    --Plot(2, 'Exchange Balance', walletBal, {c=Orange, s=Step})
 
    ChartSetOptions(4, 'Oscillator')
    Plot(4, 'Fast', fastOSCI, {c=White})
    Plot(4, 'Slow', slowOSCI, {c=Red})
    Plot(4, 'Mid', 50, {c=DarkGray})

    ChartSetOptions(5, 'Squeeze Momentum')
    PlotHistogram(Plot(5, 'SQZ', sqz, Green), Red)

    Log('Size Reduction: '..SRCounter..' times')
 
 
---------------------
-- FINAL REPORT
    Finalize(function()
        CustomReport('Current Balance Ratio', Round(100 * balRatio, 2)..'%')
        CustomReport('Highest Balance Ratio', Round(100 * BRCounter, 2)..'%')
        CustomReport('Size Reduction', SRCounter..' times')
        CustomReport('Final Wallet Balance', Round(walletBal, 5)..' '..profitLabel)
        CustomReport('Highest Profit', Round(highestP, 5)..' '..profitLabel)
        CustomReport('Lowest Profit', Round(lowestP, 5)..' '..profitLabel)
        if testWallet then
            local profitPercent = Round(PercentageChange(maxCostD, botBalance), 2) 
            CustomReport('Profit %: ', profitPercent..'%')
            CustomReport('Profit to Highest Bal Ratio', Round(profitPercent / (100 * BRCounter), 2))
        end
        
    end)
 
---------------------
 
    Log('Profit Monitor -> Current: '..Round(botProfit, 5)..' '..profitLabel..' | Highest: '..Round(highestP, 5)..' '..profitLabel..' | Lowest: '..Round(lowestP, 5)..' '..profitLabel)
    Log('Balance Monitor -> Wallet: '..Round(walletBal, 5)..' '..profitLabel..' | Net: '..Round(netBalance, 5)..' '..profitLabel..' | Trading: '..Round(maxCost, 5)..' '..profitLabel..' | Working: '..Round(workBal, 5)..' '..profitLabel..' | Ratio: '..Round(balRatio, 3))
    -- BALANCE WARNING
        if not okBalance then
            LogWarning('TRADING BALANCE < EXCHANGE BALANCE')
        end
        if maxCostD == 0 then 
            LogWarning('Please enter trading balance')
        end
 
--local VPM = CC_VPM3()
Log('SMOKYBOT MK2')
Log(' ')

3 Comments

Sign in to leave a comment.

K
Katerin almost 4 years ago

Hi
"Then run it. When bot reach the profit limit, it will stop. Clean the bot, then start again. Repeat."

Is there any command to add make it clean and start and repeat again ?

S
smokyho almost 4 years ago

Hello,
thank you for using my bot1
Yes the clean after profit should be automatic but it is not because unfortunately there is no command to clean the bot. I am already have something in mind as work around but still testing other things. I will add this into the next version.

H
Hiromatsu almost 4 years ago

Edit: solved