Stratégie d'équilibrage de la psychologie du trading

Auteur:ChaoZhang est là., Date: le 21 février 2024 à 14h33:04
Les étiquettes:

img

Résumé

L'objectif de cette stratégie est d'équilibrer la psychologie et la performance des traders en ajustant divers paramètres, afin d'obtenir des rendements plus stables. Elle utilise des indicateurs tels que les moyennes mobiles, les bandes de Bollinger et les canaux de Keltner pour déterminer les tendances et la volatilité du marché, ainsi que l'indicateur PSAR pour identifier les signaux d'inversion.

La logique de la stratégie

La logique de base de cette stratégie est la suivante:

  1. Les prix au-dessus de l'EMA indiquent des tendances à la hausse tandis que les prix au-dessous de l'EMA indiquent des tendances à la baisse.

  2. Identifier les renversements: l'indicateur PSAR détecte les points de renversement des prix. Les points PSAR apparaissant au-dessus des prix signalent des longs tandis que les points émergeant au-dessous des prix appellent à des shorts.

  3. L'indicateur TTM Squeeze mesure la volatilité et l'élan du marché. Il compare les bandes de Bollinger et les canaux de Keltner pour quantifier les compressions et les hausses de volatilité.

  4. Générer des signaux de négociation: les signaux longs sont déclenchés lorsque les prix se croisent au-dessus de la ligne EMA et des points PSAR, accompagnés d'une libération de la pression TTM. Les signaux courts se produisent lorsque les prix se croisent au-dessous de la EMA et de la pression PSAR, avec un déclenchement de la pression TTM.

  5. Métode de stop-loss: les niveaux de stop-loss basés sur des prix hauts/baissés récents multipliés par un facteur déterminé.

  6. Métode de prise de bénéfice: la méthode prise de bénéfice risque-récompense calcule automatiquement les objectifs de bénéfice en fonction de la distance de stop-loss par rapport aux prix courants multipliée par un rapport risque-récompense prédéfini.

Les différents paramètres permettent aux traders d'équilibrer la psychologie en contrôlant la fréquence des transactions, la taille des positions, les niveaux de stop loss et les points de profit.

Analyse des avantages

Les principaux axes de cette stratégie sont les suivants:

  1. Une plus grande précision du signal résultant du consensus sur plusieurs indicateurs

  2. Principalement axé sur l'inversion, réduit la probabilité de fausses éruptions

  3. TTM Consolidation des mesures de compression pour éviter les opérations inefficaces

  4. Perte de freinage simple et réglable à haute basse

  5. Le rapport risque-récompense prendre profit quantifie le ratio de profit pour un réglage facile

  6. Paramètres flexibles adaptés aux préférences personnelles en matière de risque

Analyse des risques

Les risques liés à la stratégie sont les suivants:

  1. Risque accru d'absence de signaux d'entrée de plusieurs indicateurs

  2. Des performances inférieures sur les marchés en tendance persistante

  3. Évasion occasionnelle du stop loss au-delà des attentes

  4. L'exonération éventuelle des sorties de risque-rendement par des baisses de prix

  5. Un réglage inapproprié des paramètres peut entraîner des pertes ou des sursauts

Directions d'optimisation

Les domaines d'amélioration possibles concernent:

  1. Ajouter ou ajuster des poids d'indicateur pour une plus grande précision du signal

  2. Optimiser les paramètres d'inversion et de tendance pour une meilleure capture des bénéfices

  3. Améliorer les niveaux d'arrêt à faible perte pour une efficacité maximale

  4. Testez différents ratios risque-rendement pour obtenir des résultats optimaux

  5. Ajuster la taille des positions afin de minimiser les effets des pertes d'une seule transaction

Résumé

En résumé, grâce à des combinaisons d'indicateurs et des paramètres réglables, cette stratégie est capable d'équilibrer la psychologie du trading et d'obtenir des résultats positifs constants.


