Multiple Indicators Combined

I'm trying to improve this algorithm that uses two different crossing moving averages and the rsi as signals and combines them into one:

• How can I reduce the max drawdown? I tried using the stop loss but it does not seem to work. Maybe the algorithm does many unsuccessfull trades.
• How do I let the algorithm select the stocks? Right now they are hand picked and this suffers from both survivorship bias and selection bias.
• Could an ai optimize the weight of the different signals? Now they are all equal to one...
• I tried using the MACD signal too but got worst results so I removed it. It take a lot of code for something so common. Is there a better way to iterate on signals?

Thanks

337
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
import talib

def initialize(context):
context.stocks = symbols('MMM', 'GOOG_L', 'PG', 'DIA', 'AAPL', 'TSLA', 'NFLX', 'SPY')
context.pct_per_stock = 1.0 / len(context.stocks)

context.max_cash_per_stock = 100000.0 / len(context.stocks)
context.LOW_RSI = 20
context.HIGH_RSI = 70
context.STOP_LOSS = 0.97
# Create a variable to track the date change
context.date = None

# The handle_data function is where the real work is done.
# This function is run either every minute
# (in live trading and minute backtesting mode)
# or every day (in daily backtesting mode).
def handle_data(context, data):
todays_date = get_datetime().date()

# Do nothing unless the date has changed
if todays_date == context.date:
return
# Set the new date
context.date = todays_date

# Load historical data for the stocks
prices = history(50, '1d', 'price')

# Use pandas dataframe.apply to get the last RSI value
# for for each stock in our basket
rsi = prices.apply(talib.RSI, timeperiod=14).iloc[-1]

for stock in context.stocks:
ma20  = data[stock].mavg(20)
ma50  = data[stock].mavg(50)
ma100 = data[stock].mavg(100)
ma200 = data[stock].mavg(200)
price = data[stock].price

# Signals : positive means buy
# low RSI = oversold => buy, high RSI = overbought => sell
r1 = (1 if rsi[stock] < context.LOW_RSI else 0) + \
(-1 if rsi[stock] > context.HIGH_RSI else 0)
m1 = 1 if ma50 > ma200 else -1
m2 = 1 if ma20 > ma100 else -1

combo = m1 + m2 + r1
record(combo=combo)

current_position = context.portfolio.positions[stock].amount

# Close position for the stock when the signal is negative and we own shares.
if combo < -1 and current_position > 0:
log.info("Selling {} at {}".format(stock.symbol, price))
# remove stop loss
orders = get_open_orders(stock)
for o in orders:
cancel_order(o)
order_target(stock, 0)

# Enter the position for the stock when the signal is positive and
# our portfolio shares are 0.
elif combo > 1 and current_position <= 0:
order_target_percent(stock, context.pct_per_stock, style=LimitOrder(price))
order_target_percent(stock, context.pct_per_stock, style=StopLimitOrder(price*context.STOP_LOSS, price*context.STOP_LOSS))
There was a runtime error.
9 responses

Im no expert and quite a beginner but I believe that you can generate the stocks to be picked in the before_trading_start part of the source code and then use an SQL query to sift through them and then update_universe based on the parameters you set. Hope this somewhat helped.

You will need a screener to select your candidate stocks. Your screening can be based on trading volumes, valuation ....whatever. It will make your life easy. Once you have screened the stocks, one way to reduce max drawdown is to have a set of performing strategies but with uncorrelated drawdowns. You can let a neural net or any regressor find the weights by itself. But be sure to check the output of your ai algorithm on unseen (out of sample). Hope this helps. Wish you luck.

Great Work, im trying to use this strategy LIVE by hand on an BULL OMX30 X18 derivate for the stockholm OMX30 index.. damn hard the analog way.

I think what you are trying to do is to risk-manage your strategy. Many strategies work alright on average, but using a little overlay of risk management will go a long way in improving your returns and reducing your drawdowns (volatility).

