mirror of
https://github.com/wassname/options_backtester.git
synced 2026-07-20 12:30:38 +08:00
Strategy now immediately exits when there are missing contracts with the cost imputed
This commit is contained in:
@@ -116,6 +116,11 @@ class Backtest:
|
||||
self._strategy._exit_candidates(l.direction, self.inventory[l.name], options) for l in self._strategy.legs
|
||||
]
|
||||
|
||||
# If a contract is missing we replace the NaN values with those of the inventory
|
||||
# except for cost, which we imput as zero.
|
||||
for leg in leg_candidates:
|
||||
leg['cost'].fillna(0, inplace=True)
|
||||
|
||||
calls_value = -np.sum(
|
||||
np.sum(leg['cost'] * self.inventory['totals']['qty']
|
||||
for leg in leg_candidates if (leg['type'] == 'call').any()))
|
||||
|
||||
@@ -1 +1 @@
|
||||
from .charts import monthly_returns_heatmap
|
||||
from .charts import monthly_returns_heatmap, returns_histogram, returns_chart
|
||||
|
||||
@@ -25,7 +25,7 @@ class Strategy:
|
||||
self.initial_capital = initial_capital
|
||||
self.legs = []
|
||||
self.conditions = []
|
||||
self.exit_thresholds = (0.0, 0.0)
|
||||
self.exit_thresholds = (math.inf, math.inf)
|
||||
|
||||
def add_leg(self, leg):
|
||||
"""Adds leg to the strategy"""
|
||||
@@ -108,7 +108,11 @@ class Strategy:
|
||||
filter_mask = []
|
||||
for i, leg in enumerate(self.legs):
|
||||
flt = leg.exit_filter
|
||||
filter_mask.append(flt(leg_candidates[i]))
|
||||
|
||||
# This mask is to ensure that legs with missing contracts exit.
|
||||
missing_contracts_mask = leg_candidates[i]['cost'].isna()
|
||||
|
||||
filter_mask.append(flt(leg_candidates[i]) | missing_contracts_mask)
|
||||
fields = self._signal_fields((~leg.direction).value)
|
||||
leg_candidates[i] = leg_candidates[i].loc[:, fields.values()]
|
||||
leg_candidates[i].columns = pd.MultiIndex.from_product([["leg_{}".format(i + 1)],
|
||||
@@ -122,7 +126,14 @@ class Strategy:
|
||||
filter_mask = reduce(lambda x, y: x | y, filter_mask)
|
||||
exits_mask = threshold_exits | filter_mask
|
||||
|
||||
exits = pd.concat([l[exits_mask] for l in leg_candidates], axis=1)
|
||||
candidates = pd.concat(leg_candidates, axis=1)
|
||||
|
||||
# If a contract is missing we replace the NaN values with those of the inventory
|
||||
# except for cost, which we imput as zero.
|
||||
imputed_inventory = self._imput_missing_data(inventory)
|
||||
candidates = candidates.fillna(imputed_inventory)
|
||||
|
||||
exits = candidates[exits_mask]
|
||||
total_costs = total_costs[exits_mask] * exits['totals']['qty']
|
||||
|
||||
return (exits, exits_mask, total_costs)
|
||||
@@ -260,5 +271,19 @@ class Strategy:
|
||||
excess_return = (current_cost / entry_cost + 1) * -np.sign(entry_cost)
|
||||
return (excess_return >= profit_pct) | (excess_return <= -loss_pct)
|
||||
|
||||
def _imput_missing_data(self, inventory):
|
||||
"""Returns a copy of the inventory with the cost of all its contracts set to zero.
|
||||
|
||||
Args:
|
||||
inventory (pd.DataFrame): current inventory
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: imputed version of current inventory
|
||||
"""
|
||||
df = inventory.copy()
|
||||
for l in self.legs:
|
||||
df.at[:, (l.name, 'cost')] = 0
|
||||
return df
|
||||
|
||||
def __repr__(self):
|
||||
return "Strategy(legs={}, conditions={})".format(self.legs, self.conditions)
|
||||
|
||||
Reference in New Issue
Block a user