/realized-strangle

Strangle realized volatility on Uniswap V3

Primary LanguagePythonThe UnlicenseUnlicense

Realized Strangle

Open a perpetual strangle (selling a put at a lower strike and a call at a higher strike) position on Uniswap V3 to sell realized volatility and capture fees.

This repository contains the smart contracts from the Alpha Vaults protocol and leverages ribbon.finanace rvol.

TODO

  • Add Testing
    • Strike Price
    • Deploy Vault
    • Deploy Strategy
    • Strategy Parameters
    • Simulations
    • Rebalance
  • Emit rebalance events

Recomended Reading

Usage

Before compiling, run below. The uniswap-v3-periphery package has to be cloned otherwise imports don't work.

brownie pm clone Uniswap/uniswap-v3-periphery@1.0.0

Run tests

brownie test

Run tests with with coveragee brownie test -s --coverage

To deploy, modify the parameters in scripts/deploy_mainnet.py and run:

brownie run deploy_mainnet

To trigger a rebalance, run:

brownie run rebalance

Testing

Experimenting with Brownie and Vol Oracle

## starting up 
brownie console --network mainnet

oracle = Contract.from_explorer("0x8eB47e59E0C03A7D1BFeaFEe6b85910Cefd0ee99")
pricer = Contract.from_explorer("0x966878c047e3e4aDa52Baa93A94bc176FF67b2Dc")

pricer.getOptionDelta(250000000000, 1627160535) / 10000 ## get option delta ex: 8100 = 0.81 delta)

oracle.twap("0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8") / 10**18 ## USDC for ETH
1 / (oracle.twap("0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8") / 10**18) * 1.2 ## x% rise in price converted to ETH to usdc pair

Deploy Contracts

run("deploy_mainnet")
strike = Contract.from_abi("Strike", "0xeC859E8966E83a11a535d452dcFDFc51504Af9F9", StrikeSelection.abi)
real = Contract.from_abi("RealVolStrat", "0xecAF80dE71c980886870F615b6933dC971A94AfA", RealVolStrategy.abi)

current_tick = real.getTick()
## call price
(call_price, call_delta) = strike.getStrikePrice(1627616181, False)
call_price = call_price * 1e22
call_tick = real.testTick(call_price)

## put price
(put_price, put_delta) = strike.getStrikePrice(1627616181, True)
put_price = put_price * 1e22
put_tick = real.testTick(put_price)

put_price = real.testPrice(put_tick) ## check sqrtPriceX96
current_price = real.testPrice(current_tick)
call_price = real.testPrice(call_tick) ## check sqrtPriceX96

# print strike, tick, and deltas
print('put_price={:f}, put_delta={:f}, put_tick={:f}\n current_price={:f}, current_tick={:f}\n call_price={:f},call_delta={:f}, call_tick={:f}'.format(
  put_price / 1e30, 
  1 - (put_delta / 10000), 
  put_tick,
  current_price / 1e30,
  current_tick,
  call_price / 1e30, 
  call_delta / 10000,
  call_tick
))
run("deploy_mainnet")
strike = Contract.from_abi("Strike", "0xeC859E8966E83a11a535d452dcFDFc51504Af9F9", StrikeSelection.abi)
real = Contract.from_abi("RealVolStrat", "0xecAF80dE71c980886870F615b6933dC971A94AfA", RealVolStrategy.abi)
real.getPutStrikePriceAsTicks()
real.getCallStrikePriceAsTicks()

Calculating vault rebalances

tickFloor - real.baseThreshold() # lower
tickCeil + real.baseThreshold()  # upper

# getting ticks
(put_tick, put_strike, put_delta) = real.getPutStrikePriceAsTicks() 
lowerThreshold = put_tick # lower
(call_tick, call_strike, call_delta) = real.getCallStrikePriceAsTicks()
upper_threshold = call_tick # upper

## testing a rebalance
real.rebalance({'from': '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'}) # w/ the keeper addr for now unlocked in brownie-config.yaml

Converting sqrtPriceX96 to spot price

from https://discord.com/channels/597638925346930701/823968973753810945/849542438745014282

1 / (( real.getPrice()/pow(2,96) ) / pow(10,6) )**2
>> 1987.0467456825836

Knowing what the spot price is from the sqrtPriceX96 is helpful for testing since the strikes of the calls and puts are not given in a sqrtPriceX96 format.