One way to reduce your drawn downs is to use optimization, instead of hard-coding your stop-loss or using moving averages as indicators, why not target a volatility, and scale your strategy weights in conjunction with your target volatility?

A good example will be this (http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2371227)

The authors found that using a dynamic weighted momentum strategy by optimizing the returns using a target volatility of 12% doubles the sharpe ratio of a traditional dual momentum strategy.

I've tried this cloned algo with a few different RSI and MA criteria but it doesent want to sell the shares once it reaches the point where the Combo becomes negative (it just holds them). Is there something that needs to be added to the close section once combo score becomes negative?

The backtest does show it sells shares.
Thanks guys for the suggestions on stock picking and volatility. I might work on it more this week.

337
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
import talib

def initialize(context):
context.stocks = symbols('MMM', 'GOOG_L', 'PG', 'DIA', 'AAPL', 'TSLA', 'NFLX', 'SPY')
context.pct_per_stock = 1.0 / len(context.stocks)

context.max_cash_per_stock = 100000.0 / len(context.stocks)
context.LOW_RSI = 20
context.HIGH_RSI = 70
context.STOP_LOSS = 0.97
# Create a variable to track the date change
context.date = None

# The handle_data function is where the real work is done.
# This function is run either every minute
# (in live trading and minute backtesting mode)
# or every day (in daily backtesting mode).
def handle_data(context, data):
todays_date = get_datetime().date()

# Do nothing unless the date has changed
if todays_date == context.date:
return
# Set the new date
context.date = todays_date

# Load historical data for the stocks
prices = history(50, '1d', 'price')

# Use pandas dataframe.apply to get the last RSI value
# for for each stock in our basket
rsi = prices.apply(talib.RSI, timeperiod=14).iloc[-1]

for stock in context.stocks:
ma20  = data[stock].mavg(20)
ma50  = data[stock].mavg(50)
ma100 = data[stock].mavg(100)
ma200 = data[stock].mavg(200)
price = data[stock].price

# Signals : positive means buy
# low RSI = oversold => buy, high RSI = overbought => sell
r1 = (1 if rsi[stock] < context.LOW_RSI else 0) + \
(-1 if rsi[stock] > context.HIGH_RSI else 0)
m1 = 1 if ma50 > ma200 else -1
m2 = 1 if ma20 > ma100 else -1

combo = m1 + m2 + r1
record(combo=combo)

current_position = context.portfolio.positions[stock].amount

# Close position for the stock when the signal is negative and we own shares.
if combo < -1 and current_position > 0:
log.info("Selling {} at {}".format(stock.symbol, price))
# remove stop loss
orders = get_open_orders(stock)
for o in orders:
cancel_order(o)
order_target(stock, 0)

# Enter the position for the stock when the signal is positive and
# our portfolio shares are 0.
elif combo > 1 and current_position <= 0:
order_target_percent(stock, context.pct_per_stock, style=LimitOrder(price))
order_target_percent(stock, context.pct_per_stock, style=StopLimitOrder(price*context.STOP_LOSS, price*context.STOP_LOSS))
There was a runtime error.

I'm a new user, please forgive me if I understand your question incorrectly... I don't know why you only pick a few stocks as below
MMM', 'GOOG_L', 'PG', 'DIA', 'AAPL', 'TSLA', 'NFLX', 'SPY' which might be a reason to get high max drawdown. Since, GOOG, TSLA, AAPL are volatile stocks. Can you have a dynamic list of stocks based on ATR and price ratios?
Does Quantopian support dynamic list of stock?

Isn't this a bug?

order_target_percent(stock, context.pct_per_stock, style=StopLimitOrder(price*context.STOP_LOSS, price*context.STOP_LOSS))


Should probably be:
 order_target_percent(stock, 0, style=StopLimitOrder(price*context.STOP_LOSS, price*context.STOP_LOSS))