Skip to content

Instantly share code, notes, and snippets.

@johnymontana
Last active May 17, 2023 13:10
Show Gist options
  • Save johnymontana/8116155 to your computer and use it in GitHub Desktop.
Save johnymontana/8116155 to your computer and use it in GitHub Desktop.
My entry for the Neo4j GraphGist December competition. Very simplified options trading in a graph.

Options Trading As A Graph


Introduction

This GraphGist will begin to explore how stock option data can be modeled as a graph, some simple Cypher queries for calculating payout at expiration for an options contract and a very basic look at finding profitable options trades given a specific forecast. Please note that some of the concepts here have been simplified and are only meant as an educational overview of exploring Neo4j and graph data modeling.


Stock Options Data

In finance, an options contract gives the buyer the right to buy/sell (call/put) an underlying security at a set price (the strike price). Typically each contract represents this right for 100 shares of the undelrying. Each contract has an expiration date, after which the contract is not valid. For simplification we will only consider payout at expiration. Thus the data we are concerned with for each contract is:

  • The underlying stock

  • The price of the contract

  • The type of the options contract (put/call)

  • The strike price of the contract

  • The expiration of the contract


Modeling Options Contracts As A Graph

We will consider options on Yahoo! (Symbol: YHOO) for a single expiration, January 2014. Since an options trader can either buy or sell an options contract we will use Buy and Sell nodes to represent this action. Using the graph model shown below, a path from the Underlying node through an options contract node to a Buy/Sell node will represent a specific trade.


CREATE (YHOO: Underlying {symbol: 'YHOO', last: 40.64})

CREATE (YHOO140118C00039000: Call {type: 'Call', strike: 39, expiration: 'Jan 14', last: 1.98})
CREATE (YHOO140118C00040000: Call {type: 'Call', strike: 40, expiration: 'Jan 14', last: 1.30})
CREATE (YHOO140118C00041000: Call {type: 'Call', strike: 41, expiration: 'Jan 14', last: 0.79})
CREATE (YHOO140118C00044000: Call {type: 'Call', strike: 44, expiration: 'Jan 14', last: 0.13})

CREATE (YHOO140118P00038000: Put {type: 'Put', strike: 38, expiration: 'Jan 14', last: 0.17})
CREATE (YHOO140118P00039000: Put {type: 'Put', strike: 39, expiration: 'Jan 14', last: 0.32})
CREATE (YHOO140118P00041000: Put {type: 'Put', strike: 41, expiration: 'Jan 14', last: 1.14})
CREATE (YHOO140118P00042000: Put {type: 'Put', strike: 42, expiration: 'Jan 14', last: 1.74})

CREATE (Long: Buy {type: 'Buy'})
CREATE (Short: Sell {type: 'Sell'})

CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118C00039000)-[:TRADE]->(Long)
CREATE (YHOO140118C00039000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118C00040000)-[:TRADE]->(Long)
CREATE (YHOO140118C00040000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118C00041000)-[:TRADE]->(Long)
CREATE (YHOO140118C00041000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118C00044000)-[:TRADE]->(Long)
CREATE (YHOO140118C00044000)-[:TRADE]->(Short)

CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118P00038000)-[:TRADE]->(Long)
CREATE (YHOO140118P00038000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118P00039000)-[:TRADE]->(Long)
CREATE (YHOO140118P00039000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118P00041000)-[:TRADE]->(Long)
CREATE (YHOO140118P00041000)-[:TRADE]->(Short)
CREATE (YHOO)-[:HAS_CONTRACT]->(YHOO140118P00042000)-[:TRADE]->(Long)
CREATE (YHOO140118P00042000)-[:TRADE]->(Short)

We can query this graph for a specific set of contracts. In this case, find all Put option contracts for YHOO:

MATCH (symbol:Underlying {symbol: 'YHOO'})-[r:HAS_CONTRACT]-(contract:Put)
RETURN contract

Calculating Payout At Expiration

Given a forecast at expiration, we can calculate the payout at expiration assuming the price of the underlying is equal to our forecast at expiration. The formulas are Max(0, K-S) for a Put and Max(0, S-K) for a Call. If the contract is sold, the value at expiration becomes -(Max(0, S-K)) for a Put and -(Max(0, K-S)). The price (represented as 'last' property) of the options contract must also be taken into account.

Given a forecast for our underlying we can represent an options position and calculate the payout at expiration using Cypher:

MATCH (YHOO: Underlying {symbol: 'YHOO'})-[r:HAS_CONTRACT]->(call:Call)-[:TRADE]->(:Buy)
WHERE call.strike = 39
WITH YHOO, call, 45 as Forecast
RETURN (( Forecast - call.strike - call.last) * 100) As Profit

Finding Profitable Options Trading Strategies

We can use Cypher to find profitable options trading strategies, given our forecast at expiration:

MATCH (YHOO: Underlying {symbol: 'YHOO'})-[r:HAS_CONTRACT]->(contract)-[:TRADE]->(Trade)
WITH YHOO, contract, Trade, 43 as Forecast
RETURN CASE
 WHEN contract.type = 'Put' AND Trade.type='Buy' THEN (( CASE WHEN (contract.strike - Forecast) <= 0 THEN 0 ELSE (contract.strike - Forecast) END - contract.last) * 100)
 WHEN contract.type = 'Put' AND Trade.type='Sell' THEN ( -(CASE WHEN (contract.strike - Forecast) <= 0 THEN 0 ELSE (contract.stike - Forecast) END + contract.last) * 100)
 WHEN contract.type = 'Call' AND Trade.type='Buy' THEN (( CASE WHEN (Forecast - contract.strike) <= 0 THEN 0 ELSE (Forecast - contract.strike) END - contract.last) * 100)
 WHEN contract.type = 'Call' AND Trade.type='Sell' THEN (-(CASE WHEN (Forecast - contract.stike) <= 0 THEN 0 ELSE (Forecast - contract.strike) END + contract.last) * 100)
END AS Profit, contract, Trade.type AS Trade ORDER BY Profit DESC LIMIT 5

TODO

This gist shows a very simplified method of modeling stock options contracts in a graph and calculating payouts at expiration given a forecast. For finding profitable options trades it would be nice to include trading strategies that include buying/selling multiple contracts and combinations of trades. More realistic models would take into account implied volatilities, probability of profit, margin requirements and transaction costs. As mentioned in the Introduction the purpose of this GraphGist was only to begin to explore the concepts of modeling options trading as a Graph and how Neo4j Cypher queries could be used in that domain.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment