[pshaiBot] Nerve-wrecker

stable
By pshai in Trading Bots Published January 2021 👁 1,797 views 💬 0 comments

Description

Hi community! Let me introduce you to the Nerve-Wrecker! Run some backtests with it and see where the name comes from.. ;) The bot utilizes customizable moving averages, ADX, ATR and stochastics to do its thing and has a wide range of how it can be used; anything between turtle, swing and scalp trading. Note regarding custom leverage input: set this to the max leverage used on your desired market (for example, 125 on Binance Futures BTC/USDT), or 1 if you are using this on a spot market. The trading rules are as follows: Go long if... - Price is above higher timeframe MA - ADX is above its signal line - CCI is below its upper extreme (by default range is set to 140, which means upper extreme is 140) - Lower timeframe MA is above higher timeframe MA - Stochastics give us a crossover signal below its lower level (by default range is set to 10, which means lower level is 40) Go short if... - Price is below higher timeframe MA - ADX is above its signal line - CCI is above its lower extreme (by default range is set to 140, which means lower extreme is -140) - Lower timeframe MA is below higher timeframe MA - Stochastics give us a crossunder signal above its upper level (by default range is set to 10, which means upper level is 60) When position is opened, the bot will record the ROI % based value using the current ATR value. This will be used as the start % for the profit trailer it uses for exits. You can also use a stop-loss based on this same ATR value by setting [3.6. Stop-Loss Multiplier] higher than 0 (SL not used when set to 0). Custom report statistics include stats for successful trades, stop-losses hit, the ratio between these 2 and all the Trading Report stats. Required scripts: - [pshaiCmd] HighSpeedPrices Happy trading, and may the profits be with you. ~pshai NOTE: Script uses GetTradingReport which is only available in BETA version of HTS at the time being. If you do not want to update, comment the related lines of code: 227 - 240.
HaasScript
EnableHighSpeedUpdates(true)

local stoch_configs = {
    '5/2/3',
    '5/2/6',
    '5/2/9',
    '14/3/3',
    '14/3/6',
    '14/3/9',
    '21/3/3',
    '21/3/6',
    '21/3/9'
}

local get_stoch_configs = function(config)
    local split = StringExplode(config, '/')
    return {
        k = Parse(split[1], NumberType),
        s = Parse(split[2], NumberType),
        d = Parse(split[3], NumberType)
    }
end

InputGroupHeader('General Settings')
local max_leverage = Input('1. Leverage', 125)
local tf_trend = InputInterval('2.1. Trend Timeframe', 60)
local tf_trend_update = InputInterval('2.2. Trend Update Interval', 15)
local tf_trade = InputInterval('3.1. Trading Timeframe', 5)
local tf_trade_update = InputInterval('3.2. Trading Update Interval', 1)


InputGroupHeader('Indicator Settings')
local cci_len = Input('1.1. CCI Length', 20)
local cci_u = Input('1.2. CCI Range', 140, 'Sets the range for the CCI. New long entries are not allowed if CCI > X and short entries are not allowed if CCI < -X.')
local cci_l = -cci_u
local stoch_config = InputOptions('2.1. Stoch Config', stoch_configs[9], stoch_configs)
local stoch_r = Input('2.2. Stoch Range', 10, 'Sets the size of the stochastics range. If range is set to 10, then short entry signals (cross-under) must occur above above 60 (50 + 10) and long entry signals (cross-over) below 40 (50 - 10).')
local stoch_u = 50 + stoch_r
local stoch_l = 50 - stoch_r
local atr_len = Input('3.1. ATR Length', 32, 'Sets the length of the ATR on the 1h timeframe, and its value is used as the base for target and stop-loss. Control this by setting the multipliers.')
local target_mult = Input('3.2. Target Multiplier', 2)
local trail_mult = Input('3.3. Trail Multiplier', 1.5, 'This value is proportional to the final target value. if ATR value 100, target multiplier is 2, then target becomes 200. If we have a trail multiplier of 1.5, then the trail value becomes 300.')
local trail_mode = InputOptions('3.4. Trail Mode', 'shrink', {'default', 'grow', 'shrink'})
local rebounds = Input('3.5. Max. Rebounds', 0)
local sl_mult = Input('3.6. Stop-Loss Multiplier', 0, 'Setting this to zero will disable stop-loss feature.')
local ma_len = Input('4.1. Fast MA Length', 200, 'Sets the length of the MA on the 5min timeframe calculations.')
local maType = InputMaTypes('4.2. Fast MA Type', EmaType)
local ma_len2 = Input('5.1. Trend MA Length', 200, 'Sets the length of the MA on the 1h timeframe calculations.')
local maType2 = InputMaTypes('5.2. Trend MA Type', EmaType)
local adx_len = Input('6.1. ADX Length', 32, 'ADX is used to filter entries. When ADX > its signal MA, new entries are allowed.')
local adx_ma_len = Input('6.2. ADX Signal Length', 20)
local adx_maType = InputMaTypes('6.3. ADX Signal Type', EmaType)