/*backtest
start: 2024-01-01 00:00:00
end: 2024-01-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/


//@version=5
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © simwai
strategy('Octopus Nest Strategy 🐙', shorttitle='🐙', overlay=true )

// -- Colors --
color maximumYellowRed = color.rgb(255, 203, 98) // yellow
color rajah = color.rgb(242, 166, 84) // orange
color magicMint = color.rgb(171, 237, 198)
color languidLavender = color.rgb(232, 215, 255)
color maximumBluePurple = color.rgb(181, 161, 226)
color skyBlue = color.rgb(144, 226, 244)
color lightGray = color.rgb(214, 214, 214)
color quickSilver = color.rgb(163, 163, 163)
color mediumAquamarine = color.rgb(104, 223, 153)
color carrotOrange = color.rgb(239, 146, 46)

// -- Inputs --
float src = input.source(close, 'Choose Source', group='General', inline='1')
bool isSignalLabelEnabled = input.bool(title='Show Signal Labels?', defval=true, group='General', inline='2')
bool isPsarAdaptive = input.bool(title='Is PSAR Adaptive?', defval=false, group='General', inline='2')

float highLowStopLossMultiplier = input.float(defval=0.98,  step=0.01, minval=0, maxval=1, title='Multiplier', group='High Low Stop Loss', inline='1')
float highLowStopLossBackupMultiplier = input.float(defval=0.98, step=0.01, minval=0, maxval=1, title='Backup Multiplier', group='High Low Stop Loss', inline='1')
int highLowStopLossLookback = input.int(defval=20, step=5, minval=1, title='Lookback', group='High Low Stop Loss', inline='2')
float automaticHighLowTakeProfitRatio = input.float(defval=1.125, step=0.1, minval=0, title='Risk Reward Ratio', group='Automatic High Low Take Profit', inline='2')

int emaLength = input.int(100, minval=2, title='Length', group='EMA', inline='1')
int ttmLength = input.int(title='Length', defval=20, minval=0, group='TTM Squeeze', inline='1')

float psarStart = input.float(0.02, 'Start', step=0.01, minval=0.0, group='PSAR', inline='1')
float psarInc = input.float(0.02, 'Increment', step=0.01, minval=0.01, group='PSAR', inline='1')
float psarMax = input.float(0.2, 'Max', step=0.05, minval=0.0, group='PSAR', inline='2')

startAFactor = input.float(0.02, 'Starting Acceleration Factor', step = 0.001, group='Adaptive PSAR', inline='1')
minStep = input.float(0.0, 'Min Step', step = 0.001, group='Adaptive PSAR', inline='1')
maxStep = input.float(0.02, 'Max Step', step = 0.001, group='Adaptive PSAR', inline='2')
maxAFactor = input.float(0.2, 'Max Acceleration Factor', step = 0.001, group='Adaptive PSAR', inline='2')  

hiloMode = input.string('On', 'HiLo Mode', options = ['Off', 'On'], group='Adaptive PSAR')
adaptMode = input.string('Kaufman', 'Adaptive Mode', options = ['Off', 'Kaufman', 'Ehlers'], group='Adaptive PSAR')
adaptSmth = input.int(5, 'Adaptive Smoothing Period', minval = 1, group='Adaptive PSAR')
filt = input.float(0.0, 'Filter in Pips', group='Adaptive PSAR', minval = 0)
minChng = input.float(0.0, 'Min Change in Pips', group='Adaptive PSAR', minval = 0)
SignalMode = input.string('Only Stops', 'Signal Mode', options = ['Only Stops', 'Signals & Stops'], group='Adaptive PSAR')

// -- Functions --
tr(_high, _low, _close) => math.max(_high - _low, math.abs(_high - _close[1]), math.abs(_low - _close[1]))

// -- Calculation --
var string lastTrade = 'initial'

float _low = low
float _high = high
float _close = close

// -- TTM Squeeze – Credits to @Greeny --
bband(ttmLength, mult) =>
    ta.sma(src, ttmLength) + mult * ta.stdev(src, ttmLength)
keltner(ttmLength, mult) =>
    ta.ema(src, ttmLength) + mult * ta.ema(tr(_high, _low, _close), ttmLength)

e1 = (ta.highest(_high, ttmLength) + ta.lowest(_low, ttmLength)) / 2 + ta.sma(src, ttmLength)
osc = ta.linreg(src - e1 / 2, ttmLength, 0)
diff = bband(ttmLength, 2) - keltner(ttmLength, 1)
osc_color = osc[1] < osc[0] ? osc[0] >= 0 ? #00ffff : #cc00cc : osc[0] >= 0 ? #009b9b : #ff9bff
mid_color = diff >= 0 ? color.green : color.red

// -- PSAR --
// Credits to @Bjorgum
calcBaseUnit() =>
    bool  isForexSymbol = syminfo.type     == 'forex'
    bool  isYenPair     = syminfo.currency == 'JPY'
    float result = isForexSymbol ? isYenPair ? 0.01 : 0.0001 : syminfo.mintick

// Credits to @loxx
_afact(mode,input, per, smooth) =>
    eff = 0., seff = 0.
    len = 0, sum = 0., max = 0., min = 1000000000.
    len := mode == 'Kaufman' ? math.ceil(per) : math.ceil(math.max(20, 5 * per))
    for i = 0 to len 
        if (mode == 'Kaufman') 
            sum += math.abs(input[i] - input[i + 1])
        else
            max := input[i] > max ? input[i] : max
            min := input[i] < min ? input[i] : min
    if (mode == 'Kaufman' and sum != 0) 
        eff := math.abs(input - input[len]) / sum
    else
        if (mode == 'Ehlers' and (max - min) > 0) 
            eff := (input - min) / (max - min)
    seff := ta.ema(eff, smooth)
    seff

hVal2 = nz(high[2]), hVal1 = nz(high[1]), hVal0 = high
lowVal2 = nz(low[2]), lowVal1 = nz(low[1]), lowVal0 = low
hiprice2 = nz(high[2]), hiprice1 = nz(high[1]), hiprice0 = high
loprice2 = nz(low[2]), loprice1 = nz(low[1]), loprice0 = low

upSig = 0., dnSig = 0.
aFactor = 0., step = 0., trend = 0.
upTrndSAR = 0., dnTrndSAR = 0.
length = (2 / maxAFactor - 1)

if (hiloMode == 'On') 
    hiprice0 := high
    loprice0 := low
else
    hiprice0 := src
    loprice0 := hiprice0

if bar_index == 1
    trend := 1
    hVal1 := hiprice1
    hVal0 := math.max(hiprice0, hVal1)
    lowVal1 := loprice1
    lowVal0 := math.min(loprice0, lowVal1)
    aFactor := startAFactor
    upTrndSAR := lowVal0
    dnTrndSAR := 0.
else
    hVal0 := hVal1
    lowVal0 := lowVal1
    trend := nz(trend[1])
    aFactor := nz(aFactor[1])
    inputs = 0.
    inprice = src
    if (adaptMode != 'Off')
        if (hiloMode == 'On') 
            inprice := src
        else 
            inprice := hiprice0
        if (adaptMode == 'Kaufman') 
            inputs := inprice
        else
            if (adaptMode == 'Ehlers') 
                if (nz(upTrndSAR[1]) != 0.)
                    inputs := math.abs(inprice - nz(upTrndSAR[1]))
                else
                    if (nz(dnTrndSAR[1]) != 0.) 
                        inputs := math.abs(inprice - nz(dnTrndSAR[1]))
        step := minStep + _afact(adaptMode, inputs, length, adaptSmth) * (maxStep - minStep)
    else 
        step := maxStep
        
    upTrndSAR := 0., dnTrndSAR := 0., upSig := 0., dnSig := 0.
    
    if (nz(trend[1]) > 0) 
        if (nz(trend[1]) == nz(trend[2]))
            aFactor := hVal1 > hVal2 ? nz(aFactor[1]) + step : aFactor
            aFactor := aFactor > maxAFactor ? maxAFactor : aFactor
            aFactor := hVal1 < hVal2 ? startAFactor : aFactor
        else 
            aFactor := nz(aFactor[1])
            
        upTrndSAR := nz(upTrndSAR[1]) + aFactor * (hVal1 - nz(upTrndSAR[1]))
        upTrndSAR := upTrndSAR > loprice1 ? loprice1 : upTrndSAR
        upTrndSAR := upTrndSAR > loprice2 ? loprice2 : upTrndSAR
    else
        if (nz(trend[1]) == nz(trend[2])) 
            aFactor := lowVal1 < lowVal2 ? nz(aFactor[1]) + step : aFactor
            aFactor := aFactor > maxAFactor ? maxAFactor : aFactor
            aFactor := lowVal1 > lowVal2 ? startAFactor : aFactor
        else
            aFactor := nz(aFactor[1])
            
        dnTrndSAR := nz(dnTrndSAR[1]) + aFactor * (lowVal1 - nz(dnTrndSAR[1]))
        dnTrndSAR := dnTrndSAR < hiprice1 ? hiprice1 : dnTrndSAR
        dnTrndSAR := dnTrndSAR < hiprice2 ? hiprice2 : dnTrndSAR
    
    hVal0 := hiprice0 > hVal0 ? hiprice0 : hVal0
    lowVal0 := loprice0 < lowVal0 ? loprice0 : lowVal0
        
    if (minChng > 0) 
        if (upTrndSAR - nz(upTrndSAR[1]) < minChng * calcBaseUnit() and upTrndSAR != 0. and nz(upTrndSAR[1]) != 0.)
            upTrndSAR := nz(upTrndSAR[1])
        if (nz(dnTrndSAR[1]) - dnTrndSAR < minChng * calcBaseUnit() and dnTrndSAR != 0. and nz(dnTrndSAR[1]) != 0.)
            dnTrndSAR := nz(dnTrndSAR[1])

    dnTrndSAR := trend < 0 and dnTrndSAR > nz(dnTrndSAR[1]) ? nz(dnTrndSAR[1]) : dnTrndSAR
    upTrndSAR := trend > 0 and upTrndSAR < nz(upTrndSAR[1]) ? nz(upTrndSAR[1]) : upTrndSAR
    
    if (trend < 0 and hiprice0 >= dnTrndSAR + filt * calcBaseUnit())
        trend := 1
        upTrndSAR := lowVal0
        upSig := SignalMode == 'Signals & Stops' ? lowVal0 : upSig
        dnTrndSAR := 0.
        aFactor := startAFactor
        lowVal0 := loprice0
        hVal0 := hiprice0
    else if (trend > 0 and loprice0 <= upTrndSAR - filt * calcBaseUnit())
        trend := -1
        dnTrndSAR := hVal0
        dnSig := SignalMode == 'Signals & Stops' ? hVal0 : dnSig
        upTrndSAR := 0.
        aFactor := startAFactor
        lowVal0 := loprice0
        hVal0 := hiprice0
    
psar = upTrndSAR > 0 ? upTrndSAR : dnTrndSAR
psar := isPsarAdaptive ? psar : ta.sar(psarStart, psarInc, psarMax) 
plot(psar, title='PSAR', color=src < psar ? rajah : magicMint, style=plot.style_circles)

// -- EMA --
float ema = ta.ema(src, emaLength)
plot(ema, title='EMA', color=languidLavender)

// -- Signals --
var string isTradeOpen = ''
var string signalCache = ''

bool enterLong = src > ema and ta.crossover(src, psar) and ta.crossover(osc, 0)
bool enterShort = src < ema and ta.crossunder(src, psar) and ta.crossunder(osc, 0)
// bool exitLong = ta.crossunder(src, ema)
// bool exitShort = ta.crossover(src, ema)

if (signalCache == 'long entry')
    signalCache := ''
    enterLong := true
else if (signalCache == 'short entry')
    signalCache := ''
    enterShort := true

if (isTradeOpen == '')
    if (enterLong)
        isTradeOpen := 'long'
    else if (enterShort)
        isTradeOpen := 'short'
else if (isTradeOpen == 'long')
    if (enterLong)
        enterLong := false
else if (isTradeOpen == 'short')
    if (enterShort)
        enterShort := false

plotshape((isSignalLabelEnabled and enterLong and (isTradeOpen == 'long')) ? psar : na, title='LONG', text='L', style=shape.labelup, color=mediumAquamarine, textcolor=color.white, size=size.tiny, location=location.absolute)
plotshape((isSignalLabelEnabled and enterShort and (isTradeOpen == 'short')) ? psar : na, title='SHORT', text='S', style=shape.labeldown, color=carrotOrange, textcolor=color.white, size=size.tiny, location=location.absolute)

// -- High Low Stop Loss and Take Profit --
bool isHighLowStopLossEnabled = true
bool isAutomaticHighLowTakeProfitEnabled = true
bool recalculateStopLossTakeProfit = false
bool isStrategyEntryEnabled = false
bool isLongEnabled = true
bool isShortEnabled = true
bool isStopLossTakeProfitRecalculationEnabled = true

bool longStopLossTakeProfitRecalculation = isStopLossTakeProfitRecalculationEnabled ? true : (lastTrade == 'short' or lastTrade == 'initial')
bool shortStopLossTakeProfitRecalculation = isStopLossTakeProfitRecalculationEnabled ? true : (lastTrade == 'long' or lastTrade == 'initial')

var float longHighLowStopLoss = 0
var float shortHighLowStopLoss = 0

float highLowStopLossLowest = ta.lowest(_low, highLowStopLossLookback)
float highLowStopLossHighest = ta.highest(_high, highLowStopLossLookback)

if (isHighLowStopLossEnabled)
    if (((enterLong and longStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true))
        if (highLowStopLossLowest == _low)
            longHighLowStopLoss := _high * highLowStopLossBackupMultiplier
        else if (highLowStopLossLowest > 0)
            longHighLowStopLoss := highLowStopLossLowest * highLowStopLossMultiplier
            
    if (((enterShort and shortStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size < 0) : true))
        if (highLowStopLossHighest == _high)
            shortHighLowStopLoss := _high * (1 + (1 - highLowStopLossBackupMultiplier))
        else if (highLowStopLossHighest > 0)
            shortHighLowStopLoss := highLowStopLossHighest * (1 + (1 - highLowStopLossMultiplier))
        
plot((isLongEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'long')) ? longHighLowStopLoss : na, 'Long High Low Stop Loss', color=magicMint, style=plot.style_circles, trackprice=false)
plot((isShortEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'short')) ? shortHighLowStopLoss : na, 'Short High Low Stop Loss ', color=rajah, style=plot.style_circles, trackprice=false)

// -- Automatic High Low Take Profit --
var float longAutomaticHighLowTakeProfit = na
var float shortAutomaticHighLowTakeProfit = na

if (isAutomaticHighLowTakeProfitEnabled)
    if (((enterLong and longStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true))
        longHighLowStopLossPercentage = 1 - (longHighLowStopLoss / _close)
        longAutomaticHighLowTakeProfit := _close * (1 + (longHighLowStopLossPercentage  * automaticHighLowTakeProfitRatio))
    if (((enterShort and shortStopLossTakeProfitRecalculation) or recalculateStopLossTakeProfit) and (isStrategyEntryEnabled ? not(strategy.position_size > 0) : true)) 
        shortHighLowStopLossPercentage = 1 - (_close / shortHighLowStopLoss)
        shortAutomaticHighLowTakeProfit := _close * (1 - (shortHighLowStopLossPercentage * automaticHighLowTakeProfitRatio))

plot((isAutomaticHighLowTakeProfitEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'long')) ? longAutomaticHighLowTakeProfit : na, 'Long Automatic High Low Take Profit', color=magicMint, style=plot.style_circles, trackprice=false)
plot((isAutomaticHighLowTakeProfitEnabled and isHighLowStopLossEnabled and (isTradeOpen == 'short')) ? shortAutomaticHighLowTakeProfit : na, 'Short Automatic High Low Take Profit', color=rajah, style=plot.style_circles, trackprice=false)

// log.info('Automatic Long High Low Take Profit: ' + str.tostring(longAutomaticHighLowTakeProfit))
// log.info('Automatic Short High Low Take Profit: ' + str.tostring(shortAutomaticHighLowTakeProfit))

// log.info('Long High Low Stop Loss: ' + str.tostring(longHighLowStopLoss))
// log.info('Short High Low Stop Loss: ' + str.tostring(shortHighLowStopLoss))

bool longHighLowStopLossCondition = ta.crossunder(_close, longHighLowStopLoss)
bool shortHighLowStopLossCondition = ta.crossover(_close, shortHighLowStopLoss)

bool longAutomaticHighLowTakeProfitCondition = ta.crossover(_close, longAutomaticHighLowTakeProfit)
bool shortAutomaticHighLowTakeProfitCondition = ta.crossunder(_close, shortAutomaticHighLowTakeProfit)

bool exitLong = (longHighLowStopLossCondition or longAutomaticHighLowTakeProfitCondition) and strategy.position_size > 0
bool exitShort = (shortHighLowStopLossCondition or shortAutomaticHighLowTakeProfitCondition) and strategy.position_size < 0

plotshape((isSignalLabelEnabled and exitLong and (isTradeOpen == 'long')) ? psar : na, title='LONG EXIT', style=shape.circle, color=magicMint, size=size.tiny, location=location.absolute)
plotshape((isSignalLabelEnabled and exitShort and (isTradeOpen == 'short')) ? psar : na, title='SHORT EXIT', style=shape.circle, color=rajah, size=size.tiny, location=location.absolute)

// Long Exits
if (exitLong)
    strategy.close('long', comment=longAutomaticHighLowTakeProfitCondition ? 'EXIT_LONG_TP' : 'EXIT_LONG_SL')
    isTradeOpen := ''

// Short Exits
if (exitShort)
    strategy.close('short', comment=shortAutomaticHighLowTakeProfitCondition ? 'EXIT_SHORT_TP' : 'EXIT_SHORT_SL')
    isTradeOpen := ''

// Long Entries
if (enterLong and (strategy.position_size == 0))
    strategy.entry('long', strategy.long, comment='ENTER_LONG')

// Short Entries
if (enterShort and (strategy.position_size == 0))
    strategy.entry('short', strategy.short, comment='ENTER_SHORT')

// Save last trade state
if (enterLong or exitLong)
    lastTrade := 'long'
if (enterShort or exitShort)
    lastTrade := 'short'

barcolor(color=isTradeOpen == 'long' ? mediumAquamarine : isTradeOpen == 'short' ? carrotOrange : na)

Plus de