Stratégie de trading basée sur la moyenne mobile et l'écart type pondéré


Date de création: 2023-11-24 13:54:58 Dernière modification: 2023-11-24 13:54:58
Copier: 0 Nombre de clics: 773
1
Suivre
1617
Abonnés

Stratégie de trading basée sur la moyenne mobile et l’écart type pondéré

Aperçu

Cette stratégie utilise un indicateur de décalage standard pondéré, combiné à une moyenne mobile, pour réaliser des transactions de tendance sur les crypto-monnaies. La stratégie calcule le canal de décalage standard pondéré du prix en fonction du prix de clôture et du volume de transactions au cours d’un certain cycle.

Principe de stratégie

Le code définit deux fonctions personnalisées, respectivement la séquence temporelle et la différence pondérée de calcul de l’arithmétique. Les principales étapes sont:

  1. Calcul du prix moyen pondéré en fonction du prix de clôture et du volume des transactions
  2. Calculer le carré de l’erreur de chaque ligne K par rapport à la moyenne
  3. Différence calculée sur la base de la moyenne après ajustement de la masse et du poids des échantillons
  4. Le carré est égal à la différence standard

On obtient ainsi un canal dont le centre est la moyenne pondérée et la distance entre le haut et le bas est un écart standard. Lorsque le prix franchit le fond du canal par le bas, on fait plus; lorsqu’il franchit le sommet du canal par le haut, on fait moins.

Analyse des avantages

Le plus grand avantage de cette stratégie réside dans la combinaison des moyennes mobiles et de l’analyse de la volatilité. Les moyennes mobiles déterminent la direction de la tendance du marché, l’écart standard définit une plage raisonnable, les deux se vérifient mutuellement et sont plus fiables. De plus, le poids de transaction peut filtrer les fausses ruptures et la probabilité de rupture réelle est plus élevée.

La stratégie impose également des points de stop-loss, qui permettent de maîtriser la tendance et d’éviter que les retournements entraînent des pertes excessives. C’est un point que de nombreux débutants ne maîtrisent pas.

Analyse des risques

Le risque principal est que le marché puisse être très volatile. Le canal de déviation standard peut alors également être très volatile, ce qui nuit au jugement. De plus, le taux d’erreur est élevé si le cycle de sélection est trop court et sujet au bruit.

La contre-mesure est d’ajuster les paramètres de cycle et de lisser la courbe. On peut également envisager de combiner d’autres indicateurs, tels que le RSI, pour augmenter l’effet de confirmation de la rupture.

Direction d’optimisation

  1. Paramètres de cycle d’optimisation: vous pouvez tester différents cycles de 5 minutes, 15 minutes, 30 minutes, etc. pour trouver la combinaison optimale
  2. Optimiser le ratio d’arrêt-stop. Tester différents points d’arrêt-stop pour obtenir le meilleur rendement
  3. Augmentation des conditions de filtrage, par exemple pour combiner le trafic et éviter les fausses percées entraînant des pertes
  4. Ajout d’indicateurs d’erreur, tels que la confirmation des entités de ligne K par la position du cours de clôture, la longueur de la ligne d’ombre, etc.

Résumer

Cette stratégie utilise avec succès les indicateurs de décalage standard pondérés, les moyennes mobiles pour déterminer la direction et suivre la tendance des crypto-monnaies. En même temps, un arrêt de perte raisonnable aide à maîtriser le rythme du marché et à éviter les pertes dues à une inversion excessive.

