vix_utils_tddschn 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vix_utils_tddschn-0.2.0/PKG-INFO +110 -0
- vix_utils_tddschn-0.2.0/README.md +82 -0
- vix_utils_tddschn-0.2.0/pyproject.toml +66 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/__init__.py +42 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/cboe_equity_history.py +187 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/cfe-rule-book.pdf +0 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/continuous_maturity.py +146 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/data_notes.md +59 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/download_vix_futures.py +785 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/a_t.ipynb +43 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/hello_x.py +7 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/sample_load_data.py +119 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/sample_plots.py +122 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/vix_utils xarray.ipynb +1387 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/examples/vix_utils.ipynb +2585 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/futures_utils.py +41 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/location.py +18 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/old_download_vix_futures.py +660 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/vix_cash_term_structure.py +205 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/vix_futures_dates.py +490 -0
- vix_utils_tddschn-0.2.0/src/vix_utils/vixutil.py +182 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: vix_utils_tddschn
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Provide VIX Cash and Futures Term Structure as Pandas dataframes
|
|
5
|
+
Keywords: vix,volatility,pandas,vix term structure,cboe
|
|
6
|
+
Author: Doug Ransom, T
|
|
7
|
+
Author-email: Doug Ransom <doug@ransom.vip>, T <45612704+tddschn@users.noreply.github.com>
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
11
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
12
|
+
Requires-Dist: pandas
|
|
13
|
+
Requires-Dist: pandas-market-calendars>=4.4.0
|
|
14
|
+
Requires-Dist: aiofiles
|
|
15
|
+
Requires-Dist: aiohttp[speedups]
|
|
16
|
+
Requires-Dist: openpyxl
|
|
17
|
+
Requires-Dist: appdirs
|
|
18
|
+
Requires-Dist: more-itertools
|
|
19
|
+
Requires-Dist: icecream
|
|
20
|
+
Requires-Dist: matplotlib ; extra == 'examples'
|
|
21
|
+
Requires-Dist: scipy ; extra == 'examples'
|
|
22
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Project-URL: home-page, https://github.com/tddschn/vix_utils
|
|
25
|
+
Provides-Extra: examples
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# VIX Utils
|
|
30
|
+
## Overview
|
|
31
|
+
|
|
32
|
+
*vix_utils* provides some tools for preparing data for analysing the VIX Futures and Cash Term structures.
|
|
33
|
+
|
|
34
|
+
The futures can also contain a 30 day continuous maturity weighting of front two months of vix futures.
|
|
35
|
+
|
|
36
|
+
VIX Futures Data downloaded from [CBOE Futures Historical Data](https://www.cboe.com/us/futures/market_statistics/historical_data/).
|
|
37
|
+
|
|
38
|
+
Vix Cash Data are downloaded from [CBOE Historical Volatility Indexes](https://www.cboe.com/tradable_products/vix/vix_historical_data/).
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
There is an API for Python to load the data into Pandas DataFrames. If you do your analysis in Python, use the API.
|
|
42
|
+
|
|
43
|
+
Since there is no documentation yet, look at the examples in the src/vix_utils/examples folder.
|
|
44
|
+
There is a Jupyter Notebook vix_utils.ipynb in that folder.
|
|
45
|
+
|
|
46
|
+
*Important note for Juypter notebooks.*
|
|
47
|
+
You must use async_get_vix_index_histories and async_load_vix_term_structure
|
|
48
|
+
rather than get_vix_index_histories and load_vix_term_structure. There is an example Jupyter notebook "vix_utils use in Jupyter.ipynb" in the src/vix_utils/examples folder.
|
|
49
|
+
|
|
50
|
+
If you do your analysis in other tools such as R or excel, you can use the command line tool vixutil.
|
|
51
|
+
|
|
52
|
+
`vixutil -h` will give the help. The data are availble in record and wide formats. Just run it and look at the excel or csv output to see what they look like.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
You will need a Python 3.11 or later instalation.
|
|
60
|
+
|
|
61
|
+
### Install from the Python Packaging Index
|
|
62
|
+
|
|
63
|
+
Install using pip from [The Python Package Index ](https://www.pypi.org):
|
|
64
|
+
|
|
65
|
+
`pip install vix_utils`
|
|
66
|
+
|
|
67
|
+
If you want to run the samples, install like this:
|
|
68
|
+
`pip install vix_utils[examples]`
|
|
69
|
+
|
|
70
|
+
The sample to load all the various data frames can be run as:
|
|
71
|
+
'vix_sample_load_data'
|
|
72
|
+
|
|
73
|
+
The sample to plot the history of futures and cash term structures:
|
|
74
|
+
`vix_sample_plots`
|
|
75
|
+
|
|
76
|
+
To load the sample Jupyter notebook, run vix_sample_load_data to figure out where the examples folder is. Browse there with Jupyter and open a notebook.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Development
|
|
80
|
+
|
|
81
|
+
Clone from [github repository](https://github.com/dougransom/vix_utils).
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
`pip install -e .[test,examples]` will:
|
|
85
|
+
- install vix_utils into your python environment, including any command line scripts.
|
|
86
|
+
- install the necessary prequisites for running any
|
|
87
|
+
tests in the `test` folder, and for running the programs in the `src/vixutils/examples` folder.
|
|
88
|
+
|
|
89
|
+
#### Testing
|
|
90
|
+
|
|
91
|
+
The tests directory contains a few tests. This project wasn't developed with
|
|
92
|
+
[Test Driven Development](https://www.agilealliance.org/glossary/tdd/), unit tests have been added to isolate
|
|
93
|
+
and fix defects.
|
|
94
|
+
|
|
95
|
+
However, new features and bug fixes should be developed with [Test Driven Development](https://www.agilealliance.org/glossary/tdd/) practices when practical.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Examples
|
|
99
|
+
Source is in `src/vix_utils/examples`
|
|
100
|
+
|
|
101
|
+
~~~
|
|
102
|
+
## Data Notes
|
|
103
|
+
These dates appear to be missing from the CBOE Data.
|
|
104
|
+
At some point they need to be patched in if they exist.
|
|
105
|
+
```
|
|
106
|
+
[Timestamp('2006-11-10 00:00:00'), Timestamp('2007-01-03 00:00:00'), Timestamp('2021-04-02 00:00:00'), Timestamp('2021-12-24 00:00:00')]
|
|
107
|
+
```
|
|
108
|
+
There seem to be a few dates where spot indexes are missing, you will have to workaround by using fill feature of Pandas datafame, or skip those days, in any analysis.
|
|
109
|
+
~~~
|
|
110
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# VIX Utils
|
|
2
|
+
## Overview
|
|
3
|
+
|
|
4
|
+
*vix_utils* provides some tools for preparing data for analysing the VIX Futures and Cash Term structures.
|
|
5
|
+
|
|
6
|
+
The futures can also contain a 30 day continuous maturity weighting of front two months of vix futures.
|
|
7
|
+
|
|
8
|
+
VIX Futures Data downloaded from [CBOE Futures Historical Data](https://www.cboe.com/us/futures/market_statistics/historical_data/).
|
|
9
|
+
|
|
10
|
+
Vix Cash Data are downloaded from [CBOE Historical Volatility Indexes](https://www.cboe.com/tradable_products/vix/vix_historical_data/).
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
There is an API for Python to load the data into Pandas DataFrames. If you do your analysis in Python, use the API.
|
|
14
|
+
|
|
15
|
+
Since there is no documentation yet, look at the examples in the src/vix_utils/examples folder.
|
|
16
|
+
There is a Jupyter Notebook vix_utils.ipynb in that folder.
|
|
17
|
+
|
|
18
|
+
*Important note for Juypter notebooks.*
|
|
19
|
+
You must use async_get_vix_index_histories and async_load_vix_term_structure
|
|
20
|
+
rather than get_vix_index_histories and load_vix_term_structure. There is an example Jupyter notebook "vix_utils use in Jupyter.ipynb" in the src/vix_utils/examples folder.
|
|
21
|
+
|
|
22
|
+
If you do your analysis in other tools such as R or excel, you can use the command line tool vixutil.
|
|
23
|
+
|
|
24
|
+
`vixutil -h` will give the help. The data are availble in record and wide formats. Just run it and look at the excel or csv output to see what they look like.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
You will need a Python 3.11 or later instalation.
|
|
32
|
+
|
|
33
|
+
### Install from the Python Packaging Index
|
|
34
|
+
|
|
35
|
+
Install using pip from [The Python Package Index ](https://www.pypi.org):
|
|
36
|
+
|
|
37
|
+
`pip install vix_utils`
|
|
38
|
+
|
|
39
|
+
If you want to run the samples, install like this:
|
|
40
|
+
`pip install vix_utils[examples]`
|
|
41
|
+
|
|
42
|
+
The sample to load all the various data frames can be run as:
|
|
43
|
+
'vix_sample_load_data'
|
|
44
|
+
|
|
45
|
+
The sample to plot the history of futures and cash term structures:
|
|
46
|
+
`vix_sample_plots`
|
|
47
|
+
|
|
48
|
+
To load the sample Jupyter notebook, run vix_sample_load_data to figure out where the examples folder is. Browse there with Jupyter and open a notebook.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Development
|
|
52
|
+
|
|
53
|
+
Clone from [github repository](https://github.com/dougransom/vix_utils).
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
`pip install -e .[test,examples]` will:
|
|
57
|
+
- install vix_utils into your python environment, including any command line scripts.
|
|
58
|
+
- install the necessary prequisites for running any
|
|
59
|
+
tests in the `test` folder, and for running the programs in the `src/vixutils/examples` folder.
|
|
60
|
+
|
|
61
|
+
#### Testing
|
|
62
|
+
|
|
63
|
+
The tests directory contains a few tests. This project wasn't developed with
|
|
64
|
+
[Test Driven Development](https://www.agilealliance.org/glossary/tdd/), unit tests have been added to isolate
|
|
65
|
+
and fix defects.
|
|
66
|
+
|
|
67
|
+
However, new features and bug fixes should be developed with [Test Driven Development](https://www.agilealliance.org/glossary/tdd/) practices when practical.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Examples
|
|
71
|
+
Source is in `src/vix_utils/examples`
|
|
72
|
+
|
|
73
|
+
~~~
|
|
74
|
+
## Data Notes
|
|
75
|
+
These dates appear to be missing from the CBOE Data.
|
|
76
|
+
At some point they need to be patched in if they exist.
|
|
77
|
+
```
|
|
78
|
+
[Timestamp('2006-11-10 00:00:00'), Timestamp('2007-01-03 00:00:00'), Timestamp('2021-04-02 00:00:00'), Timestamp('2021-12-24 00:00:00')]
|
|
79
|
+
```
|
|
80
|
+
There seem to be a few dates where spot indexes are missing, you will have to workaround by using fill feature of Pandas datafame, or skip those days, in any analysis.
|
|
81
|
+
~~~
|
|
82
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
keywords=["vix","volatility","pandas","vix term structure","cboe"]
|
|
7
|
+
name = "vix_utils_tddschn"
|
|
8
|
+
authors = [
|
|
9
|
+
{name="Doug Ransom", email="doug@ransom.vip"},
|
|
10
|
+
{name="T", email="45612704+tddschn@users.noreply.github.com"}
|
|
11
|
+
]
|
|
12
|
+
description="Provide VIX Cash and Futures Term Structure as Pandas dataframes"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
17
|
+
"Topic :: Office/Business :: Financial :: Investment"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
readme="README.md"
|
|
21
|
+
requires-python=">=3.11"
|
|
22
|
+
version = "0.2.0"
|
|
23
|
+
|
|
24
|
+
dependencies= [
|
|
25
|
+
"pandas",
|
|
26
|
+
"pandas-market-calendars >= 4.4.0",
|
|
27
|
+
"aiofiles",
|
|
28
|
+
"aiohttp[speedups]",
|
|
29
|
+
"openpyxl",
|
|
30
|
+
"appdirs",
|
|
31
|
+
"more_itertools",
|
|
32
|
+
"icecream"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
test=["pytest"]
|
|
37
|
+
examples=["matplotlib","scipy"]
|
|
38
|
+
|
|
39
|
+
[tool.pytest.ini_options]
|
|
40
|
+
minversion = "7.1.2"
|
|
41
|
+
addopts = "--capture=tee-sys "
|
|
42
|
+
# very important
|
|
43
|
+
#the pythonpath lets pytest load code in your source area
|
|
44
|
+
#in addition to that in site-packages etc.
|
|
45
|
+
#you may want to run your tests without install natlinkcore with flit or pip
|
|
46
|
+
pythonpath = [
|
|
47
|
+
]
|
|
48
|
+
testpaths= [
|
|
49
|
+
"test",
|
|
50
|
+
]
|
|
51
|
+
python_files = [
|
|
52
|
+
"test_*.py",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[project.scripts]
|
|
56
|
+
vixutil = "vix_utils.vixutil:main"
|
|
57
|
+
|
|
58
|
+
#samples
|
|
59
|
+
vix_sample_plots="vix_utils.examples.sample_plots:main"
|
|
60
|
+
vix_sample_load_data="vix_utils.examples.sample_load_data:main"
|
|
61
|
+
|
|
62
|
+
[project.urls]
|
|
63
|
+
home-page = "https://github.com/tddschn/vix_utils"
|
|
64
|
+
|
|
65
|
+
[tool.uv.build-backend]
|
|
66
|
+
module-name = "vix_utils"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A library for preparing VIX Futures and Cash Term Structures for analysis,
|
|
3
|
+
including a continuous maturity VIX Futures term structure.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
__version__ = version("vix_utils_tddschn")
|
|
10
|
+
except PackageNotFoundError:
|
|
11
|
+
__version__ = "0.1.7"
|
|
12
|
+
|
|
13
|
+
from .download_vix_futures import (
|
|
14
|
+
pivot_futures_on_monthly_tenor,
|
|
15
|
+
select_monthly_futures,
|
|
16
|
+
async_load_vix_term_structure,
|
|
17
|
+
load_vix_term_structure,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .vix_cash_term_structure import (
|
|
21
|
+
async_get_vix_index_histories,
|
|
22
|
+
get_vix_index_histories,
|
|
23
|
+
pivot_spot_term_structure_on_symbol,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from .vix_futures_dates import (
|
|
27
|
+
vix_futures_expiry_date_monthly,
|
|
28
|
+
vix_futures_expiry_date_from_trade_date,
|
|
29
|
+
vix_futures_trade_dates_and_expiry_dates,
|
|
30
|
+
vix_constant_maturity_weights,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from .continuous_maturity import (
|
|
34
|
+
continuous_maturity_one_month,
|
|
35
|
+
append_continuous_maturity_one_month,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
from .cboe_equity_history import (
|
|
39
|
+
async_get_cboe_equity_histories,
|
|
40
|
+
get_cboe_equity_histories,
|
|
41
|
+
pivot_equity_histories_on_symbol,
|
|
42
|
+
)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import aiofiles
|
|
6
|
+
import aiohttp
|
|
7
|
+
import asyncio
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from .location import data_dir, make_dir
|
|
11
|
+
|
|
12
|
+
# Browse equities at https://www.cboe.com/us/equities/
|
|
13
|
+
_cboe_equity_history_url = (
|
|
14
|
+
"https://cdn.cboe.com/api/global/delayed_quotes/charts/historical/{symbol}.json"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _normalize_equity_symbols(symbols):
|
|
19
|
+
if isinstance(symbols, str):
|
|
20
|
+
symbols = [symbols]
|
|
21
|
+
out = []
|
|
22
|
+
for symbol in symbols:
|
|
23
|
+
symbol_str = str(symbol).upper().strip()
|
|
24
|
+
if not symbol_str:
|
|
25
|
+
continue
|
|
26
|
+
if symbol_str in out:
|
|
27
|
+
continue
|
|
28
|
+
out.append(symbol_str)
|
|
29
|
+
return out
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _read_equity_json(fname, symbol):
|
|
33
|
+
try:
|
|
34
|
+
with open(fname) as f:
|
|
35
|
+
data = json.load(f)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logging.warning(f"Skipping symbol {symbol}: failed to read {fname}: {e}")
|
|
38
|
+
return pd.DataFrame(
|
|
39
|
+
columns=["Trade Date", "Open", "High", "Low", "Close", "Volume", "Symbol"]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
records = data.get("data", [])
|
|
43
|
+
if not records:
|
|
44
|
+
return pd.DataFrame(
|
|
45
|
+
columns=["Trade Date", "Open", "High", "Low", "Close", "Volume", "Symbol"]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
df = pd.DataFrame(records)
|
|
49
|
+
|
|
50
|
+
col_map = {
|
|
51
|
+
"date": "Trade Date",
|
|
52
|
+
"open": "Open",
|
|
53
|
+
"high": "High",
|
|
54
|
+
"low": "Low",
|
|
55
|
+
"close": "Close",
|
|
56
|
+
"volume": "Volume",
|
|
57
|
+
}
|
|
58
|
+
df = df.rename(columns={k: v for k, v in col_map.items() if k in df.columns})
|
|
59
|
+
df["Symbol"] = symbol
|
|
60
|
+
|
|
61
|
+
for col in ["Open", "High", "Low", "Close"]:
|
|
62
|
+
if col in df.columns:
|
|
63
|
+
df[col] = pd.to_numeric(df[col], errors="coerce")
|
|
64
|
+
if "Volume" in df.columns:
|
|
65
|
+
df["Volume"] = pd.to_numeric(df["Volume"], errors="coerce")
|
|
66
|
+
|
|
67
|
+
df["Trade Date"] = pd.to_datetime(df["Trade Date"], errors="coerce")
|
|
68
|
+
df = df.dropna(subset=["Trade Date", "Close"])
|
|
69
|
+
|
|
70
|
+
ordered_cols = ["Trade Date"]
|
|
71
|
+
for col in ["Open", "High", "Low", "Close", "Volume", "Symbol"]:
|
|
72
|
+
if col in df.columns:
|
|
73
|
+
ordered_cols.append(col)
|
|
74
|
+
df = df[ordered_cols]
|
|
75
|
+
return df
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def async_get_cboe_equity_histories(symbols):
|
|
79
|
+
"""
|
|
80
|
+
Download historical daily OHLCV data for equities/ETFs from CBOE.
|
|
81
|
+
|
|
82
|
+
Uses the endpoint:
|
|
83
|
+
https://cdn.cboe.com/api/global/delayed_quotes/charts/historical/{symbol}.json
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
symbols : str or list of str
|
|
88
|
+
Ticker symbol(s) to download (e.g. ``"SPY"`` or ``["SPY", "NVDA"]``).
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
pd.DataFrame
|
|
93
|
+
Records-format DataFrame with columns:
|
|
94
|
+
Trade Date, Open, High, Low, Close, Volume, Symbol.
|
|
95
|
+
"""
|
|
96
|
+
symbols = _normalize_equity_symbols(symbols)
|
|
97
|
+
|
|
98
|
+
equity_download_dir = Path(data_dir()) / "equity" / "download"
|
|
99
|
+
make_dir(equity_download_dir)
|
|
100
|
+
|
|
101
|
+
async with aiohttp.ClientSession() as session:
|
|
102
|
+
|
|
103
|
+
async def download_one(symbol):
|
|
104
|
+
url = _cboe_equity_history_url.format(symbol=symbol)
|
|
105
|
+
logging.debug(f"Reading URL {url}")
|
|
106
|
+
cache_path = equity_download_dir / f"{symbol}_History.json"
|
|
107
|
+
|
|
108
|
+
async with session.get(url) as resp:
|
|
109
|
+
if resp.status != 200:
|
|
110
|
+
logging.warning(
|
|
111
|
+
f"Skipping symbol {symbol}: {url} returned HTTP {resp.status}"
|
|
112
|
+
)
|
|
113
|
+
return None
|
|
114
|
+
text = await resp.text()
|
|
115
|
+
|
|
116
|
+
async with aiofiles.open(cache_path, mode="w") as f:
|
|
117
|
+
await f.write(text)
|
|
118
|
+
logging.debug(f"Wrote {cache_path}")
|
|
119
|
+
|
|
120
|
+
return symbol, cache_path
|
|
121
|
+
|
|
122
|
+
downloaded = await asyncio.gather(*(download_one(s) for s in symbols))
|
|
123
|
+
|
|
124
|
+
downloaded = [entry for entry in downloaded if entry is not None]
|
|
125
|
+
if not downloaded:
|
|
126
|
+
return pd.DataFrame(
|
|
127
|
+
columns=["Trade Date", "Open", "High", "Low", "Close", "Volume", "Symbol"]
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
frames = [
|
|
131
|
+
frame
|
|
132
|
+
for frame in (_read_equity_json(path, symbol) for symbol, path in downloaded)
|
|
133
|
+
if not frame.empty
|
|
134
|
+
]
|
|
135
|
+
if not frames:
|
|
136
|
+
return pd.DataFrame(
|
|
137
|
+
columns=["Trade Date", "Open", "High", "Low", "Close", "Volume", "Symbol"]
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
result = pd.concat(frames)
|
|
141
|
+
result["Trade Date"] = pd.to_datetime(result["Trade Date"])
|
|
142
|
+
result = result.sort_values(["Trade Date", "Symbol"]).reset_index(drop=True)
|
|
143
|
+
logging.debug(f"Equity histories shape: {result.shape}")
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_cboe_equity_histories(symbols):
|
|
148
|
+
"""
|
|
149
|
+
Download historical daily OHLCV data for equities/ETFs from CBOE.
|
|
150
|
+
|
|
151
|
+
Synchronous wrapper around :func:`async_get_cboe_equity_histories`.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
symbols : str or list of str
|
|
156
|
+
Ticker symbol(s) to download (e.g. ``"SPY"`` or ``["SPY", "NVDA"]``).
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
pd.DataFrame
|
|
161
|
+
Records-format DataFrame with columns:
|
|
162
|
+
Trade Date, Open, High, Low, Close, Volume, Symbol.
|
|
163
|
+
"""
|
|
164
|
+
return asyncio.run(async_get_cboe_equity_histories(symbols=symbols))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def pivot_equity_histories_on_symbol(equity_histories):
|
|
168
|
+
"""
|
|
169
|
+
Pivot equity histories from record format to wide format.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
equity_histories : pd.DataFrame
|
|
174
|
+
Records-format DataFrame as returned by :func:`get_cboe_equity_histories`.
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
pd.DataFrame
|
|
179
|
+
Wide-format DataFrame with Trade Date as index and a MultiIndex of
|
|
180
|
+
(price column, Symbol) as columns.
|
|
181
|
+
"""
|
|
182
|
+
try:
|
|
183
|
+
wide = equity_histories.set_index(["Trade Date", "Symbol"]).unstack()
|
|
184
|
+
except Exception as e:
|
|
185
|
+
logging.error(f"{e} in pivot_equity_histories_on_symbol")
|
|
186
|
+
raise
|
|
187
|
+
return wide
|
|
Binary file
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from operator import mul
|
|
2
|
+
from functools import partial
|
|
3
|
+
import numpy as np
|
|
4
|
+
from .download_vix_futures import \
|
|
5
|
+
pivot_futures_on_monthly_tenor
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from .vix_futures_dates import vix_futures_expiry_date_monthly, \
|
|
10
|
+
vix_futures_expiry_date_from_trade_date, \
|
|
11
|
+
vix_futures_trade_dates_and_expiry_dates, \
|
|
12
|
+
vix_constant_maturity_weights
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
_weighted_column_names=['Open','High','Low','Close','Settle','Change']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def do_weight(trades_df:pd.DataFrame,weight_df:pd.DataFrame,weight_column_name:str,tenor:int):
|
|
20
|
+
"""
|
|
21
|
+
Produces a data frame containing a scaled set of select columns.
|
|
22
|
+
parameters:
|
|
23
|
+
----------
|
|
24
|
+
trades_df: a DataFrame indexed by trade date on axis 0, and by an integer (which represents a tenor which could be monthly or weekly)
|
|
25
|
+
as the first level index on axis 1.
|
|
26
|
+
weight_df: a DataFrame with columns that represent the desired weights.
|
|
27
|
+
weight_column_name: the name of the column with the desired weights.
|
|
28
|
+
tenor: the column index of trades_df for the select columns to be scaled.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
w=weight_df[weight_column_name]
|
|
32
|
+
weight_fn=partial(mul,w) #a function to multiply by w
|
|
33
|
+
tenor_df=trades_df[tenor]
|
|
34
|
+
v=tenor_df.apply(weight_fn) #apply to the relevant columns.
|
|
35
|
+
return v
|
|
36
|
+
|
|
37
|
+
def do_weighting_months(trades_df : pd.DataFrame,weight_df:pd.DataFrame,weights_and_tenors : list[(str,int)]) ->pd.DataFrame:
|
|
38
|
+
""" Produces a data frame containing the weighted mean of select columns.
|
|
39
|
+
parameters:
|
|
40
|
+
----------
|
|
41
|
+
trades_df: a DataFrame indexed by trade date on axis 0, and by an integer (which represents a tenor which could be monthly or weekly)
|
|
42
|
+
as the first level index on axis 1.
|
|
43
|
+
weight_df: a dataframe with columns that represent the desired weights.
|
|
44
|
+
weights_and_tenors: a list of tuples of the name of the column weighting and the tenor to be used to find the columns in trades_df.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
return sum(do_weight(trades_df,weight_df,n,t) for n,t in weights_and_tenors )
|
|
48
|
+
|
|
49
|
+
_weights_and_tenors_vix_front_months=[(f"T{i}W",i) for i in range(1,4)]
|
|
50
|
+
|
|
51
|
+
def do_weighting_front_three_months(trades_df : pd.DataFrame,weight_df : pd.DataFrame) -> pd.DataFrame:
|
|
52
|
+
"""
|
|
53
|
+
produces a weighted mean of the nearest monthly futures resulting in an average of maturity one month.
|
|
54
|
+
parameters:
|
|
55
|
+
----------
|
|
56
|
+
trades_df: a DataFrame indexed by trade date on axis 0, and by Tenor_Monthly (as the first level index) on axis 1.
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
return do_weighting_months(trades_df,weight_df,_weights_and_tenors_vix_front_months)
|
|
60
|
+
|
|
61
|
+
def append_continuous_maturity_one_month(monthly_wide_records : pd.DataFrame)->pd.DataFrame:
|
|
62
|
+
"""
|
|
63
|
+
produces a weighted mean of the two nearest monthly futures (using continous_maturity_30day)
|
|
64
|
+
appends it to the monthly_wide_records, with Monthly_Tenor of 1.5 (for ease of sorting)
|
|
65
|
+
There will be fewer columns as the result of continous_maturity_30day has fewer columns for a tenor than
|
|
66
|
+
monthly_wide_records.
|
|
67
|
+
parameters:
|
|
68
|
+
-----------
|
|
69
|
+
monthly_records:
|
|
70
|
+
A DataFrame in a wide format of Monthly records, as returned by pivot_futures_on_monthly_tenor
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
cm=continuous_maturity_one_month(monthly_wide_records)
|
|
75
|
+
wide_columns=monthly_wide_records[1].columns
|
|
76
|
+
#intersection of columns in the two data frames
|
|
77
|
+
|
|
78
|
+
cols=[col for col in cm.columns if col in wide_columns ]
|
|
79
|
+
new_df1=monthly_wide_records.swaplevel(axis=1)[cols]
|
|
80
|
+
new_cm=cm[cols]
|
|
81
|
+
new_df2=new_df1.swaplevel(axis=1)
|
|
82
|
+
#add a level to new_cm
|
|
83
|
+
d={}
|
|
84
|
+
d[1.5]=new_cm
|
|
85
|
+
e=pd.concat(d,axis=1)
|
|
86
|
+
|
|
87
|
+
#concatenate new_cm (after adding the level of idexing)
|
|
88
|
+
new_df3=pd.concat([new_df2,e],axis=1).sort_index(axis=1)
|
|
89
|
+
return new_df3
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def continuous_maturity_one_month(monthly_wide_records : pd.DataFrame)->pd.DataFrame:
|
|
100
|
+
"""
|
|
101
|
+
produces a weighted mean of the two nearest monthly futures resulting in an average of maturity one month.
|
|
102
|
+
parameters:
|
|
103
|
+
-----------
|
|
104
|
+
monthly_records:
|
|
105
|
+
A DataFrame in a wide format of Monthly records, as returned by pivot_futures_on_monthly_tenor
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
df=vix_futures_trade_dates_and_expiry_dates()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
futures_history=pd.DataFrame(monthly_wide_records)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
weights_all=vix_constant_maturity_weights(df)
|
|
119
|
+
|
|
120
|
+
#we only need the weigths for dates we have trades
|
|
121
|
+
weights=weights_all[weights_all.index.isin(futures_history.index)]
|
|
122
|
+
|
|
123
|
+
#select the front three months and the columns that have trade values
|
|
124
|
+
#we need three because at times teh front month is ignored and the back two contracts are used.
|
|
125
|
+
|
|
126
|
+
with pd.option_context('display.max_columns',None):
|
|
127
|
+
logging.debug(f"\n{'*'*50}\nColumns to weight:\n{futures_history}")
|
|
128
|
+
front_three_months=futures_history[[1,2,3]]
|
|
129
|
+
futures_history_trade_value_columns=front_three_months.swaplevel(axis=1)[_weighted_column_names].swaplevel(axis=1)
|
|
130
|
+
|
|
131
|
+
weighted_values=do_weighting_front_three_months(futures_history_trade_value_columns,weights)
|
|
132
|
+
|
|
133
|
+
#should have the same number of rows
|
|
134
|
+
assert weighted_values.shape[0]==futures_history_trade_value_columns.shape[0]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
df_file=front_three_months.swaplevel(axis=1)["File"]
|
|
138
|
+
weighted_values["File"]=df_file[1]+"+"+df_file[2]
|
|
139
|
+
|
|
140
|
+
weighted_values['Expiry']=weights['Expiry']
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
weighted_values["Tenor_Days"]=(weighted_values['Expiry']-weighted_values.index).dt.days
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
return weighted_values
|