Back to Community
Identifying and Enhancing Alpha Factors to Maximize Sharpe Ratio

Hi All,

I created a very basic mean reversion algorithm based on stock returns. I was wondering if anyone could give me suggestions on how to improve my sharpe ratio to 2 or higher while generating some more alpha. I've been looking into the optimize API but can't figure out what my "alpha" should be that I would maximize. Any suggestions would be great!

Thanks,

Rohit

Clone Algorithm
4
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
# Backtest ID: 5934c5d9596dd94d57ac1479
There was a runtime error.
8 responses

So i added some stuff to improve the backtest. The first was the Q1500US() universe, this will save time filtering through penny stocks, and other noise. I also added position counters, so you know how many longs and shorts you have. I also expanded the zscore from 1.5 to 1.65, hoping to find more statistical significance. What is the advantage of using 2.0 as leverage?

Clone Algorithm
9
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
# Backtest ID: 59371013ce199f6d693fd609
There was a runtime error.

Hi Eric,

Thanks for the input! I agree that the ordering logic should be done through pipeline (just because I think its the best way to analyze alpha factors and such) but I'm not too great at using the pipeline API so I chose just code the ordering logic in a separate function. But I think I'll try to move through to pipeline soon. As for the leverage, from what I've read and seen, it allows you to place trades on borrowed money to generate greater returns but it could also lead to heavy losses if not managed properly. Also, US equity regulation allows a maximum leverage of 2 (I think Quantopian allows 3 in their competitions and fund) so my thought was to utilize the most amount of capital I could to achieve the greatest amount of returns.

Thanks,

Rohit

I think if possible I should do this set of code through pipeline:

""" Calculate z-score for all stocks in list
"""

# Get pricing data for the last month  
stock_price = data.history(stock, 'price', 30, '1d')  

# Calculate the returns from past prices  
stock_returns = stock_price.pct_change()[1:]  

# Calculate z-score of the current returns  
zscore = (np.mean(stock_returns[-5]) - np.mean(stock_returns)) / np.std(stock_returns, ddof = 2)  

return zscore

and keep this set of code to use long_weight and short_weight in the optimize API to optimize weights with leverage and position constraints:

""" Calculate weights to be optimized
"""

# Initialize lists  
context.longs = []  
context.shorts = []  
context.zscore= 0.00  
long_weight=0.00  
short_weight=0.00  

"""  
Implement this logic within pipeline  
"""  

for stock in context.my_securities:  

    context.zscore = calculate_zscore(stock,data)  

    if get_open_orders():  
        return  
    # Determine percent of portfolio that can be invested  
    available_percent = max(2.0 - context.account.leverage, 0.0)  

    # When to go long  
    if context.zscore < -1.65:  
        context.longs.append(stock)  

    # When to go short  
    if context.zscore > 1.65:  
        context.shorts.append(stock)  

    if len(context.longs) > 0:  
        # Distribute the available percent across longs  
        long_weight = (0.8 * available_percent) / len(context.longs)  

    if len(context.shorts) > 0:  
        # Distribute the available percent across shorts  
        short_weight = (-0.2 * available_percent) / len(context.shorts)  

return long_weight, short_weight

Thoughts?

I think you could definitely do this in pipeline. I believe you can even use a z-score built-in function. Here's how I would imagine it.

returns= n day returns
zscore= zscore.returns #not quite sure the code
buy= zscore>1.65
sell= zscore<-1.65

screen= buy or sell
pipeline would have the zscore, and then you could optimize by the zscore.

The only thing that would probably change is the selling logic. Optimize API really only adds positions in my experience.

that makes sense. I'll give that a shot. Thanks!

Here's what I got so far.This is still wrong though. The problem is the sell signal. I am not quite sure how to make it sell every day if it is in the -0.15 and 0.15 range. This buys and sells each month based on the zscore, and sells at the end of the month if it is not above 1.65 or below negative 1.65, which really ruins the point of mean reversion.

Clone Algorithm
1
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
# Backtest ID: 593af4fe99f8636e57b8fbe5
There was a runtime error.

I spent some time but (finally) worked on implementing the Optimize API. It kind of does what it should in terms of market neutrality and low volatility but its returns aren't great. I think it would be best to optimize alpha instead of weights but I'm just not sure what the alpha is in this algorithm and how to optimize it.

Clone Algorithm
8
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
# Backtest ID: 594becd048d0a36980536e05
There was a runtime error.

Also I'm not sure if optimize actually sells positions or just orders them, that might be a reason as to why the returns for this were never positive.