Added strangle and option for reading csv

This commit is contained in:
Javier Rodríguez Chatruc
2019-11-08 10:53:48 -03:00
parent 435a7cadc0
commit 5fa8ae97c8
5 changed files with 97 additions and 4 deletions
@@ -1,17 +1,26 @@
import pandas as pd
import os
from .schema import Schema
class HistoricalOptionsData:
"""Historical Options Data container class."""
def __init__(self, file, schema=None, **params):
if schema:
assert isinstance(schema, Schema)
else:
self.schema = HistoricalOptionsData.default_schema()
self._data = pd.read_hdf(file, **params)
file_extension = os.path.splitext(file)[1]
if file_extension == '.h5':
self._data = pd.read_hdf(file, **params)
elif file_extension == '.csv':
params["parse_dates"] = [
self.schema.expiration.mapping, self.schema.date.mapping
]
self._data = pd.read_csv(file, **params)
columns = self._data.columns
assert all((col in columns for _key, col in self.schema))
+4 -1
View File
@@ -33,7 +33,7 @@ class Schema:
def __setitem__(self, key, value):
self._mappings[key] = value
def __getitem__(self, key):
"""Returns mapping of given `key`"""
return self._mappings[key]
@@ -45,6 +45,9 @@ class Schema:
return "Schema({})".format(
[Field(k, m) for k, m in self._mappings.items()])
def __eq__(self, other):
return self._mappings == other._mappings
class Field:
"""Encapsulates data fields to build filters used by strategies"""
+2
View File
@@ -1,2 +1,4 @@
from .strategy import Strategy
from .strategy_leg import StrategyLeg
from .straddle import Straddle
from .strangle import Strangle
+80
View File
@@ -0,0 +1,80 @@
import pandas as pd
class Strangle:
def __init__(self,
underlying,
strike,
dte,
strike_diff,
shares_per_contract=100,
capital=1000000.0):
self.underlying = underlying
self.strike = strike
self.dte = dte
self.strike_diff = strike_diff
self.inventory = set()
self.shares_per_contract = shares_per_contract
self.capital = capital
def execute_entry(self, date, group):
calls = group.loc[(group.type == 'call')
& (group.strike >= self.strike[0]) &
(group.strike <= self.strike[1]) &
(group.dte >= self.dte[0])
& (group.dte <= self.dte[1])]
puts = group.loc[group.type == 'put']
merge = calls.merge(puts, on=['dte'], suffixes=('_call', '_put'))
merge['ask_sum'] = merge['ask_call'] + merge['ask_put']
merge['strike_diff'] = abs(merge['strike_call'] - merge['strike_put'])
merge_strangle = merge.loc[merge['strike_diff'] <= self.strike_diff]
if merge_strangle.empty:
return
entry_index = merge_strangle['ask_sum'].idxmin()
entry = merge_strangle.loc[entry_index]
cost = sum([entry['ask_sum'] * self.shares_per_contract])
if cost <= self.capital:
self.capital -= cost
self.inventory.add((entry.optionroot_call, entry.dte))
self.inventory.add((entry.optionroot_put, entry.dte))
self._update_trade_log(date, entry.optionroot_call,
entry.type_call,
-entry.ask_call * self.shares_per_contract)
self._update_trade_log(date, entry.optionroot_put, entry.type_put,
-entry.ask_put * self.shares_per_contract)
def execute_exits(self, inventory, date, group):
exits = []
remove_set = set()
for entry in inventory:
exit = group.loc[(group.optionroot == entry[0]) & (group.dte == 1)]
if not exit.empty:
exits.append(exit)
remove_set.add(entry)
for exit in exits:
profit = exit.bid.values[0] * self.shares_per_contract
contract = exit.optionroot.values[0]
type_ = exit.type.values[0]
self.capital += profit
self._update_trade_log(date, contract, type_, profit)
self.inventory.difference_update(remove_set)
def run(self, data):
self.trade_log = pd.DataFrame(
columns=["date", "contract", "type", "profit", "capital"])
for date, group in self._iter_dates(data):
self.execute_entry(date, group)
self.execute_exits(self.inventory, date, group)
return self.trade_log
def _update_trade_log(self, date, contract, type_, profit):
"""Adds entry for the given order to `self.trade_log`."""
self.trade_log.loc[len(
self.trade_log)] = [date, contract, type_, profit, self.capital]
def _iter_dates(self, data):
"""Returns `pd.DataFrameGroupBy` with the given underlying and with contracts grouped by date"""
df = data._data.loc[data._data.underlying == self.underlying]
return df.groupby(data.schema["date"])
-1
View File
@@ -10,7 +10,6 @@ class Strategy:
Takes in a number of `legs` (option contracts), and filters that determine
entry and exit conditions.
"""
def __init__(self, schema):
assert isinstance(schema, Schema)
self.schema = schema