Smokybot

stable
By smokyho in Trading Bots Published February 2022 👁 4,484 views 💬 10 comments ★ Staff Pick

Description

Hi guys! After years of learning and testing and coping with lockdown and other IRL stuff, here i am back with a new bot script for the community. Smokybot is a trend following bot that using MA and Oscillators. It also has budget management just like my version of Phsai's SMM. It also has stop loss so relatively "safe" to leave it run forever...hopefully lol. Hopefully the tool tips could explain what is what and what is for. If not, please find me in Haasonline DIscord and i would be grateful if the others could help explore and support other users. Last but not least, thank you Phsai for teaching and guiding me in using Haasscript. Little bit details 1. You need to have these installed https://www.haasscripts.com/t/pshaicmd-sqzmom-extended/ and https://www.haasscripts.com/t/haasbot-utilities-vpm3-create_adjust_close-virtual-position-management-for-running-haasbots/ 2. Compatible with Hedge and One-Way market. If you are not trading in hedge market or in one-way market, tick Not Hedge 3. Trading Balance is in profit currency. USDT/BUSD in those market and crypto in Inverse. 4. Suggested time interval is 15 minutes. 5. Always start with ALL Trade Settings options UN-TICKED to let the bot preparing values. 6. Test with default values before changing anything to understand the bot. If the default value result is not satisfying, find the best one using HaasLab. 8 weeks backtest is highly recommended. 7. Because of the dynamic part of the slot size you need to use custom wallet amount in HaasLab. 8. PAY ATTENTION to the log warning if you feel something is off before screaming the bot is not working. May the Profits be with you! *Backtest was Bybit USDT Futures BIT/USDT 4 Weeks on Feb 2 22 Version: 2022.1.25
HaasScript
Log('Tip wallet ERC20/BSC: 0xaa28dE4372CA0a8BC36722886E9749f70DF32382')
EnableHighSpeedUpdates(true)
HideOrderSettings()
HideTradeAmountSettings()

-- Suggested time interval is 15 minutes.
-- 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 screeaming the bot is not working.

-- Check Market
    local getMarket = PriceMarket()
 
-- inputs
    InputGroupHeader('Trade Settings')
    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, 'Selec this if the market is NOT HEDGE mode')

    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.')

    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 slotSizeD = Input('02. Slot Size ', 0, 'Minimum slot size if Dynamic Slot Size activated. Static amount if Dynamic Slot Size disabled.')
    local autoSlot = Input('03A. Dynamic Slot Size', true, 'DSSize - Dynamically change slot size. Calculated IF there is no position or Recalculate Slot Size ticked.')
    local slotBudget = Input('03B. Balance Divider', 50, 'DSSize - Trading Balance divider to calculate slot size') 
    local slotSizeM = Input('04. Slot Size Multiplier', 2, 'Multiplier for slot size value. Active at a certain condition w/wo DSS')
    local slotSpreadD = Input('05. Slot Spread %', 0.5, '% based spread value between entry orders')
    local priceDistance = Input('06. Price Distance %', 2, '% price movement for: modifying spread % if slot count > 1 and price movement range.')
    
    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 %', 2, '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()
    -- Current Interval
        local mainInterval = CurrentInterval()
        local h, l, c, pivot = OptimizedForInterval(0, function()
            local h = HighPrices(0)
            local l = LowPrices(0)
            local c = ClosePrices(0)
            local pivot = (h + l + c) / 3

            return h, l, c, pivot
            end)
        
        local fastOSCI = RSI(c, 13)
        local slowOSCI = RSI(c, 55)
        local sqz = CC_SQZMOM_LB_Ext(c, 20, 2, 20, 1.5)
        local sqz1 = ArrayGet(sqz, 2)
        local mAVG = EMA(pivot, 21)
        local atr = ATR(h, l, c, 21)
        
        local osciUP = fastOSCI > slowOSCI 
        local osciTOP = fastOSCI / slowOSCI > 1.236
        local osciDOWN = slowOSCI > fastOSCI
        local osciBTM = slowOSCI / fastOSCI > 1.236
        local sqzUP = sqz > sqz1
        local sqzDOWN = sqz < sqz1
        --Log('sqz '..sqz..' sqz1 '..sqz1)

        -- 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
         
        -- counters 
            local highestP = Load('highestP', 0)
            local lowestP = Load('lowestP', 0)
            local SRCounter = Load('SRCounter', 0)
 
        -- 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
        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


