Skip to content

Commit

Permalink
roll states wrong
Browse files Browse the repository at this point in the history
  • Loading branch information
rob committed Jul 1, 2023
1 parent a61516b commit e006e80
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 57 deletions.
10 changes: 5 additions & 5 deletions sysdata/mongodb/mongo_override.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _get_override_object_for_type_and_key(
except missingData:
return self.default_override()

override = _from_dict_to_override(result_dict)
override = from_dict_to_override(result_dict)

return override

Expand All @@ -64,7 +64,7 @@ def _update_other_type_of_override(
self, override_type: str, key: str, new_override_object: Override
):
dict_of_keys = {OVERRIDE_KEY: key, OVERRIDE_TYPE: override_type}
new_override_as_dict = _from_override_to_dict(new_override_object)
new_override_as_dict = from_override_to_dict(new_override_object)

self.mongo_data.add_data(
dict_of_keys, new_override_as_dict, allow_overwrite=True
Expand All @@ -75,7 +75,7 @@ def _get_dict_of_items_with_overrides_for_type(self, override_type: str) -> dict
results = self.mongo_data.get_list_of_result_dicts_for_dict_keys(dict_of_keys)
result_dict_of_overrides = dict(
[
(result_dict[OVERRIDE_KEY], _from_dict_to_override(result_dict))
(result_dict[OVERRIDE_KEY], from_dict_to_override(result_dict))
for result_dict in results
]
)
Expand All @@ -89,13 +89,13 @@ def _delete_all_overrides_without_checking(self):
self.mongo_data.delete_data_without_any_warning(key)


def _from_dict_to_override(result_dict: dict) -> Override:
def from_dict_to_override(result_dict: dict) -> Override:
value = result_dict[OVERRIDE_VALUE]
override = Override.from_numeric_value(value)
return override


def _from_override_to_dict(override: Override) -> dict:
def from_override_to_dict(override: Override) -> dict:
override_as_value = override.as_numeric_value()
override_as_dict = {OVERRIDE_VALUE: override_as_value}

Expand Down
47 changes: 47 additions & 0 deletions sysdata/mongodb/mongo_temporary_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from syscore.constants import arg_not_supplied

from sysdata.production.temporary_override import temporaryOverrideData
from sysdata.mongodb.mongo_override import from_dict_to_override, from_override_to_dict
from sysobjects.production.override import Override
from sysdata.mongodb.mongo_generic import mongoDataWithSingleKey
from syslogging.logger import get_logger

TEMPORARY_OVERRIDE_COLLECTION = "temporary_override_collection"
KEY = "instrument_code"


class mongoTemporaryOverrideData(temporaryOverrideData):
def __init__(
self, mongo_db=arg_not_supplied, log=get_logger("mongoTemporaryOverrideData")
):

super().__init__(log=log)
self._mongo_data = mongoDataWithSingleKey(
TEMPORARY_OVERRIDE_COLLECTION, KEY, mongo_db=mongo_db
)

def __repr__(self):
return "mongoTemporaryOverrideData %s" % str(self.mongo_data)

@property
def mongo_data(self):
return self._mongo_data

def get_stored_override_for_instrument(self, instrument_code: str) -> Override:
override_as_dict = self.mongo_data.get_result_dict_for_key(instrument_code)

return from_dict_to_override(override_as_dict)

def _add_stored_override_without_checking(
self, instrument_code: str, override_for_instrument: Override
):
override_as_dict = from_override_to_dict(override_for_instrument)
self.mongo_data.add_data(
key=instrument_code, data_dict=override_as_dict, allow_overwrite=True
)

def _delete_stored_override_without_checking(self, instrument_code: str):
self.mongo_data.delete_data_without_any_warning(instrument_code)

def does_instrument_have_override_stored(self, instrument_code) -> bool:
return self.mongo_data.key_is_in_data(instrument_code)
4 changes: 2 additions & 2 deletions sysdata/production/override.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def get_cumulative_override_for_instrument_strategy(
strategy_override = self._get_override_for_strategy(
instrument_strategy.strategy_name
)
instrument_override = self._get_override_for_instrument(
instrument_override = self.get_override_for_instrument(
instrument_strategy.instrument_code
)
strategy_instrument_override = self._get_override_for_instrument_strategy(
Expand All @@ -50,7 +50,7 @@ def _get_override_for_instrument_strategy(
strategy_instruments_overrides, key
)

def _get_override_for_instrument(self, instrument_code: str) -> Override:
def get_override_for_instrument(self, instrument_code: str) -> Override:
return self._get_override_object_for_type_and_key(
instrument_overrides, instrument_code
)
Expand Down
49 changes: 49 additions & 0 deletions sysdata/production/temporary_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from sysdata.base_data import baseData

from sysobjects.production.override import Override
from syslogging.logger import get_logger


class temporaryOverrideData(baseData):
"""
Temporary close is a way of temporarily setting position limits to
zero
We use this table to store the old position limits
"""

def __init__(self, log=get_logger("temporaryOverrideData")):
super().__init__(log=log)

def add_stored_override(
self, instrument_code: str, override_for_instrument: Override
):
if self.does_instrument_have_override_stored(instrument_code):
raise Exception(
"Need to clear_stored_override_for_instrument before adding a new one for %s"
% instrument_code
)

self._add_stored_override_without_checking(
instrument_code=instrument_code,
override_for_instrument=override_for_instrument,
)

def get_stored_override_for_instrument(self, instrument_code: str) -> Override:
raise NotImplementedError("Need to use inheriting class")

def clear_stored_override_for_instrument(self, instrument_code: str):
if self.does_instrument_have_override_stored(instrument_code):
self._delete_stored_override_without_checking(instrument_code)

def _add_stored_override_without_checking(
self, instrument_code: str, override_for_instrument: Override
):
raise NotImplementedError("Need to use inheriting class")

def does_instrument_have_override_stored(self, instrument_code) -> bool:
raise NotImplementedError("Need to use inheriting class")

def _delete_stored_override_without_checking(self, instrument_code: str):
raise NotImplementedError("Need to use inheriting class")
93 changes: 88 additions & 5 deletions sysexecution/stack_handler/roll_orders.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import datetime
from dataclasses import dataclass
from sysexecution.orders.named_order_objects import missing_order
from sysobjects.production.roll_state import roll_close_state
from syscore.constants import named_object

from sysdata.data_blob import dataBlob

Expand Down Expand Up @@ -229,18 +231,38 @@ def create_force_roll_orders(
:return: tuple; instrument_order (or missing_order), contract_orders
"""
roll_spread_info = get_roll_spread_information(data, instrument_code)

type_of_roll = flat_roll_or_close_near_contract(data, instrument_code)
instrument_order = create_instrument_roll_order(
roll_spread_info=roll_spread_info, instrument_code=instrument_code
roll_spread_info=roll_spread_info,
instrument_code=instrument_code,
type_of_roll=type_of_roll,
)

list_of_contract_orders = create_contract_roll_orders(
data=data, roll_spread_info=roll_spread_info, instrument_order=instrument_order
data=data,
roll_spread_info=roll_spread_info,
instrument_order=instrument_order,
type_of_roll=type_of_roll,
)

return instrument_order, list_of_contract_orders


roll_state_is_flat_roll = named_object("flat_roll")
roll_state_is_close_near_contract = named_object("close_near_contract")


def flat_roll_or_close_near_contract(data: dataBlob, instrument_code: str):
diag_positions = diagPositions(data)
roll_state = diag_positions.get_roll_state(instrument_code)

if roll_state is roll_close_state:
return roll_state_is_close_near_contract
else:
## force or force outright
return roll_state_is_flat_roll


@dataclass
class rollSpreadInformation:
instrument_code: str
Expand Down Expand Up @@ -294,7 +316,25 @@ def get_roll_spread_information(


def create_instrument_roll_order(
roll_spread_info: rollSpreadInformation, instrument_code: str
roll_spread_info: rollSpreadInformation,
instrument_code: str,
type_of_roll: named_object,
) -> instrumentOrder:
if type_of_roll is roll_state_is_flat_roll:
instrument_order = create_instrument_roll_order_for_flat_roll(
roll_spread_info=roll_spread_info, instrument_code=instrument_code
)
else:
instrument_order = create_instrument_roll_order_closing_priced_contract(
roll_spread_info=roll_spread_info, instrument_code=instrument_code
)

return instrument_order


def create_instrument_roll_order_for_flat_roll(
roll_spread_info: rollSpreadInformation,
instrument_code: str,
) -> instrumentOrder:
strategy = ROLL_PSEUDO_STRATEGY
trade = 0
Expand All @@ -312,18 +352,43 @@ def create_instrument_roll_order(
return instrument_order


def create_instrument_roll_order_closing_priced_contract(
roll_spread_info: rollSpreadInformation,
instrument_code: str,
) -> instrumentOrder:
strategy = ROLL_PSEUDO_STRATEGY
position_priced = roll_spread_info.position_in_priced
trade = -position_priced
instrument_order = instrumentOrder(
strategy,
instrument_code,
trade,
roll_order=True,
order_type=best_order_type,
reference_price=roll_spread_info.reference_price_spread,
reference_contract=ROLL_PSEUDO_STRATEGY,
reference_datetime=roll_spread_info.reference_date,
)

return instrument_order


def create_contract_roll_orders(
data: dataBlob,
roll_spread_info: rollSpreadInformation,
instrument_order: instrumentOrder,
type_of_roll: named_object,
) -> listOfOrders:
diag_positions = diagPositions(data)
instrument_code = instrument_order.instrument_code

if roll_spread_info.position_in_priced == 0:
return missing_order

if diag_positions.is_roll_state_force(instrument_code):
if type_of_roll is roll_state_is_close_near_contract:
contract_orders = create_contract_orders_close_first_contract(roll_spread_info)

elif diag_positions.is_roll_state_force(instrument_code):
contract_orders = create_contract_orders_spread(roll_spread_info)

elif diag_positions.is_roll_state_force_outright(instrument_code):
Expand All @@ -342,6 +407,24 @@ def create_contract_roll_orders(
return contract_orders


def create_contract_orders_close_first_contract(
roll_spread_info: rollSpreadInformation,
) -> listOfOrders:
strategy = ROLL_PSEUDO_STRATEGY

first_order = contractOrder(
strategy,
roll_spread_info.instrument_code,
roll_spread_info.priced_contract_id,
-roll_spread_info.position_in_priced,
reference_price=roll_spread_info.reference_price_priced_contract,
roll_order=True,
order_type=CONTRACT_ORDER_TYPE_FOR_ROLL_ORDERS,
)

return listOfOrders([first_order])


def create_contract_orders_outright(
roll_spread_info: rollSpreadInformation,
) -> listOfOrders:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,13 @@ def get_required_contract_trade_for_instrument(
Depends on roll status and trade vs position:
- roll_states = ['No_Roll', 'Passive', 'Force', 'Force_Outright', 'Roll_Adjusted']
If 'No Roll' then trade current contract
If 'No Roll' then trade current contract (also 'No Open', since constraint applied upstream)
If 'Passive', and no position in current contract: trade next contract
If 'Passive', and reducing trade which leaves zero or something in current contract: trade current contract
If 'Passive', and reducing trade which is larger than current contract position: trade current and next contract
If 'Passive', and increasing trade: trade next contract
If 'Force' or 'Force Outright' or 'Roll_Adjusted': don't trade
If 'Force' or 'Force Outright' or 'Roll_Adjusted' or 'Close': don't trade
:param instrument_order:
:param data: dataBlog
Expand Down
40 changes: 29 additions & 11 deletions sysobjects/production/roll_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@

RollState = Enum(
"RollState",
("No_Roll", "Passive", "Force", "Force_Outright", "Roll_Adjusted", "Close"),
(
"No_Roll",
"Passive",
"Force",
"Force_Outright",
"Roll_Adjusted",
"Close",
"No_Open",
),
)

no_roll_state = RollState.No_Roll
roll_adj_state = RollState.Roll_Adjusted
roll_close_state = RollState.Close

no_open_state = RollState.No_Open
default_state = no_roll_state

roll_explanations = {
Expand All @@ -17,12 +25,13 @@
RollState.Force: "Force the contract to roll ASAP using spread order",
RollState.Force_Outright: "Force the contract to roll ASAP using two outright orders",
RollState.Roll_Adjusted: "Roll adjusted prices from existing priced to new forward contract (after adjusted prices have been changed, will automatically move state to no roll",
RollState.Close: "Close position in near contract by setting position limit to zero",
RollState.Close: "Close position in near contract only",
RollState.No_Open: "No opening trades as close to expiry but forward not liquid enough",
}


def is_forced_roll_state(roll_state: RollState):
if roll_state == RollState.Force or roll_state == RollState.Force_Outright:
if roll_state in [RollState.Force, RollState.Force_Outright, RollState.Close]:
return True
else:
return False
Expand Down Expand Up @@ -59,18 +68,27 @@ def allowable_roll_state_from_current_and_position(
# A 0 suffix indicates we have no position in the priced contract
# A 1 suffix indicates we do have a position in the priced contract
allowed_transition = dict(
No_Roll0=["Roll_Adjusted", "Passive", "No_Roll"],
No_Roll1=["Passive", "Force", "Force_Outright", "No_Roll", "Close"],
Passive0=["Roll_Adjusted", "Passive", "No_Roll"],
Passive1=["Force", "Force_Outright", "Passive", "No_Roll", "Close"],
No_Roll0=["Roll_Adjusted", "Passive", "No_Roll", "No_Open"],
No_Roll1=["Passive", "Force", "Force_Outright", "No_Roll", "Close", "No_Open"],
Passive0=["Roll_Adjusted", "Passive", "No_Roll", "No_Open"],
Passive1=["Force", "Force_Outright", "Passive", "No_Roll", "Close", "No_Open"],
Force0=["Roll_Adjusted", "Passive"],
Force1=["Force", "Force_Outright", "Passive", "No_Roll", "Close"],
Force1=["Force", "Force_Outright", "Passive", "No_Roll", "Close", "No_Open"],
Force_Outright0=["Roll_Adjusted", "Passive"],
Force_Outright1=["Force", "Force_Outright", "Passive", "No_Roll", "Close"],
Force_Outright1=[
"Force",
"Force_Outright",
"Passive",
"No_Roll",
"Close",
"No_Open",
],
Close0=["Roll_Adjusted", "Passive"],
Close1=["Close", "Force", "Force_Outright", "Passive", "No_Roll"],
Close1=["Close", "Force", "Force_Outright", "Passive", "No_Roll", "No_Open"],
Roll_Adjusted0=["No_Roll"],
Roll_Adjusted1=["Roll_Adjusted"],
No_Open0=["Roll_Adjusted", "Passive"],
No_Open1=["Close", "Force", "Force_Outright", "Passive", "No_Roll"],
)

status_plus_position = complete_roll_state(current_roll_state, priced_position)
Expand Down
Loading

0 comments on commit e006e80

Please sign in to comment.