Back to Community
How to avoid huge drawdown?

It's a ten-year backtest performance of the strategy, which is a daily momentum strategy on ETFs.

I suffer some huge drawdowns in the strategy. Should I change the logic, or add some modifications to the current code?

Clone Algorithm
10
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This is a template algorithm on Quantopian for you to adapt and fill in.
"""
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn import preprocessing
from collections import Counter
import numpy as np
 
def initialize(context):
    """
    Called once at the start of the algorithm.
    """   
    # If you don't specify a commission, your backtest defaults to $0.0075 per share with a $1 minimum cost per trade.
    
    context.stocks = symbols('XLY',  # XLY Consumer Discrectionary SPDR Fund   
                           'XLF',  # XLF Financial SPDR Fund  
                           'XLK',  # XLK Technology SPDR Fund  
                           'XLE',  # XLE Energy SPDR Fund  
                           'XLV',  # XLV Health Care SPRD Fund  
                           'XLI',  # XLI Industrial SPDR Fund  
                           'XLP',  # XLP Consumer Staples SPDR Fund   
                           'XLB',  # XLB Materials SPDR Fund  
                           'XLU')  # XLU Utilities SPRD Fund
    
    context.historical_bars = 100
    context.feature_window = 10
    
    # Rebalance every day.
    schedule_function(my_rebalance, date_rules.every_day())
    
    
def my_rebalance(context, data):
    """
    Execute orders according to our schedule_function() timing. 
    """
    prices = data.history(context.stocks, 'price', context.historical_bars, '1d')
    
    for stock in context.stocks:
        try:
            
            ma1 = data.history(stock, 'price', 50, '1d').mean()
            ma2 = data.history(stock, 'price', 200, '1d').mean()
            
            start_bar = context.feature_window
            price_list = prices[stock].tolist()

            X = []
            y = []

            bar = start_bar
            
            # feature creation
            while bar < len(price_list)-1:
                try:
                    end_price = price_list[bar+1]
                    begin_price = price_list[bar]

                    pricing_list = []
                    xx = 0
                    for _ in range(context.feature_window):
                        price = price_list[bar-(context.feature_window-xx)]
                        pricing_list.append(price)
                        xx += 1

                    features = np.around(np.diff(pricing_list) / pricing_list[:-1] * 100.0, 1)

                    #print(features)

                    if end_price > begin_price:
                        label = 1
                    else:
                        label = -1

                    bar += 1
                    X.append(features)
                    y.append(label)

                except Exception as e:
                    bar += 1
                    print(('feature creation',str(e)))
            
            clf1 = RandomForestClassifier()
            clf2 = LinearSVC()
            clf3 = NuSVC()
            clf4 = LogisticRegression()

            last_prices = price_list[-context.feature_window:]
            current_features = np.around(np.diff(last_prices) / last_prices[:-1] * 100.0, 1)

            X.append(current_features)
            X = preprocessing.scale(X)

            current_features = X[-1]
            X = X[:-1]

            clf1.fit(X,y)
            clf2.fit(X,y)
            clf3.fit(X,y)
            clf4.fit(X,y)

            p1 = clf1.predict(current_features)[0]
            p2 = clf2.predict(current_features)[0]
            p3 = clf3.predict(current_features)[0]
            p4 = clf4.predict(current_features)[0]
            
            if Counter([p1,p2,p3,p4]).most_common(1)[0][1] >= 4:
                p = Counter([p1,p2,p3,p4]).most_common(1)[0][0]
                
            else:
                p = 0
            
            current_price = data.current(stock, 'price')

            #print(('Prediction',p))
            if p == 1 and ma1 > ma2:
                order_target_percent(stock,0.22)
                order_target_percent(stock,0,style=StopOrder(current_price*0.95))
            elif p == -1 and ma1 < ma2:
                order_target_percent(stock,-0.22) 
                order_target_percent(stock,0,style=StopOrder(current_price*1.05))
            
        except Exception as e:
            print(str(e))
            
    record('ma1',ma1)
    record('ma2',ma2)
    record('Leverage',context.account.leverage)                   

def handle_data(context,data):
    """
    Called every minute.
    """
    pass
There was a runtime error.
4 responses

i think that this is a strategy that does not work. and i think that tweaking it will probably not give good out of sample results. i personally would probably try a different approach.

The best ways to avoid huge drawdowns are:

Structure the list of symbols that will hedge portfolio naturally.
Remove stop loss orders - they will never prevent losses, just will take them.
Lower leverage especially in short positions during bull market .

Clone Algorithm
6
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This is a template algorithm on Quantopian for you to adapt and fill in.
"""
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn import preprocessing
from collections import Counter
import numpy as np
 
