Gewichtete Standardabweichungshandelsstrategie

Schriftsteller:ChaoZhang, Datum: 2023-11-24 13:54:58
Tags:

img

Übersicht

Diese Strategie verwendet den gewichteten Standardabweichungsindikator in Kombination mit dem gleitenden Durchschnitt, um den Trendhandel mit Kryptowährungen umzusetzen. Sie berechnet einen Preiskanal mit gewichteter Standardabweichung basierend auf Schlusskurs und -volumen über einen bestimmten Zeitraum. Wenn der Preis durch den oberen oder unteren Kanal bricht, werden Long- oder Short-Positionen eingegangen. Stop-Loss- und Take-Profit-Bedingungen werden auch so festgelegt, dass Verluste pro Handel begrenzt werden.

Strategie Logik

Der Code definiert zwei benutzerdefinierte Funktionen zur Berechnung der gewichteten Standardabweichung von Zeitreihen und Arrays.

  1. Berechnung des gewichteten Durchschnittspreises auf der Grundlage von Schlusskurs und Volumen
  2. Berechnen Sie den Quadratfehler jeder Kerze gegenüber dem durchschnittlichen Preis
  3. Berechnung der Varianz auf der Grundlage von Stichprobengröße, Gewichten und bereinigtem Mittelwert
  4. Nehmen Sie die Quadratwurzel, um die Standardabweichung abzuleiten.

Dies gibt uns einen Kanal, der sich auf den gewichteten Durchschnittspreis konzentriert, mit oberen und unteren Grenzen in einer Standardabweichung entfernt.

Analyse der Vorteile

Der größte Vorteil dieser Strategie ist die Kombination von gleitendem Durchschnitt und Volatilitätsanalyse. Der MA beurteilt die Markttrendrichtung, während der SD-Bereich ein vernünftiges Band definiert - beide überprüfen sich gegenseitig für höhere Zuverlässigkeit. Außerdem hilft die Volumengewichtung, falsche Breaks für höhere Erfolgswahrscheinlichkeit bei tatsächlichen Breaks zu filtern.

Die Stop-Loss- und Take-Profit-Punkte helfen weiter, mit dem Trend zu handeln und übermäßige Verluste bei Umkehrungen zu vermeiden.

Risikoanalyse

Das Hauptrisiko besteht in starken Marktschwankungen, die dazu führen können, dass der SD-Kanal auch wild schwankt und Urteile erschwert.

Die Lösung besteht darin, die Parameter und Perioden-Einstellungen angemessen zu glätten.

Optimierungsrichtlinien

  1. Optimieren Sie die Periodenparameter - Test 5min, 15min, 30min etc. für die beste Kombination
  2. Optimierung der Stop-Loss-/Take-Profit-Verhältnisse für maximale Rendite
  3. Fügen Sie Filter hinzu, z. B. Volumen, um falsche Bruchvorgänge zu vermeiden
  4. Hinzufügen von Kerzenfiltern zum Schließpreis, Docht usw. zur Verbesserung der Genauigkeit

Schlussfolgerung

Diese Strategie verwendet erfolgreich den gewichteten Standardabweichungsindikator zusammen mit MA, um Kryptowährungstrends zu verfolgen. Vernünftige Stop-Loss/Take-Profit-Setups helfen auch, den Handelsmarktrhythmus zu regeln und übermäßige Umkehrverluste zu vermeiden. Weitere Optimierungen über Parameter-Tuning und Multi-Indikator-Bestätigung können die Zuverlässigkeit für eine solide Algo-Handelsstrategie verbessern.


/*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)

Mehr