InputGroupHeader('Trade Logic Settings')
local use_cci = Input('1. Use CCI', true, 'CCI prevents entries outside its zone. So if CCI >upper or <lower, then no entries are allowed. Additionally, profit trailer wont trigger outside the zone. This can affect profits in good as well as bad way.')
local use_adx = Input('2. Use ADX', true, 'ADX is used to filter entries. If ADX is above its signal-MA then entries are allowed. Otherwise they are blocked.')


-- trend logic and targets
local adx, big_ma, up, down, atr, cci_up, cci_down = OptimizedForInterval(
    tf_trend_update,
    function()
        

        local hsp = CC_HighSpeedPrices(tf_trend)
        local h = hsp.high
        local l = hsp.low
        local c = hsp.close

        local adx = ADX(h, l, c, adx_len)
        local adx_ma = MA(adx, adx_ma_len, adx_maType)

        Plot(1, 'adx', adx)
        Plot(1, 'ma', adx_ma, Red)
        Plot(1, 'adx_hist', adx-adx_ma, Gray(50))

        local ma = MA(c, ma_len2, maType2)

        Plot(0, 'trend_ma', ma)

        local atr = ATR(h, l, c, atr_len)

        Plot(2, 'atr', atr)

        local cci = CCI(h, l, c, cci_len)

        Plot(3, 'cci', cci)
        PlotHorizontalLine(3, '', Gray, cci_l, Dashed)
        PlotHorizontalLine(3, '', Gray, cci_u, Dashed)

        return adx - adx_ma > 0,
            ma,
            c > ma and ma[1] > ma[3],
            c < ma and ma[1] < ma[3],
            atr,
            cci < cci_u,
            cci > cci_l
    end
)

-- check if cci or adx is used
if not use_cci then
    cci = true -- always allow entries when disabled
end

if not use_adx then
    adx = true -- always allow entries when disabled
end


local target = Load('ts', 0)
local stop = Load('sl', 0)