---------------------
-- DYNAMICS
    local LLP = LastLongPrice()
    local firstL = Load('firstL', 0)
    local longDeriskM = Load('longDerisk', 1)

    local LSP = LastShortPrice()    
    local firstS = Load('firstS', 0)
    local shortDeriskM = Load('shortDerisk', 1)

    --Log('firstL '..firstL..' firstS '..firstS)

    -- entry exit price 
        local longPrice = c - ((h - c) * 0.275)
        local shortPrice = c + ((h - c) * 0.275)
    
        local exitPriceL = aep_l + (3 * atr) 
        local exitPriceS = aep_s - (3 * atr) 

        --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 - (botProfit * profitOut / 100)
                        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 * 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 multiplying
        if osciUP and sqzUP then
            slotSizeL = slotSizeL * slotSizeM
            TPL = targetProfit
        else
            slotSizeL = slotSizeL
            TPL = minProfit
        end

        if osciDOWN and sqzDOWN then
            slotSizeS = slotSizeS * slotSizeM
            TPS = targetProfit
        else
            slotSizeS = slotSizeS
            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 cp.close > longPrice  
                            and c > longPrice 
                            and IfElse(oneWay, pamt_s == 0, true) 
        local longOpen = mustLong 
                            and not osciTOP
                            and longPrice >= mAVG
                            and longPrice <= AddPerc(mAVG, priceDistance)

        local okLongDerisk = okDerisk
                                and pamt_l > 0
                                and c < SubPerc(mAVG, priceDistance)

        local longExit = okProfitL
                            and pamt_l > 0
                            and exitPriceL > AddPerc(aep_l, TPL)
                            and cp.close < exitPriceL
                            
    --SHORT
        local mustShort = okShort
                            and okBalance
                            and cp.close < shortPrice
                            and c < shortPrice
                            and IfElse(oneWay, pamt_l == 0, true)
        local shortOpen = mustShort
                            and not osciBTM
                            and shortPrice <= mAVG
                            and shortPrice >= SubPerc(mAVG, priceDistance)

        local okShortDerisk = okDerisk
                                and pamt_s > 0
                                and c > AddPerc(mAVG, priceDistance)

        local shortExit = okProfitS
                            and pamt_s > 0
                            and exitPriceS < SubPerc(aep_s, TPS)
                            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, slotSpreadL) then 
                            canPlace = false 
                        end 

                        if not isLong and shortPrice <= AddPerc(LSP, slotSpreadS) 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
                    elseif order.isFilled then 
                        if isLong and firstL == 0 then
                            Save('firstL', order.price)
                        elseif not isLong and firstS== 0 then 
                            Save('firstS', order.price)
                        end
                        oid = ''
                    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 timer = Load(prefix .. 'tp_timer', 0)
                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)
                Save(prefix .. 'tp_timer', timer)
            end

            -- variables
                updateTakeProfit(true, pamt_l, longExit and delta_l > minProfit)
                updateTakeProfit(false, pamt_s, shortExit and delta_s > minProfit)
 
        -- 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 pamt_l == 0 then 
        Save('firstL', 0)
    end 
    if pamt_s == 0 then 
        Save('firstS', 0)
    end

    if botProfit > highestP then 
        Save('highestP', botProfit)
    elseif botProfit < lowestP then 
        Save('lowestP', botProfit) 
    end

---------------------        
-- WTF
    if wtfStop then
        local longNull = pamt_l == 0
        local shortNull = pamt_s == 0
        if longNull and shortNull then
            DeactivateBot('Deactivate on No Position is active', true)
        else
            LogWarning('Will deactivate on No Position, waiting...maybe next second, maybe never :)')
        end
    end
 
    if wtfBal then
        if balRatio > reduceTrigger then
            DeactivateBot('Over Budget', true)
        end
    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, '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, 'Top', 60, {c=Green})
    Plot(4, 'Mid', 50, {c=DarkGray})

    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..' | 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 2022.1.25')
Log(' ')

10 Comments

Sign in to leave a comment.

A
amnesia about 4 years ago

could you recomend safe settings for deposit usdt 500 ? no liquidation and small gain 2+% day
coins? how many pairs?

N
NjoOoO about 4 years ago

Thanks for the script

A
amnesia about 4 years ago

do you have good results? Share please.

N
NjoOoO about 4 years ago

i stated testing it on simulated account. lets wait and see :)

A
amnesia about 4 years ago

ok! give me results please when u finish

T
Trentacles about 4 years ago

Have been following this script for a while... settings need creative inputs when using on inverse accs (profit in Crypto) to get ANY backtest results... here's what I mean. Regular leverage accs profit in USDT so the custom wallet and trading balance settings are calculated in USDT and display correctly in USDT even though it uses BTC as the quantity for contract sizes, AWESOME works correctly ...whereas inverse lev accs profit in crypto so the custom wallet and trading balance are calculated as crypto and inverse trading amount as USD per contract and don't display correctly in BTC because it uses usd as the quantity for contracts (the inverse trading amount setting) and reads the custom and trading balances as BTC amounts ... It will correctly calculate BTC profit but the wallet totals will be wrong extremely wrong. If you enter actual BTC amounts instead of USD/T in the custom or trading balance settings the bot won't be able to execute orders because it states the contract size is to small (below exchange min)... and if you add USD amounts in those settings it thinks you have that many BTC in BTC. Normal lev acc $1000 in custom and trading balance settings and it works on $1000... Inverse lev acc 1000 in both custom and trading balance settings and it works on you have 1000 BTC... ok so how about I say 0.2 for custom and trading bal settings on a inverse x10 leverage acc and it won't make a trade nor backtest results because it's below min contract size (for an inverse acc). It's probably unavoidable in the code and the calculations of profit for inverse accs will be sound as long as you ignore the wallet balance figure and just look at the additional coin it added to amount you put in...the min amount for inverse accs is $10 USD (which the bot will show as 10BTC in your results). Only putting in a inverse amount in settings also yields no results. Just be sure to check your settings and play around with them until you receive realistic profit amounts... $1000 will NOT YEILD YOU 100+ BTC over a week lol.. the bot isn't magic. returns will be in decimal amounts.

S
Sharpnel_89 almost 4 years ago

got a question, does it also happen to others when your order is in good profits it does not exit the trade and let it ru all the way back again while in the logs it supassed your exit price (by a mile)

J
JeffVernon almost 4 years ago

Thanks for the great contribution!

S
smokyho almost 4 years ago

Sorry for the late reply.
so yeah, that is a coding mistake in the taking profit part. the solution would be:
1. manually close the position in the exchange then either use VPM to close the position in the bot or stop and clean the bot
2. use the later version which does not have this problem.

S
smokyho almost 4 years ago

always a pleasure and thanks for the amazing platform!