Back to Community
Tactically short gamma (synthetic via ETFs)

It's freezing here in NYC and I'm sidelined at home with a cold. I figured I'd finally get around to playing with this platform.

Someone had asked earlier about the possibility of backtesting options based strategies off here, lately I've been starting to think about vol based strategies again. Since the platform doesn't have futures or options, I figured I'd work something out and share with the people here.

So we can think of a LETF as a derivative on whatever is being levered (the delta 1 product if you wish). Now I'm sure everyone here is familiar with the decay that occurs with these products, so I won't go into it. Now a not so well known fact is that the decay is directly related to volatility. So if we construct a delta-neutral position between the LETF and its delta 1 underlying, the payoff of that position is similar to a straddle (See figure 1).

Figure1

Now in the real world we'd have issues putting this trade on due to borrow costs on the short side, but for now we'll ignore it as we're just using this as a proxy to be short gamma.

As I hope everyone is aware, you don't want to be consistently short gamma. It's one of those things that works until it doesn't and when it doesn't - the pain is plentiful. So here's a simple first pass at the problem, we're going to take VIX spot and smooth it then tie our position to the current level of SMA of VIX. Basically if the SMA exceeds 30 then we take our position off.

In the backtest it seems to do alright. The max drawdown is concerning, might be reasonable for a PA but you'd likely be blown out in a professional setting.

So where does this leave us? Well as you noticed I used SMA to define my levels as oppose to some other filter and also I never actually go long in this model either. I think the notion of vol regimes is fairly well established and where I'm trying to get at is different filters, strategies, or whatnot will perform better within certain regimes.

This leaves you open a few possibilities such as running some sort of hidden markov model, then running sub-strategies (e.g. filters, long/short, whatever) within each state. It's a hairy path to walk down after this though, as you run a high risk of overfitting your model if you're not careful.

Hope someone gets some type of utility out of this.

-A

EDIT: Ignore my variable naming convention, I became too lazy to change the variable names but context.sds is not using SDS (it's using SSO).

Clone Algorithm
247
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
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def rename_col(df):
    df = df.rename(columns={'Adj Close': 'price'})
    df = df.fillna(method='ffill')
    df = df[['price', 'sid']]
    return df

def initialize(context):
    yahoo_vix_url = "http://ichart.finance.yahoo.com/table.csv?s=%5EVIX&d=0&e=22&f=2014&g=d&a=0&b=2&c=1990&ignore=.csv"
    context.target_notional = 1*pow(10,6)
    context.init_amts = True
    
    fetch_csv(yahoo_vix_url, date_column='Date', date_format='%Y-%m-%d', symbol='vix', usecols=['Adj Close'], post_func=rename_col)
    context.sds = sid(32270)
    context.spy = sid(8554)
    
    set_commission(commission.PerShare(cost=0.0015))
    set_slippage(slippage.FixedSlippage(spread=0.01))
    
def handle_data(context, data):
    vix_data = data['vix']
    
    if context.init_amts:
        context.sds_trade_amt = -context.target_notional/(data[context.sds].close_price) - context.portfolio.positions[context.sds].amount
        context.spy_trade_amt = 2*context.target_notional/data[context.spy].close_price - context.portfolio.positions[context.spy].amount
        context.init_amts = False
        context.ok_trade = True

    if vix_data.mavg(25) > 30:
        order(context.sds, -context.portfolio.positions[context.sds].amount)
        order(context.spy, -context.portfolio.positions[context.spy].amount)
        context.ok_trade=True
    elif context.ok_trade:
        order(context.sds, context.sds_trade_amt)
        order(context.spy, context.spy_trade_amt)
        context.ok_trade=False
    else:
        pass
    
    record(VIX_spot=vix_data['price'])
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.
15 responses

Here's a short follow up post going a little more in depth as to why the payoff of a hedge LETF is similar to that of a straddle:

Figure1

I mentioned in the previous post that with the hedged position we end up with something similar to that of a straddle. I extracted 10-day constant maturity straddles for SPY from its vol surface, then in figure1 I show the equity curve for a hedge LETF and a short ATM 10-day CM straddle on SPY. They do indeed look pretty similar.

eqns1 eqns2 eqns3

I won't go too much into the math here, but in eqns1 the first equation represents the evolution of the LETF where L represents the LETF, lambda your leverage ratio, S the delta 1 underlying which, and let S follow GBM. If you solve this SDE you'll end up with the 2nd line. In eqns2 there we have the payoff for a hedge LETF, then reexpressed as a function of S. Now finally in eqns3, assuming a leverage ratio of 2 and using the handy dandy quadratic equation a la middle school math we end up with the breakeven points. If you'd like to read the original paper refer to Avellaneda & Zhang.

So practically speaking what's going on here? In a nutshell the decay the two exists solely because of the leverage, in order for the ETF provider to remain hedged they end up buying high and selling low (sound like something?). As such the payoff is inextricably tied to volatility (i.e. variance premium).

Ok finally the goal of these posts were to show you guys a few things: 1) it's very possible that whatever position you've put on is just a another form of vol selling, so caveat emptor, and 2) possibly get some ideas flowing on trading vol in a systematic way without futures and options data available.

If I'm not too busy this weekend, I'll do another follow up post by introducing vol regimes and running sub-strategies within given regimes (if someone wants to beat me to it, please feel free).

Hi Al,

