# arbitragerepair
Python modules and jupyter notebook examples for the paper [Detect and Repair
Arbitrage in Price Data of Traded Options](https://arxiv.org/abs/2008.09454).
[![DOI](https://zenodo.org/badge/288789939.svg)](https://zenodo.org/badge/latestdoi/288789939)
## Repair option price data -- remove arbitrage
For a finite collection of call option prices written on the same underlying
asset, there are six types of constraints that ensure their prices to be
statically arbitrage-free. Given violation of the arbitrage constraints, we
repair the price data in a fast, model-independent way to remove all arbitrages.
Some examples of arbitrage repair are shown as below:
![image](https://user-images.githubusercontent.com/32545513/83334755-9666ad80-a2a0-11ea-9910-34137539517b.png)
An arbitrage-free normalised call price surface
<img src="https://render.githubusercontent.com/render/math?math=(T,k) \mapsto c(T,k)">
should satisfy some shape constraints. Assuming smooth surface function
<img src="https://render.githubusercontent.com/render/math?math=c(T,k) \in C^{1,2} (\mathbb{R}_{ %3E 0} \times \mathbb{R}_{\geq 0})">,
then these shape constraints are
- Positivity: <img src="https://render.githubusercontent.com/render/math?math=0 \leq c \leq 1">
- Monotonicity: <img src="https://render.githubusercontent.com/render/math?math=-1\leq\partial c / \partial k \leq 0">, <img src="https://render.githubusercontent.com/render/math?math=\partial c / \partial T \geq 0">
- Convexity: <img src="https://render.githubusercontent.com/render/math?math=\partial^2 c / \partial^2 k \geq 0">
## Code
### Installation
It is recommended to create a new virtual environment and install from pypi.
>```
>pip install arbitragerepair
>```
**Requirements:** ```Python >= 3.8``` and ```CVXOPT >= 1.3.0```.
### Usage
While an example can be found in [this jupyter notebook](notebook/example.ipynb),
the usage of this code consists of the following steps.
**0.** Import packages
>```
>from arbitragerepair import constraints, repair
>```
**1.** Normalise strikes and call prices
The inputs are four 1D ```numpy.array``` objects ```T, K, C, F```, which should be of the same length, representing
time-to-expiries, strike prices, option prices and forward prices.
>```
>normaliser = constraints.Normalise()
>normaliser.fit(T, K, C, F)
>T1, K1, C1 = normaliser.transform(T, K, C)
>```
**2.** Construct arbitrage constraints and detect violation
>```
>mat_A, vec_b, _, _ = constraints.detect(T1, K1, C1, verbose=True)
>```
Setting `verbose=True`, an arbitrage detection report will be shown. An example
is shown below:
>```
>Number of violations to non-negative outright price: 0/13
>Number of violations to non-negative and unit-bounded vertical spread: 0/130
>Number of violations to non-negative butterfly spread: 0/104
>Number of violations to non-negative calendar (horizontal) spread: 0/0
>Number of violations to non-negative calendar vertical spread: 9/513
>Number of violations to non-negative calendar butterfly spread: 126/3070
>```
**3.** Repair arbitrage
Repair using the
<img src="https://render.githubusercontent.com/render/math?math=\ell^1">-norm
objective:
>```
>epsilon = repair.l1(mat_A, vec_b, C1)
>```
Repair using the
<img src="https://render.githubusercontent.com/render/math?math=\ell^1">-BA
objective (where bid-ask spreads data need to be supplied):
>```
>epsilon = repair.l1ba(mat_A, vec_b, C1, spread)
>```
**4.** De-normalise
>```
>K0, C0 = normaliser.inverse_transform(K1, C1 + epsilon)
>```
## Why is repairing arbitrage in price data important?
### Frequent presence of arbitrage in historical price data
We collect daily close (bid, ask and mid) prices from 1st November, 2007 to 31st May,
2018 for OTC FX options from Bloomberg. We count violations of arbitrage constraints
in raw daily close mid-prices over time for some major currencies and emerging market
(EM) currencies.
![Screenshot 2020-05-31 at 17 26 36](https://user-images.githubusercontent.com/32545513/83357422-186bda80-a364-11ea-8293-fc1ea9b6faf5.png)
### Repairing arbitrage can improve robustness of model calibration
We verify that our repair method improves model calibration with more robust parameter
estimates and smaller calibration error.
#### Experiment design
![Screenshot 2020-07-03 at 16 49 52](https://user-images.githubusercontent.com/32545513/86484098-54bc9d00-bd4d-11ea-8fdb-f01ec9c06b76.png)
#### Results
![Screenshot 2020-07-03 at 16 44 28](https://user-images.githubusercontent.com/32545513/86483770-a7498980-bd4c-11ea-88b6-137e6d0c4855.png)
## How do our algorithm and code perform in practice?
All of the following studies were carried out on a quadcore Intel Core i7-8650U CPU
with 32GB RAM. All LPs are solved using the GLPK (GNU Linear Programming Kit) solver
wrapped by the [CVXOPT](https://cvxopt.org/) Python package.
![Screenshot 2020-05-31 at 17 27 11](https://user-images.githubusercontent.com/32545513/83357427-1c97f800-a364-11ea-9f38-bf034ab40952.png)
## The formation and disappearance of executable arbitrage
We can use the our method on order book data for identifying executable arbitrage. An
example is given below. We collect the order book data for all E-mini S&P 500 monthly
European call options from 12:00 ET to 16:10 ET on 12th June, 2020. There is a large
spike of number of arbitrages at around 15:52 ET, a few minutes before the close of
the S&P 500 index market at 16:00 ET. This spike coincided with rallies in the futures
market, while the IV maintained its relatively low level.
![Screenshot 2020-08-19 at 14 56 54](https://user-images.githubusercontent.com/32545513/90644137-4c9cbc00-e22c-11ea-9f01-e5525c1a6575.png)
The formation and disappearance of intra-day executable arbitrage opportunities in the
E-mini S\&P 500 monthly European call option market on 12th June, 2020.
## Citation
>```
>@misc{arbitragerepair2020,
> author = {Samuel N. Cohen and Christoph Reisinger and Sheng Wang},
> title = {arbitragerepair},
> publisher = {GitHub},
> journal = {GitHub repository},
> year = {2020},
> howpublished = {\url{https://github.com/vicaws/arbitragerepair}},
> note = {DOI: 10.5281/zenodo.5338299}
>}
>```
Raw data
{
"_id": null,
"home_page": "https://github.com/vicaws/arbitragerepair",
"name": "arbitragerepair",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "option,arbitrage,quantitative finance,data cleansing,asset pricing",
"author": "Victor Wang",
"author_email": "wangsheng.victor@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/5a/88/636846d255d78355205274b005756cab57eec1ecdb8bb26c0773bf6f1108/arbitragerepair-1.1.0.tar.gz",
"platform": null,
"description": "# arbitragerepair\nPython modules and jupyter notebook examples for the paper [Detect and Repair\nArbitrage in Price Data of Traded Options](https://arxiv.org/abs/2008.09454).\n\n[![DOI](https://zenodo.org/badge/288789939.svg)](https://zenodo.org/badge/latestdoi/288789939)\n\n## Repair option price data -- remove arbitrage\nFor a finite collection of call option prices written on the same underlying\nasset, there are six types of constraints that ensure their prices to be\nstatically arbitrage-free. Given violation of the arbitrage constraints, we\nrepair the price data in a fast, model-independent way to remove all arbitrages.\n\nSome examples of arbitrage repair are shown as below:\n\n![image](https://user-images.githubusercontent.com/32545513/83334755-9666ad80-a2a0-11ea-9910-34137539517b.png)\n\nAn arbitrage-free normalised call price surface\n<img src=\"https://render.githubusercontent.com/render/math?math=(T,k) \\mapsto c(T,k)\">\nshould satisfy some shape constraints. Assuming smooth surface function\n<img src=\"https://render.githubusercontent.com/render/math?math=c(T,k) \\in C^{1,2} (\\mathbb{R}_{ %3E 0} \\times \\mathbb{R}_{\\geq 0})\">,\nthen these shape constraints are\n- Positivity: <img src=\"https://render.githubusercontent.com/render/math?math=0 \\leq c \\leq 1\">\n- Monotonicity: <img src=\"https://render.githubusercontent.com/render/math?math=-1\\leq\\partial c / \\partial k \\leq 0\">, <img src=\"https://render.githubusercontent.com/render/math?math=\\partial c / \\partial T \\geq 0\">\n- Convexity: <img src=\"https://render.githubusercontent.com/render/math?math=\\partial^2 c / \\partial^2 k \\geq 0\">\n\n## Code\n\n### Installation\n\nIt is recommended to create a new virtual environment and install from pypi.\n\n>```\n>pip install arbitragerepair\n>```\n\n**Requirements:** ```Python >= 3.8``` and ```CVXOPT >= 1.3.0```.\n\n### Usage\n\nWhile an example can be found in [this jupyter notebook](notebook/example.ipynb),\nthe usage of this code consists of the following steps.\n\n**0.** Import packages\n\n>```\n>from arbitragerepair import constraints, repair\n>```\n\n**1.** Normalise strikes and call prices\n\nThe inputs are four 1D ```numpy.array``` objects ```T, K, C, F```, which should be of the same length, representing \ntime-to-expiries, strike prices, option prices and forward prices. \n\n>```\n>normaliser = constraints.Normalise()\n>normaliser.fit(T, K, C, F)\n>T1, K1, C1 = normaliser.transform(T, K, C)\n>```\n\n**2.** Construct arbitrage constraints and detect violation\n>```\n>mat_A, vec_b, _, _ = constraints.detect(T1, K1, C1, verbose=True)\n>```\nSetting `verbose=True`, an arbitrage detection report will be shown. An example\nis shown below:\n>```\n>Number of violations to non-negative outright price: 0/13\n>Number of violations to non-negative and unit-bounded vertical spread: 0/130\n>Number of violations to non-negative butterfly spread: 0/104\n>Number of violations to non-negative calendar (horizontal) spread: 0/0\n>Number of violations to non-negative calendar vertical spread: 9/513\n>Number of violations to non-negative calendar butterfly spread: 126/3070\n>```\n\n**3.** Repair arbitrage\n\nRepair using the\n<img src=\"https://render.githubusercontent.com/render/math?math=\\ell^1\">-norm\nobjective:\n\n>```\n>epsilon = repair.l1(mat_A, vec_b, C1)\n>```\n\nRepair using the\n<img src=\"https://render.githubusercontent.com/render/math?math=\\ell^1\">-BA\nobjective (where bid-ask spreads data need to be supplied):\n\n>```\n>epsilon = repair.l1ba(mat_A, vec_b, C1, spread)\n>```\n\n**4.** De-normalise\n\n>```\n>K0, C0 = normaliser.inverse_transform(K1, C1 + epsilon)\n>```\n\n## Why is repairing arbitrage in price data important?\n\n### Frequent presence of arbitrage in historical price data\n\nWe collect daily close (bid, ask and mid) prices from 1st November, 2007 to 31st May, \n2018 for OTC FX options from Bloomberg. We count violations of arbitrage constraints \nin raw daily close mid-prices over time for some major currencies and emerging market \n(EM) currencies.\n\n![Screenshot 2020-05-31 at 17 26 36](https://user-images.githubusercontent.com/32545513/83357422-186bda80-a364-11ea-8293-fc1ea9b6faf5.png)\n\n### Repairing arbitrage can improve robustness of model calibration\n\nWe verify that our repair method improves model calibration with more robust parameter \nestimates and smaller calibration error.\n\n#### Experiment design\n![Screenshot 2020-07-03 at 16 49 52](https://user-images.githubusercontent.com/32545513/86484098-54bc9d00-bd4d-11ea-8fdb-f01ec9c06b76.png)\n\n#### Results\n![Screenshot 2020-07-03 at 16 44 28](https://user-images.githubusercontent.com/32545513/86483770-a7498980-bd4c-11ea-88b6-137e6d0c4855.png)\n\n## How do our algorithm and code perform in practice?\nAll of the following studies were carried out on a quadcore Intel Core i7-8650U CPU \nwith 32GB RAM. All LPs are solved using the GLPK (GNU Linear Programming Kit) solver \nwrapped by the [CVXOPT](https://cvxopt.org/) Python package.\n\n![Screenshot 2020-05-31 at 17 27 11](https://user-images.githubusercontent.com/32545513/83357427-1c97f800-a364-11ea-9f38-bf034ab40952.png)\n\n## The formation and disappearance of executable arbitrage\n\nWe can use the our method on order book data for identifying executable arbitrage. An \nexample is given below. We collect the order book data for all E-mini S&P 500 monthly \nEuropean call options from 12:00 ET to 16:10 ET on 12th June, 2020. There is a large \nspike of number of arbitrages at around 15:52 ET, a few minutes before the close of \nthe S&P 500 index market at 16:00 ET. This spike coincided with rallies in the futures \nmarket, while the IV maintained its relatively low level.\n\n\n![Screenshot 2020-08-19 at 14 56 54](https://user-images.githubusercontent.com/32545513/90644137-4c9cbc00-e22c-11ea-9f01-e5525c1a6575.png)\nThe formation and disappearance of intra-day executable arbitrage opportunities in the\nE-mini S\\&P 500 monthly European call option market on 12th June, 2020.\n## Citation\n\n>```\n>@misc{arbitragerepair2020,\n> author = {Samuel N. Cohen and Christoph Reisinger and Sheng Wang}, \n> title = {arbitragerepair},\n> publisher = {GitHub},\n> journal = {GitHub repository},\n> year = {2020},\n> howpublished = {\\url{https://github.com/vicaws/arbitragerepair}},\n> note = {DOI: 10.5281/zenodo.5338299}\n>}\n>```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Model-free algorithms of detecting and repairing spread, butterfly and calendar arbitrages in European option prices.",
"version": "1.1.0",
"project_urls": {
"Homepage": "https://github.com/vicaws/arbitragerepair"
},
"split_keywords": [
"option",
"arbitrage",
"quantitative finance",
"data cleansing",
"asset pricing"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5a88636846d255d78355205274b005756cab57eec1ecdb8bb26c0773bf6f1108",
"md5": "736f0343202114777abc2531334d9815",
"sha256": "4e1e14578aa8598c1cdb71ce4c3fdd7ef63958ea63230cf8243be4189ae87a71"
},
"downloads": -1,
"filename": "arbitragerepair-1.1.0.tar.gz",
"has_sig": false,
"md5_digest": "736f0343202114777abc2531334d9815",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 14244,
"upload_time": "2024-01-07T07:24:44",
"upload_time_iso_8601": "2024-01-07T07:24:44.479325Z",
"url": "https://files.pythonhosted.org/packages/5a/88/636846d255d78355205274b005756cab57eec1ecdb8bb26c0773bf6f1108/arbitragerepair-1.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-07 07:24:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "vicaws",
"github_project": "arbitragerepair",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "arbitragerepair"
}