mirror of
https://github.com/wassname/options_backtester.git
synced 2026-06-27 15:16:03 +08:00
make it a package, get it working with my data
This commit is contained in:
@@ -97,8 +97,8 @@ class Backtest:
|
||||
if sma_days:
|
||||
self.stocks_data.sma(sma_days)
|
||||
|
||||
dates = pd.DataFrame(self.options_data._data[['quotedate',
|
||||
'volume']]).drop_duplicates('quotedate').set_index('quotedate')
|
||||
dates = pd.DataFrame(self.options_data._data[['date',
|
||||
'volume']]).drop_duplicates('date').set_index('date')
|
||||
rebalancing_days = pd.to_datetime(
|
||||
dates.groupby(pd.Grouper(freq=str(rebalance_freq) +
|
||||
'BMS')).apply(lambda x: x.index.min()).values) if rebalance_freq else []
|
||||
|
||||
@@ -2,5 +2,6 @@ from .schema import Schema
|
||||
|
||||
from .historical_options_data import HistoricalOptionsData
|
||||
from .tiingo_data import TiingoData
|
||||
from .option_metrics_data import OptionMetricsData
|
||||
|
||||
__all__ = ['Schema', 'HistoricalOptionsData', 'TiingoData']
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import pandas as pd
|
||||
import os
|
||||
from .schema import Schema
|
||||
|
||||
from bscsi_data.optm_lz.load import load_for_tickers
|
||||
|
||||
|
||||
class OptionMetricsData:
|
||||
"""Historical Options Data container class."""
|
||||
def __init__(self, tickers, schema=None, **params):
|
||||
if schema is None:
|
||||
self.schema = OptionMetricsData.default_schema()
|
||||
|
||||
self._data = load_for_tickers(tickers).reset_index()
|
||||
# self._data['date']=self._data.date.dt.tz_localize('utc')
|
||||
# self._data['exdate']=self._data['exdate'].dt.tz_localize('utc')
|
||||
# print(self._data.head(5))
|
||||
|
||||
columns = self._data.columns
|
||||
for _key, col in self.schema:
|
||||
assert col in columns, f"missing '{col}' in data"
|
||||
# assert all((col in columns for _key, col in self.schema))
|
||||
|
||||
date_col = self.schema['date']
|
||||
expiration_col = self.schema['expiration']
|
||||
|
||||
self._data['dte'] = (self._data[expiration_col] - self._data[date_col]).dt.days
|
||||
self.schema.update({'dte': 'dte'})
|
||||
|
||||
self.start_date = self._data[date_col].min()
|
||||
self.end_date = self._data[date_col].max()
|
||||
|
||||
def apply_filter(self, f):
|
||||
"""Apply Filter `f` to the data. Returns a `pd.DataFrame` with the filtered rows."""
|
||||
return self._data.query(f.query)
|
||||
|
||||
def iter_dates(self):
|
||||
"""Returns `pd.DataFrameGroupBy` that groups contracts by date"""
|
||||
return self._data.groupby(self.schema['date'])
|
||||
|
||||
def iter_months(self):
|
||||
"""Returns `pd.DataFrameGroupBy` that groups contracts by month"""
|
||||
date_col = self.schema['date']
|
||||
iterator = self._data.groupby(pd.Grouper(
|
||||
key=date_col,
|
||||
freq="MS")).apply(lambda g: g[g[date_col] == g[date_col].min()]).reset_index(drop=True).groupby(date_col)
|
||||
return iterator
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Pass method invocation to `self._data`"""
|
||||
|
||||
method = getattr(self._data, attr)
|
||||
if hasattr(method, '__call__'):
|
||||
|
||||
def df_method(*args, **kwargs):
|
||||
return method(*args, **kwargs)
|
||||
|
||||
return df_method
|
||||
else:
|
||||
return method
|
||||
|
||||
def __getitem__(self, item):
|
||||
if isinstance(item, pd.Series):
|
||||
return self._data[item]
|
||||
else:
|
||||
key = self.schema[item]
|
||||
return self._data[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._data[key] = value
|
||||
if key not in self.schema:
|
||||
self.schema.update({key: key})
|
||||
|
||||
def __len__(self):
|
||||
return len(self._data)
|
||||
|
||||
def __repr__(self):
|
||||
return self._data.__repr__()
|
||||
|
||||
def default_schema():
|
||||
"""Returns default schema for Historical Options Data"""
|
||||
schema = Schema.options()
|
||||
schema.update({
|
||||
'underlying': 'secid',
|
||||
'underlying_last': 'forward_price', #last price of underlying
|
||||
'date': 'date',
|
||||
'contract': 'optionid',
|
||||
'type': 'cp_flag',
|
||||
'expiration': 'exdate',
|
||||
'strike': 'strike_price',
|
||||
'bid': 'best_bid',
|
||||
'ask': 'best_offer',
|
||||
'volume': 'volume',
|
||||
'open_interest': 'open_interest',
|
||||
'last': 'forward_price',
|
||||
'impliedvol': 'impl_volatility',
|
||||
'vega': 'vega',
|
||||
'delta': 'delta',
|
||||
'gamma': 'gamma',
|
||||
'theta': 'theta',
|
||||
})
|
||||
return schema
|
||||
|
||||
|
||||
# Index(['symbol', 'symbol_flag', 'exdate', 'last_date', 'cp_flag',
|
||||
# 'strike_price', 'best_bid', 'best_offer', 'volume', 'open_interest',
|
||||
# 'impl_volatility', 'delta', 'gamma', 'vega', 'theta', 'optionid',
|
||||
# 'cfadj', 'am_settlement', 'contract_size', 'ss_flag', 'forward_price',
|
||||
# 'expiry_indicator', 'root', 'suffix', 'secid'],
|
||||
# dtype='object')
|
||||
# Schema([Field(name='underlying', mapping='underlying'), Field(name='underlying_last', mapping='underlying_last'), Field(name='date', mapping='quotedate'), Field(name='contract', mapping='optionroot'), Field(name='type', mapping='type'), Field(name='expiration', mapping='expiration'), Field(name='strike', mapping='strike'), Field(name='bid', mapping='bid'), Field(name='ask', mapping='ask'), Field(name='volume', mapping='volume'), Field(name='open_interest', mapping='openinterest'), Field(name='last', mapping='last'), Field(name='impliedvol', mapping='impliedvol'), Field(name='delta', mapping='delta'), Field(name='gamma', mapping='gamma'), Field(name='theta', mapping='theta'), Field(name='vega', mapping='vega')])
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
setup(
|
||||
name='backtester',
|
||||
packages=find_packages(),
|
||||
version='0.1.0',
|
||||
description='Backtesting moris idea of buying calls 5 qs before earnings, and selling them 1 week before. Apparently 30% annual return',
|
||||
author='wassname',
|
||||
license='proprietary',
|
||||
)
|
||||
Reference in New Issue
Block a user