Thanks for sharing these - personally I have very little experience with options and volatility trading, but I've been learning more lately through some of our NYC Algo Trading meetup members. Specifically I'm working on getting a speaker lined up who will talk about 'Practical Options Trading' next month in NY. If there are other folks in the community with a beginner's interest like myself I'd encourage them to check out Sinclair's book Volatility Trading (reviewed by Ari Pine here: http://www.pinert.com/newsite/?p=191)

Best wishes, Jess

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Funny, I'm acquaintances with Euan and helped him proof Options Trading (the prequel to Volatility Trading). I haven't had a chance to read the 2nd edition of Volatility Trading, but the 1st one was good. I also recommend Options Market Making, it's a bit outdated but provides some great intuition esp at the beginner level.

Can't emphasize any more that a lot of equity strategies I've come across where you're trading the residual of an underlying versus a basket end up being nothing more than a very complicated way in trading the variance premium (not good, unless that's your intent). Now the flipside of it is that since there are a lot of different ways to trade vol, that creates opportunities to buy low and sell high!

Great stuff, thanks.

Interesting post. I tried the strategy with monthly rebalancing but then the results faded by 2009.

@al t: Rebalancing seems to me the correct approach, any thoughts?

Clone Algorithm
19
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
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def rename_col(df):
    df = df.rename(columns={'Adj Close': 'price'})
    df = df.fillna(method='ffill')
    df = df[['price', 'sid']]
    return df

def initialize(context):
    yahoo_vix_url = "http://ichart.finance.yahoo.com/table.csv?s=%5EVIX&d=0&e=22&f=2014&g=d&a=0&b=2&c=1990&ignore=.csv"
    context.target_notional = context.portfolio.cash
    context.last_dt = None
    
    fetch_csv(yahoo_vix_url, date_column='Date', date_format='%Y-%m-%d', symbol='vix', usecols=['Adj Close'], post_func=rename_col)
    
    context.a_sid = sid(32270)
    context.b_sid = sid(8554)
    context.a_weight = -1.0
    context.b_weight = 2.0
    
    set_commission(commission.PerShare(cost=0.0015))
    set_slippage(slippage.FixedSlippage(spread=0.01))
    
def handle_data(context, data):
    vix_data = data['vix']
    
    record(vix=vix_data['price'])
    
    dt = vix_data.datetime
    
    if vix_data.mavg(25) > 30:
        order_target_percent(context.a_sid, 0.0)
        order_target_percent(context.b_sid, 0.0)
    elif context.last_dt is None or context.last_dt.month != dt.month:
        order_target_percent(context.a_sid, context.a_weight)
        order_target_percent(context.b_sid, context.b_weight)
    
    context.last_dt = dt
    
    
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

Jonas,

Strategy changes at that point, this eqn indicates leaving the position unhedged will result in the short gamma position we're looking for. I'm not sure if a month is long enough for things to manifest themselves.

The hedged LETF isn't a perfect proxy for gamma anyhow, below I've attached data for SPY 10-day constant maturity atmf vols (divs, carry, repo are all taken care of). You can use that to really run a vol trade if you'd like.

Note: I've set a minor barrier of entry here, you'll still have to recover the prices, delta, and whatever else you want from the vols.

Clone Algorithm
5
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
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def rename_col(df):
    df = df.rename(columns={'iv': 'price'})
    df = df.fillna(method='ffill')
    df = df[['price', 'sid']]
    return df

def initialize(context):
    spy10dVol = "https://dl.dropboxusercontent.com/u/107365819/data.csv"
    ivNd = fetch_csv(spy10dVol, date_column='date', date_format ='%Y-%m-%d', symbol='ivNd', usecols=['iv'], post_func=rename_col)
    spy = sid(8554)

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    # Implement your algorithm logic here.

    # data[sid(X)] holds the trade event data for that security.
    # context.portfolio holds the current portfolio state.

    # Place orders with the order(SID, amount) method.

    # TODO: implement your own logic here.
    ivNd = data['ivNd']
    record(spy10dVol=ivNd.price)
    
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.

re balancing is a must but it should be based on the moves of the volatility or based on the net delta expose you have (which is changing on a daily basis).
also i have to admit i don't understand what etf short gamma is used for this as only vix is taken in the code. i will be happy if someone could elaborate.

Al explained the details in his second post; there are no explicit options or derivatives ETFs in the system, but due to the way that LETFs must dynamically rebalance on a daily basis to maintain their desired leverage, they wind up replicating a non-linear payoff, which naturally has a 'gamma' exposure.

it will be much easier when shorting etf :)

So how can we do live trading with this. The date for fetcher has to be hardcoded. Do we hardcode a later date which doesn't exist, or is there someway to always fetch the latest data?

I figured it out. You can set the date for data fetching far in advance, and it just fills up empty slots for future dates. I'm starting to paper trade an algorithm using fetcher today to test it.

Hi Richard,

Glad you found a solution - currently what happens in live trading is that the initialize() method is run each morning when the algo is launched, which results in Fetcher being called once daily. As long as your source CSV is updating with new data each day Fetcher will continue to bring that new data in.

Please let us know if you have any difficulty with the paper traded algo and we'd be happy to help!

Best regards, Jess

Hi Jessica,
The algorithm is loaded and is trading properly based on the fetched data so far.
Rich

Hi,

I would like to trade it with Quantopian virtual account. Is this possible? Regards, D

You can paper trade the algo on Quantopian. To do so, run a full backtest in minute mode, press "Live Trade Algorithm" and select the "Quantopian" option.

This will begin paper trading using a 15 minute delayed price feed. (note, clicking "Broker" will allow you to paper trade and live trade the algo with your IB account).

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.