def initialize(context):
    """
    Called once at the start of the algorithm.
    """   
    # If you don't specify a commission, your backtest defaults to $0.0075 per share with a $1 minimum cost per trade.
    
    context.stocks =symbols('XLV', 'XLP', 'XLY','TLT','TLO', 'IEF')  
    
    context.historical_bars = 100
    context.feature_window = 5
    
    # Rebalance every day.
    schedule_function(my_rebalance, date_rules.every_day())
    
    
def my_rebalance(context, data):
    """
    Execute orders according to our schedule_function() timing. 
    """
    prices = data.history(context.stocks, 'price', context.historical_bars, '1d')
    
    for stock in context.stocks:
        try:
            
            ma1 = data.history(stock, 'price', 50, '1d').mean()
            ma2 = data.history(stock, 'price', 200, '1d').mean()
            
            start_bar = context.feature_window
            price_list = prices[stock].tolist()

            X = []
            y = []

            bar = start_bar
            
            # feature creation
            while bar < len(price_list)-1:
                try:
                    end_price = price_list[bar+1]
                    begin_price = price_list[bar]

                    pricing_list = []
                    xx = 0
                    for _ in range(context.feature_window):
                        price = price_list[bar-(context.feature_window-xx)]
                        pricing_list.append(price)
                        xx += 1

                    features = np.around(np.diff(pricing_list) / pricing_list[:-1] * 100.0, 1)

                    #print(features)

                    if end_price > begin_price:
                        label = 1
                    else:
                        label = -1

                    bar += 1
                    X.append(features)
                    y.append(label)

                except Exception as e:
                    bar += 1
                    print(('feature creation',str(e)))
            
            clf1 = RandomForestClassifier()
            clf2 = LinearSVC()
            clf3 = NuSVC()
            clf4 = LogisticRegression()

            last_prices = price_list[-context.feature_window:]
            current_features = np.around(np.diff(last_prices) / last_prices[:-1] * 100.0, 1)

            X.append(current_features)
            X = preprocessing.scale(X)

            current_features = X[-1]
            X = X[:-1]

            clf1.fit(X,y)
            clf2.fit(X,y)
            clf3.fit(X,y)
            clf4.fit(X,y)

            p1 = clf1.predict(current_features)[0]
            p2 = clf2.predict(current_features)[0]
            p3 = clf3.predict(current_features)[0]
            p4 = clf4.predict(current_features)[0]
            
            if Counter([p1,p2,p3,p4]).most_common(1)[0][1] >= 4:
                p = Counter([p1,p2,p3,p4]).most_common(1)[0][0]
                
            else:
                p = 0
            
            current_price = data.current(stock, 'price')

            #print(('Prediction',p))
            if p == 1 and ma1 > ma2:
                order_target_percent(stock,0.20)
                # order_target_percent(stock,0,style=StopOrder(current_price*0.95))
            elif p == -1 and ma1 < ma2:
                order_target_percent(stock,-0.05) 
                # order_target_percent(stock,0,style=StopOrder(current_price*1.05))
            
        except Exception as e:
            print(str(e))
            
    record('ma1',ma1)
    record('ma2',ma2)
    record('Leverage',context.account.leverage)                   

def handle_data(context,data):
    """
    Called every minute.
    """
    pass
There was a runtime error.

i deleted ML logic and got pretty much the same results--i think the ML black magic is probably generating noise.

Clone Algorithm
11
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This is a template algorithm on Quantopian for you to adapt and fill in.
"""
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC, NuSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn import preprocessing
from collections import Counter
import numpy as np
 
def initialize(context):
    """
    Called once at the start of the algorithm.
    """   
    # If you don't specify a commission, your backtest defaults to $0.0075 per share with a $1 minimum cost per trade.
    
    context.stocks =symbols('XLV', 'XLP', 'XLY','TLT','TLO', 'IEF')  
    
    context.historical_bars = 100
    context.feature_window = 5
    
    # Rebalance every day.
    schedule_function(my_rebalance, date_rules.every_day())
    
    
def my_rebalance(context, data):
    """
    Execute orders according to our schedule_function() timing. 
    """
    prices = data.history(context.stocks, 'price', context.historical_bars, '1d')
    
    for stock in context.stocks:
        try:
            
            ma1 = data.history(stock, 'price', 50, '1d').mean()
            ma2 = data.history(stock, 'price', 200, '1d').mean()
            
            if ma1 > ma2:
                order_target_percent(stock,0.20)
                # order_target_percent(stock,0,style=StopOrder(current_price*0.95))
            elif ma1 < ma2:
                order_target_percent(stock,-0.05) 
                # order_target_percent(stock,0,style=StopOrder(current_price*1.05))
            
        except Exception as e:
            print(str(e))
            
    record('ma1',ma1)
    record('ma2',ma2)
    record('Leverage',context.account.leverage)                   

def handle_data(context,data):
    """
    Called every minute.
    """
    pass
There was a runtime error.