Code source de la stratégie
/*backtest
start: 2023-11-16 00:00:00
end: 2023-11-23 00:00:00
period: 45m
basePeriod: 5m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © rumpypumpydumpy   © cache_that_pass

//@version=4
strategy("[cache_that_pass] 1m 15m Function - Weighted Standard Deviation", overlay=true, pyramiding=0, default_qty_type=strategy.percent_of_equity, default_qty_value=20, initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.075)

f_weighted_sd_from_series(_src, _weight, _n) => //{
//  @function: Calculates weighted mean, variance, standard deviation, MSE and RMSE from time series variables
//  @parameters:
//      _src: time series variable of sample values
//      _weight: time series of corresponding weight values.
//      _n : number of samples
    _xw = _src * _weight
    _sum_weight = sum(_weight, _n)
    _mean = sum(_xw, _n) / _sum_weight
    float _sqerror_sum = 0
    int _nonzero_n = 0
    for _i = 0 to _n - 1
        _sqerror_sum := _sqerror_sum + pow(_mean - _src[_i], 2) * _weight[_i]
        _nonzero_n := _weight[_i] != 0 ? _nonzero_n + 1 : _nonzero_n
    _variance = _sqerror_sum / ((_nonzero_n - 1) * _sum_weight / _nonzero_n)
    _dev = sqrt(_variance)
    _mse = _sqerror_sum / _sum_weight
    _rmse = sqrt(_mse)
    [_mean, _variance, _dev, _mse, _rmse]
//}
// -----------------------------------------------------------------------------

f_weighted_sd_from_arrays(_a_src, _a_weight, _n) => //{
//  @function: Calculates weighted mean, variance, standard deviation, MSE and RMSE from arrays
//  Expects index 0 of the arrays to be the most recent sample and weight values!
//  @parameters:
//      _a_src: array of sample values
//      _a_weight: array of corresponding weight values.
//      _n : number of samples
    float _mean = na, float _variance = na, float _dev = na, float _mse = na
    float _rmse = na, float _sqerror_sum = na, float _sum_weight = na
    float[] _a_xw = array.new_float(_n)
    int _nonzero_n = 0
    if array.size(_a_src) >= _n
        _sum_weight := 0
        _sqerror_sum := 0
        for _i = 0 to _n - 1
            array.set(_a_xw, _i, array.get(_a_src, _i) * array.get(_a_weight, _i))
            _sum_weight := _sum_weight + array.get(_a_weight, _i)
            _nonzero_n := array.get(_a_weight, _i) != 0 ? _nonzero_n + 1 : _nonzero_n
        _mean := array.sum(_a_xw) / _sum_weight
        for _j = 0 to _n - 1
            _sqerror_sum := _sqerror_sum + pow(_mean - array.get(_a_src, _j), 2) * array.get(_a_weight, _j)
        _variance := _sqerror_sum / ((_nonzero_n - 1) * _sum_weight / _nonzero_n)
        _dev := sqrt(_variance)
        _mse := _sqerror_sum / _sum_weight
        _rmse := sqrt(_mse)
    [_mean, _variance, _dev, _mse, _rmse]
//}


// -----------------------------------------------------------------------------
// Example usage : 
// -----------------------------------------------------------------------------

len = input(20)

// -----------------------------------------------------------------------------
// From series :
// -----------------------------------------------------------------------------
[m, v, d, mse, rmse] = f_weighted_sd_from_series(close, volume, len)


plot(m, color = color.blue)
plot(m + d * 2, color = color.blue)
plot(m - d * 2, color = color.blue)
// -----------------------------------------------------------------------------



// -----------------------------------------------------------------------------
// From arrays : 
// -----------------------------------------------------------------------------
var float[] a_src = array.new_float()
var float[] a_weight = array.new_float()

if barstate.isfirst
    for i = 1 to len
        array.unshift(a_weight, i)

array.unshift(a_src, close)

if array.size(a_src) > len
    array.pop(a_src)

[a_m, a_v, a_d, a_mse, a_rmse] = f_weighted_sd_from_arrays(a_src, a_weight, len)

plot(a_m, color = color.orange)
plot(a_m + a_d * 2, color = color.orange)
plot(a_m - a_d * 2, color = color.orange)
// -----------------------------------------------------------------------------


series_text = "Mean : " + tostring(m) + "\nVariance : " + tostring(v) + "\nSD : " + tostring(d) + "\nMSE : " + tostring(mse) +  "\nRMSE : " + tostring(rmse)
array_text = "Mean : " + tostring(a_m) + "\nVariance : " + tostring(a_v) + "\nSD : " + tostring(a_d) + "\nMSE : " + tostring(a_mse) +  "\nRMSE : " + tostring(a_rmse)
debug_text = "Volume weighted from time series : \n" + series_text + "\n\nLinearly weighted from arrays : \n" + array_text

//debug = label.new(x = bar_index, y = close, text = debug_text, style = label.style_label_left)
//.delete(debug[1])

//test strategy
if low <= (m - d * 2)
    strategy.entry("LE", strategy.long)
if high >= (m + d * 2)
    strategy.entry("SE", strategy.short)

// User Options to Change Inputs (%)
stopPer = input(3.11, title='Stop Loss %', type=input.float) / 100
takePer = input(7.50, title='Take Profit %', type=input.float) / 100

// Determine where you've entered and in what direction
longStop = strategy.position_avg_price * (1 - stopPer)
shortStop = strategy.position_avg_price * (1 + stopPer)
shortTake = strategy.position_avg_price * (1 - takePer)
longTake = strategy.position_avg_price * (1 + takePer)

if strategy.position_size > 0 
    strategy.exit(id="Close Long", stop=longStop, limit=longTake)
//    strategy.close("LE", when = (longStop) or (longTake), qty_percent = 100)
if strategy.position_size < 0 
    strategy.exit(id="Close Short", stop=shortStop, limit=shortTake)
//    strategy.close("SE", when = (shortStop) or (shortTake), qty_percent = 100)