- Overview
- Application Logic
- Dependencies
- Frontend UI
- Option Contract
- Oracle Contract
- Backend API
- Team
Option Block is a decentralized stock option clearing house.
It frees people from the centralized stranglehold of national option clearing houses and gives freedom to write uncovered calls and puts against U.S. stocks.
Currently, OptionBlock is a demo it means that all options contracts are trading in tETH (Test ETH) on the Ropsten testnet. tETH has no value. All contracts are settled in cash (tETH) and no shares or moneys are exchanged in this demo.
In this demo only a few stocks are optionable: AAPL, GOOGL, FB, NFXL, AMZN, NVDA, and TSLA. All options are American style, which means you can exercise them when ever you want.
OptionBlock is enabled by the DeFi technology, powered by Ethereum Smart Contracts and in-house Data Oracles.
- Node.js - JavaScript runtime built on Chrome's V8 JavaScript engine
- Web3.js - collection of libraries that allow you to interact with a local or remote ethereum node using HTTP, IPC or WebSocket.
- MetaMask - crypto wallet & gateway to blockchain apps
- Flask - micro web framework written in Python
- yfinance - Yahoo! Finance market data downloader
- Quandl - source for financial, economic and alternative datasets
- SciPy - Python-based ecosystem of open-source software for mathematics, science, and engineering
- Node.js - JavaScript runtime built on Chrome's V8 JavaScript engine
- Solidity via Remix - object-oriented programming language for writing smart contracts
- Web3.js - collection of libraries that allow you to interact with a local or remote ethereum node using HTTP, IPC or WebSocket.
- node-fetch - light-weight module that brings window.fetch to Node.js
- ethereum-tx - Ethereum via Node.js
- Express - web framework for Node.js
- Cron - task scheduler in pure JavaScript for node.js based on GNU crontab
There is no installation required to try the service. However, if you want to deploy the service from the source code, some dependancies need to be installed first:
All Node.js dependancies can be installed through npm
(Node Package Manager). npm
comes with Node.js which can be installed from nodejs.org.
To install all the packages required for the front end or oracale, cd
into the respective folder and run:
npm install
The backend API runs on Flask, which is a Python service. All requirements are available in the requirements.txt
file. To install the requirements from your conda
environment, cd
into the oracle/stock_price_api
directory and run:
conda install --file requirements.txt
All Solidity smart contracts are developed, built and deployed in Remix. The contracts in the demo are deployed on the Ropsten testnet. *Make sure to update the contract addresses of the Solidity option contracts and oracles in dapp.js
, so that they are referenced correctly.
Alternatively, the backend API, oracle and frontend services can be deployed on the web. There following are instructions for deployment on Google Cloud Compute platform in the following order:
- Oracle:
google.cloud.com/appengine
- Options and oracle smart contract: Remix
- Backend API:
google.cloud.com/appengine
- Frontend:
codelabs.developers.google.com
In any case MetaMask must be installed in your browser. MetaMask is a wallet providing signatory services to transact on the Ethereum blockchain witout revealing sensitive financial information. MetaMask can be installed as a browser app through your browsers app store. After installing MetaMask, make sure to connect to the Ropsten testnet. You will also need some Ropsten Test Eth to transact. Here is a list of the most popular faucets:
The front end was developed in Node.js using the Web3.js library to connect to the Ethereum blockchain via MetaMask. The frontend was styled using Materialize library for a responsive UX.
Displays user's current long and short stock option positions. User is able to interact with current positions via Exercise
and Cancel
buttons. Long options can be exercised at any point (if they are in the money) by clicking Exercise
. Short options, which have not been sold yet can be canceled (removed from the marketplace) by clicking Cancel
.
This module lets user write options for select stocks. User selects whether to write a Call
or a Put
.
- Ticker is selected from a dropdown menu titled
Ticker
- Stock price is pulled from an in-house Oracle Smart Contract by clicking the
Get Stock Price from Oracle
button - User is then required to enter the
Strike Price
andShares per Contract
. - Collateral needed to secure the value of the option is then calculated :
Shares per Conract * Strike Price
- User is then required to select option expiry date from the
Expiration Date
calendar selector - Option premium that the option writer desires to charge is then retrived from backend Flask API by clicking
Calc. Recommended Premium
button. The option premium can be adjusted based on the user preference and market conditions. The option premium will automaticall recalculate if the strike price or number of shares per contract is changed.
Displays current open orders. The display is split into Call
and Put
options. Option buyer can buy options by clicking Buy
button next the the desired option contract. The display will update when the order is processed.
Reminder! This is a demo, a beta, a MVP. So sometimes the server is slow and the view will requires a few seconds to refresh, and sometimes the view will not refresh automatically at all. Please refresh the views (by clicking Refresh Portfolio
or Refresh Optionbook
) or reshresh the entire page, if the data on the page is weird.
The Option contract encodes the logic of an American Call or American Put option naked option. For the purpose of a demonstration, when writing naked Call, we ask the writer to produce only Strike * Number of Shares
, thus limiting the potential profit for the buyer to 100% stock movement. This in effect results in a synthetic vertical spread instead of a traditional naked option.
The Option Contract is written in Solidity using the Remix IDE and is deployed on the Ethereum Ropsten Testnet : "0xC4125a834a922B56787D817D707FBDFaF0B74d9A"
.
Option details for each option are stored in the form of a struct:
struct option {
uint strike; //Price in USD option
uint ethPriceAtTimeOfWrite;//Eth Price in USD at time of write
uint premium; //Fee in contract token that option writer charges
uint expiry; //Unix timestamp of expiration time
uint amount; //Amount of tokens the option contract is for
bool isCallOption; //Is this a call option
bool exercised; //Has option been exercised
bool canceled; //Has option been canceled
uint id; //Unique ID of option, also array index
uint latestCost; //Helper to show last updated cost to exercise
address payable writer; //Issuer of option
address payable buyer; //Buyer of option
string ticker; //Ticker of the stock
}
Most of the fields are the same as standard stock options, such as strike price, premium, expiration datetime, amount and whether the option is a call option or a put option. We have two booleans to keep track of the state of the option (exercised/canceled). And finally, we store the addresses of the writer and the buyer for ethereum transactions between the two parties.
All options are stored in a public array on the Options contract, and users can view the details of each contract using its id (array index).
The Options contract has a few public methods for users to interact with the options:
function writeCallOption(uint strike, uint premium, uint shares, uint expiry, uint tknAmt, string memory ticker) public payable;
Allows a user to write a call option. Users will need to provide the strike price of the underlying stock (USD * 100), the premium of this option, the expiration date (unix timestamp), the amount of ethereum this option is for, and the stock's ticker symbol. In addition, users will need to deposit enough ethereum as collateral to this contract; the amount of ethereum sent to the contract should be consistent with the token amount parameter.
function writePutOption(uint strike, uint premium, uint shares, uint expiry, uint tknAmt, string memory ticker) public payable;
Similar to writeCallOption, this function allows users to write covered put options.
function buyOption(uint ID) public payable;
If an option is still available on the market, i.e. the option has not been canceled, is not expired, buyer is null, a user can use the above function to buy the option. The user will need to send the corresponding eth as indicated by the premium field of the option. The premium will be sent to the writer of the option right away.
function cancelOption(uint ID) public;
Users can cancel options that they have written and haven't been bought via the above method. The collateral eth will be refunded to the writer.
function exercise(uint ID) public;
Users have the choice to exercise options that they bought previously, given that the option is not expired, using the exercise method. The value of the option is calculated as follows:
- Call options: (current stock price - strike price) * number of shares / current eth price
- Put options: (strike price - current stock price) * number of shares / current eth price Users will receive eth equal to the value of the option, up to the collateral deposited by the writer. Any remaining eth will be returned to the writer.
function updatePrices() public;
function getAllAvailableOptions() public view returns (option[] memory);
function getMyOptions() public view returns (option[] memory);
function getOptionsBought() public view returns (option[] memory);
In addition, the Options contract provide a few utility methods for the front-end as well as the user to view the options on the market.
Oracle Contract provides a closing stock price data feed to the Options Contract. It also supplies data to the frontend in order to provide the user with the correct data at the time of writing and buying the options as well as when viewing the portfolio. The Oracle also provides ETH-USD datafeed. The Oracle Contract is written in Solidity via Remix, and is deployed on the Ethereum Ropsten Testnet :
AAPL = '0x57960D9E1244deB9181BdC2a6B34968718fed1A4'
GOOGL = '0xBC32E17e2a72F6e97Aa0cA70FfCE9E951E6ef30c'
FB = '0xdc2687b1e955078E12317EAcC7AEb3635E299970'
NFLX = '0xB7703E97FeAC6d2377a8107190F7a057A54a6346'
AMZN = '0x95da0ecE375333e723A5a4387A3EfdCf60E3273c'
NVDA = '0x9Bc082c47B2Cd671B633C86BCF3b53f577968bB9'
TSLA = '0xD3DF5bEaA0C0D89dC4156870b6913C7EA8F74c23'
ETHUSD = '0x7744b083407c57E8DDCd32396699A7D8C6cc305a'
The Oracle service is written in Node.js and is runing as an Express app and is refreshed every 20 minutes via a Cron job.
Connection to the Ethereum Ropsten Testnet is provided by Infura via Web3.js, while the transactions are parsed via ethereum-tx Node.js module. node-fetch handles all imported modules.
Example of an Oracle Contract:
contract StockOracleAAPL {
/*storage*/
uint public close;
string public ticker = "AAPL";
address public owner;
/*contructor*/
constructor() public {
owner = msg.sender;
}
/*function setting price*/
function setClose(uint _close) public {
require(owner == msg.sender, "You are not the administrator of this oracle!");
close = _close;
}
/*function getting the price*/
function getClose() public view returns (uint) {
return close;
}
}
The contract is updated with a new Close
price by sending the value to the setClose()
function, which can be accessed only by the contract administrator. The contract administrator address is hard coded in the oracle.js
file for convinience of running a demo, but in production should always be hidden.
The most up-to-date Close
price can be retrieved by calling getClose()
function or by simply calling the close
public variable.
The backend API was designed to retrieve necessary data for Oracle Contract and Option premium calculation. The API is developed using Flask web framework. Stock data is obtained using yfinance
library. Risk Free Rate for the options calculations is retrieved from Quandl. While Black Scholes option premium calculation is performed with assistance of SciPy module. The API is hosted on Google Cloud App server and is accessible via URL: option-block.ue.r.appspot.com/
.
Closing price for the Oracle Contract is retrived via the following Flask URL query:
/quote?symbol=<TICKER>
Where
symbol = stock ticker
Black-Scholes option premium can be retrieved with the following query:
/option_bs/<symbol>/<price>/<strike>/<mat_date>/<rf>/<call_put_flag>
Where:
symbol = stock ticker
price = stock price, where stock price multipled by 100 (ex. 145.20 = 14520)
strike = strike price, where stike price multipled by 100 (ex. 145.20 = 14520)
mat_date = maturity date (YYYY-MM-DD)
rf = risk free rate in basis points (ex. 0.25% = 25)
call_put_flag = for call pass "c", for put pass "p"
The fastest way to get the option premium data is to obtain market data for options with similar strike price and expiry:
/option_yf/<symbol>/<strike>/<mat_date>/<call_put_flag>
Where:
symbol = stock ticker
strike = strike price, where stike price multipled by 100 (ex. 145.20 = 14520)
mat_date = maturity date (YYYY-MM-DD)
call_put_flag = for call pass "c", for put pass "p"