-- trading logic on shorter timeframe
OptimizedForInterval(
    tf_trade_update,
    function()
        local hsp = CC_HighSpeedPrices(tf_trade)
        local h = hsp.high
        local l = hsp.low
        local c = hsp.close

        local config = get_stoch_configs( stoch_config )
        local stoch = STOCH(h, l, c, config.k, config.s, config.d)
        
        Plot(-2, '%K', stoch.slowK, Yellow)
        Plot(-2, '%D', stoch.slowD, Red)
        PlotHorizontalLine(-2, '', Gray, stoch_l, Dashed)
        PlotHorizontalLine(-2, '', Gray, stoch_u, Dashed)

        local ma = MA(c, ma_len, maType)

        Plot(0, 'fast_ma', ma, Orange)

        local small_up = ma > big_ma
        local small_down = ma < big_ma
        local prc = ArrayGet(atr, 1) / c * 100 * max_leverage

        if small_up and cci_up and adx and up then
            if (stoch.slowK[2] <= stoch_l or stoch.slowD[2] <= stoch_l)
            and CrossOver(stoch.slowK, stoch.slowD) then
                DoBuy()

                target = prc * target_mult
                stop = prc * sl_mult
            end
        elseif small_down and cci_down and adx and down then
            if (stoch.slowK[2] >= stoch_u or stoch.slowD[2] >= stoch_u)
            and CrossUnder(stoch.slowK, stoch.slowD) then
                DoSell()

                target = prc * target_mult
                stop = prc * sl_mult
            end
        end


        -- this part here is not in use.
        -- i found it did more harm to the bot
        -- than anything else...
        local pos_dir = GetPositionDirection()
        if pos_dir == PositionLong and down then
            --DoExitPosition('Long Correction Exit')
            --target = 0
        elseif pos_dir == PositionShort and up then
            --DoExitPosition('Short Correction Exit')
            --target = 0
        end
    end
)

-- some...
local tps_hit = Load('tpshit', 0)
local stops_hit = Load('shit', 0)
local trail = target * trail_mult

-- tp + sl
if target > 0 then
    local pt = CC_ProfitTrailer(target, trail, trail_mode, rebounds)
    local sl = stop > 0 and StopLossROI(stop)

    if pt then
        DoExitPosition('TP')
        target = 0
        stop = 0
        tps_hit = tps_hit + 1
    end

    if sl then
        DoExitPosition('SL')
        target = 0
        stop = 0
        stops_hit = stops_hit + 1
    end
end

Save('tpshit', tps_hit)
Save('shit', stops_hit)
Save('ts', target)
Save('sl', stop)

-- situational info for profit trailer values
CustomReport('Target (start %)', Round(target, 3) .. ' %', 'Situational Info')
CustomReport('Trail (distance %)', Round(trail, 3) .. ' %', 'Situational Info')
CustomReport('Trail Mode', trail_mode, 'Situational Info')
CustomReport('Stop (SL %)', Round(stop, 3) .. ' %', 'Situational Info')

Finalize(function()

    -- i made this to fix the Max DD values in the custom reports
    -- (they messed up the Labs CSV file for me)
    function fixNumber(number)
        if StringContains(number, ',') then
            local split = StringExplode(number, ',')
            return split[1] .. '.' .. split[2]
        end

        return number
    end

    CustomReport('TPs hit', tps_hit, 'Performance Report')
    CustomReport('Stops hit', stops_hit, 'Performance Report')
    CustomReport('TP/Stop Ratio', Round(tps_hit / (stops_hit > 0 and stops_hit or 1), 2), 'Performance Report')
    CustomReport('---', '---', 'Performance Report')


    local report = GetTradingReport()

    CustomReport('Max DD.', fixNumber(report.maxDrawDown) .. UnderlyingAsset(), 'Performance Report')
    CustomReport('Max DD. %', fixNumber(Round(report.maxDrawDownPrc, 3)) .. ' %', 'Performance Report')
    CustomReport('Sharpe', report.sharpeRatio, 'Performance Report')
    CustomReport('Sortino', report.sortinoRatio, 'Performance Report')
    CustomReport('Win %', Round(report.winPercentage, 3) .. ' %', 'Performance Report')
    CustomReport('Profit Ratio', report.profitRatio, 'Performance Report')
    CustomReport('Profit Factor', report.profitFactor, 'Performance Report')
    CustomReport('CPC Index', report.cpcIndex, 'Performance Report')
    CustomReport('Tail Ratio', report.tailRatio, 'Performance Report')
    CustomReport('Common Sense', report.commonSenseRatio, 'Performance Report')
    CustomReport('Outlier Win', report.outlierWinRatio, 'Performance Report')
    CustomReport('Outlier Loss', report.outlierLossRatio, 'Performance Report')
    
    
end)

0 Comments

Sign in to leave a comment.

No comments yet. Be the first!