def clear_parents_and_children_if_all_modification_rejected(self, instrument_order_id):
        parent_order = self.instrument_stack.get_order_with_id_from_stack(instrument_order_id)
        log = log_attributes_from_instrument_order(self.log, parent_order)
        list_of_child_order_ids = parent_order.children

        list_of_child_orders = [self.contract_stack.get_order_with_id_from_stack(child_order_id) \
            for child_order_id in list_of_child_order_ids]

        # Check all child orders are in 'rejected' state
        # If any aren't we can't do this
        # This shouldn't happen since we only mark parent orders as rejected once all the kids are
        for child_order in list_of_child_orders:
            if not child_order.is_order_modification_rejected():
                child_log = log_attributes_from_contract_order(self.log, child_order)
                child_log.warn("Instrument order %s has rejected modifying but child contract order %s has not! Can't clear modifications" % \
                         (str(parent_order), str(child_order)))
                return failure

        for child_order_id in list_of_child_order_ids:
            result = self.contract_stack.clear_modification_of_order_on_stack(child_order_id)
            if result is failure:
                log.warn("Can't clear modifications for contract order %d child of %s" %
                         (child_order_id, str(parent_order)))

                return failure

        # Children are completed, we can do parent
        result = self.instrument_stack.clear_modification_of_order_on_stack(instrument_order_id)
        if result is failure:
            log = log_attributes_from_instrument_order(self.log, parent_order)
            log.warn("Cleared modifications for contract order children, but can't clear parent instrument order %s!" % parent_order)
            return failure

        return success
    def pass_modification_from_parent_to_children(self, instrument_order_id):
        """
        Modifications will depend on the parent/child relationship:

        :param instrument_order_id:
        :return:
        """
        instrument_order = self.instrument_stack.get_order_with_id_from_stack(instrument_order_id)
        child_order_ids = instrument_order.children
        log = log_attributes_from_instrument_order(self.log, instrument_order)

        if child_order_ids is no_children:
            # No children
            result = self._modify_childless_instrument_order(instrument_order_id)
            return result

        elif len(child_order_ids)==1:
            # Dead simple: one child
            child_id = child_order_ids[0]
            result = self._modify_single_child_order(child_id, instrument_order)
            return result
        else:
            # multiple children
            result = self._modify_multiple_child_orders(instrument_order)
            return result
    def spawn_children_from_instrument_order_id(self, instrument_order_id):
        instrument_order = self.instrument_stack.get_order_with_id_from_stack(instrument_order_id)
        if instrument_order is missing_order:
            return failure

        log = log_attributes_from_instrument_order(self.log, instrument_order)

        list_of_contract_orders = spawn_children_from_instrument_order(self.data, instrument_order)

        log.msg("List of contract orders spawned %s" % str(list_of_contract_orders))

        list_of_child_ids = self.contract_stack.put_list_of_orders_on_stack(list_of_contract_orders)

        if list_of_child_ids is failure:
            log.msg("Failed to create child orders %s from parent order %s" % (str(list_of_contract_orders),
                                                                                          str(instrument_order)))
            return failure


        for contract_order, child_id in zip(list_of_contract_orders, list_of_child_ids):
            child_log = log_attributes_from_contract_order(log, contract_order)
            child_log.msg("Put child order %s on contract_stack with ID %d from parent order %s" % (str(contract_order),
                                                                                          child_id,
                                                                                          str(instrument_order)))
        result = self.instrument_stack.add_children_to_order(instrument_order.order_id, list_of_child_ids)
        if result is not success:
            log.msg("Error %s when adding children to instrument order %s" % (str(result), str(instrument_order)))
            return failure

        return success
    def clear_parents_and_children_if_all_modification_complete(
            self, instrument_order_id):
        parent_order = self.instrument_stack.get_order_with_id_from_stack(
            instrument_order_id)
        log = log_attributes_from_instrument_order(self.log, parent_order)
        list_of_child_order_ids = parent_order.children

        list_of_child_orders = [self.contract_stack.get_order_with_id_from_stack(child_order_id) \
            for child_order_id in list_of_child_order_ids]

        # Check all child orders are in 'completed modifying' state
        # if any are not, we can't do this
        # (this shouldn't happen, since we only set parent order to completed modifying when all children are set)
        for child_order in list_of_child_orders:
            child_log = log_attributes_from_contract_order(
                self.log, child_order)
            if not child_order.is_order_finished_modifying():
                child_log.warn("Instrument order %s has finished modifying but child contract order %s has not! Can't clear modifications" % \
                         (str(parent_order), str(child_order)))
                return failure

        # clear the modifications for the children
        for child_order_id in list_of_child_order_ids:
            result = self.contract_stack.clear_modification_of_order_on_stack(
                child_order_id)
            if result is failure:

                log.warn(
                    "Can't clear modifications for contract order %d, child of parent %s"
                    % (child_order_id, str(parent_order)))

                return failure

        # Children are completed, we can do parent
        result = self.instrument_stack.clear_modification_of_order_on_stack(
            instrument_order_id)
        if result is failure:
            instrument_log = log_attributes_from_instrument_order(
                self.log, parent_order)
            instrument_log.warn(
                "Cleared modifications for contract order children, but can't clear parent instrument order %s!"
                % parent_order)
            return failure

        return success
    def _modify_childless_instrument_order(self, instrument_order_id):
        instrument_order = self.instrument_stack.get_order_with_id_from_stack(instrument_order_id)
        log = log_attributes_from_instrument_order(self.log, instrument_order)
        # We can mark the parent order as completed modifying and clear the modification
        log.msg("Instrument order %s has no children so modification can take place" % str(instrument_order))
        result = self.instrument_stack.completed_modifying_order_on_stack(instrument_order_id)
        if result is failure:
            return failure
        result = self.instrument_stack.clear_modification_of_order_on_stack(instrument_order_id)

        return result
    def _modify_multiple_child_orders(self, instrument_order):
        """
        OK, it's got multiple child orders. This is more complicated...

        We now have a series of possibilites:
        - equal and opposite positions in each (eg roll order on outright legs, spread instrument)
        - opposite but not equal positions in each (spread instrument)
        - same sign positions in each (passive roll order)

        It's far too complicated to try and deal with all these cases. So instead we allow a cancellation
         order to go ahead (where there is zero unfilled quantity left), but all other types of modifications
         are rejected
        """

        log = log_attributes_from_instrument_order(self.log, instrument_order)
        parent_order_can_be_cancelled = instrument_order.fill_equals_modification_quantity(
        )
        if not parent_order_can_be_cancelled:
            log.warn(
                "Instrument order %s has multiple children and isn't a full cancellation: can't be modified"
                % str(instrument_order))
            return failure

        child_order_ids = instrument_order.children

        for child_id in child_order_ids:
            child_order = self.contract_stack.get_order_with_id_from_stack(
                child_id)
            if child_order is missing_order:
                log.warn(
                    "Child order orderid % is missing for instrument order %s, can't pass on modification"
                    % (child_id, str(instrument_order)))
                return failure
            child_log = log_attributes_from_contract_order(
                self.log, child_order)
            result = self.contract_stack.cancel_order(child_id)
            if type(result) is int:
                # successful cancellation modification
                continue
            elif result is order_is_in_status_modified:
                # Modification is already happening, probably from a previous run of this code
                continue
            else:
                child_log.warn(
                    "Couldn't pass modification from parent instrument order %s to child %s error %s"
                    % (str(instrument_order), str(child_order), str(result)))
                continue

        return success