Awesome
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
- Uniswap V3 LP Tokens as Perpetual Put and Call Options
- Synthetic Options and Short Calls in Uniswap V3
- Rebalancing vs Passive strategies for Uniswap V3 liquidity pools
- Uniswap V3: A Quant Framework to model yield farming returns
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.