def passive_roll_child_order(
    data: dataBlob,
    trade: int,
    instrument_order: instrumentOrder,
) -> list:

    log = instrument_order.log_with_attributes(data.log)
    diag_positions = diagPositions(data)
    instrument_code = instrument_order.instrument_code

    diag_contracts = diagContracts(data)
    current_contract = diag_contracts.get_priced_contract_id(instrument_code)
    next_contract = diag_contracts.get_forward_contract_id(instrument_code)

    position_current_contract = (
        diag_positions.get_position_for_instrument_and_contract_date(
            instrument_code, current_contract))

    # Break out because so darn complicated
    if position_current_contract == 0:
        # Passive roll and no position in the current contract, start trading
        # the next contract
        log.msg(
            "Passive roll handling order %s, no position in current contract, entire trade in next contract %s"
            % (str(instrument_order), next_contract))
        return [contractIdAndTrade(next_contract, trade)]

    # ok still have a position in the current contract
    increasing_trade = sign(trade) == sign(position_current_contract)
    if increasing_trade:
        # Passive roll and increasing trade
        # Do it all in next contract
        log.msg(
            "Passive roll handling order %s, increasing trade, entire trade in next contract %s"
            % (str(instrument_order), next_contract))
        return [contractIdAndTrade(next_contract, trade)]

    # ok a reducing trade
    new_position = position_current_contract + trade
    sign_of_position_is_unchanged = sign(position_current_contract) == sign(
        new_position)
    if new_position == 0 or sign_of_position_is_unchanged:
        # A reducing trade that we can do entirely in the current contract
        log.msg(
            "Passive roll handling order %s, reducing trade, entire trade in next contract %s"
            % (str(instrument_order), next_contract))
        return [contractIdAndTrade(current_contract, trade)]

    # OKAY to recap: it's a passive roll, but the trade will be split between
    # current and next
    list_of_child_contract_dates_and_trades = \
        passive_trade_split_over_two_contracts(trade=trade,
                                               current_contract=current_contract,
                                               next_contract=next_contract,
                                               position_current_contract=position_current_contract)
    log.msg(
        "Passive roll handling order %s, reducing trade, split trade between contract %s and %s"
        % (str(instrument_order), current_contract, next_contract))

    return list_of_child_contract_dates_and_trades
def passive_roll_child_order(position_current_contract, current_contract, next_contract, trade, log, instrument_order):
    # Break out because so darn complicated
    if position_current_contract == 0:
        # Passive roll and no position in the current contract, start trading the next
        log.msg("Passive roll handling order %s, no position in current contract, entire trade in next contract %s" %
                (str(instrument_order), next_contract))
        return [(next_contract, trade)]

    # ok still have a position in the current contract
    increasing_trade = sign(trade) == sign(position_current_contract)
    if increasing_trade:
        # Passive roll and increasing trade
        # Do it all in next contract
        log.msg("Passive roll handling order %s, increasing trade, entire trade in next contract %s" %
                (str(instrument_order), next_contract))
        return [(next_contract, trade)]

    # ok a reducing trade
    new_position = position_current_contract + trade
    sign_of_position_is_unchanged = sign(position_current_contract) == sign(new_position)
    if new_position == 0 or sign_of_position_is_unchanged:
        # A reducing trade that we can do entirely in the current contract
        log.msg("Passive roll handling order %s, reducing trade, entire trade in next contract %s" %
                (str(instrument_order), next_contract))
        return [(current_contract, trade)]

    ## OKAY to recap: it's a passive roll, but the trade will be split between current and next
    log.msg("Passive roll handling order %s, reducing trade, split trade between contract %s and %s" %
            (str(instrument_order), current_contract, next_contract))

    trade_in_current_contract = - position_current_contract
    trade_in_next_contract = trade - trade_in_current_contract

    return [(current_contract, trade_in_current_contract), (next_contract, trade_in_next_contract)]
def resolveBS_for_list(trade_list):
    ## result is always positive
    trade = highest_common_factor_for_list(trade_list)

    trade = sign(trade_list[0]) * trade

    return resolveBS(trade)
Example #4
0
    def cut_down_proposed_instrument_trade_okay(self, instrument_trade):

        strategy_name = instrument_trade.strategy_name
        instrument_code = instrument_trade.instrument_code
        proposed_trade = instrument_trade.trade.as_int()

        ## want to CUT DOWN rather than bool possible trades
        ## underneath should be using tradeQuantity and position objects
        ## these will handle abs cases plus legs if required in future

        max_trade_ok_against_strategy_instrument = \
            self.check_if_proposed_trade_okay_against_strategy_instrument_constraint(strategy_name,
                                                                                     instrument_code,
                                                                                     proposed_trade)
        max_trade_ok_against_instrument = \
            self.check_if_proposed_trade_okay_against_instrument_constraint(instrument_code,
                                                                            proposed_trade)

        mini_max_trade = sign(proposed_trade) * \
                         min([abs(max_trade_ok_against_instrument),
                        abs(max_trade_ok_against_strategy_instrument)])

        instrument_trade = instrument_trade.replace_trade_only_use_for_unsubmitted_trades(
            mini_max_trade)

        return instrument_trade
Example #5
0
def expiry_diff(carry_row, floor_date_diff=20):
    """
    Given a pandas row containing CARRY_CONTRACT and PRICE_CONTRACT, both of
    which represent dates

    Return the annualised difference between the dates

    :param carry_row: object with attributes CARRY_CONTRACT and PRICE_CONTRACT
    :type carry_row: pandas row, or something that quacks like it

    :param floor_date_diff: If date resolves to less than this, floor here (*default* 20)
    :type carry_row: pandas row, or something that quacks like it

    :returns: datetime.datetime or datetime.date


    """
    if carry_row.PRICE_CONTRACT == "" or carry_row.CARRY_CONTRACT == "":
        return np.nan
    ans = float((expiry_date(carry_row.CARRY_CONTRACT) -
                 expiry_date(carry_row.PRICE_CONTRACT)).days)
    if abs(ans) < floor_date_diff:
        ans = sign(ans) * floor_date_diff
    ans = ans / CALENDAR_DAYS_IN_YEAR

    return ans
Example #6
0
    def cut_down_proposed_instrument_trade_okay(self, instrument_trade):

        strategy_name = instrument_trade.strategy_name
        instrument_code = instrument_trade.instrument_code
        proposed_trade = instrument_trade.trade.as_int()

        ## want to CUT DOWN rather than bool possible trades
        ## FIXME:
        ## underneath should be using tradeQuantity and position objects
        ## these will handle abs cases plus legs if required in future
        # :FIXME
        instrument_strategy = instrumentStrategy(
            strategy_name=strategy_name, instrument_code=instrument_code)

        max_trade_ok_against_instrument_strategy = \
            self.check_if_proposed_trade_okay_against_instrument_strategy_constraint(instrument_strategy,
                                                                                    proposed_trade)
        max_trade_ok_against_instrument = \
            self.check_if_proposed_trade_okay_against_instrument_constraint(instrument_code,
                                                                            proposed_trade)

        ## FIXME THIS IS UGLY WOULD BE BETTER IF DONE INSIDE TRADE SIZE OBJECT
        mini_max_trade = sign(proposed_trade) * \
                         min([abs(max_trade_ok_against_instrument),
                        abs(max_trade_ok_against_instrument_strategy)])

        instrument_trade = instrument_trade.replace_trade_only_use_for_unsubmitted_trades(
            mini_max_trade)

        return instrument_trade
Example #7
0
def map_forecast_value_scalar(x, threshold, capped_value, a_param, b_param):
    """
    Non linear mapping of x value; replaces forecast capping; with defaults will map 1 for 1

    We want to end up with a function like this, for raw forecast x and mapped forecast m,
        capped_value c and threshold_value t:

    if -t < x < +t: m=0
    if abs(x)>c: m=sign(x)*c*a
    if c < x < -t:   (x+t)*b
    if t < x < +c:   (x-t)*b

    :param x: value to map
    :param threshold: value below which map to zero
    :param capped_value: maximum value we want x to take (without non linear mapping)
    :param a_param: slope
    :param b_param:
    :return: mapped x
    """
    x = float(x)
    if np.isnan(x):
        return x
    if abs(x) < threshold:
        return 0.0
    if x >= -capped_value and x <= -threshold:
        return b_param * (x + threshold)
    if x >= threshold and x <= capped_value:
        return b_param * (x - threshold)
    if abs(x) > capped_value:
        return sign(x) * capped_value * a_param

    raise Exception("This should cover all conditions!")
Example #8
0
def _DEPRECATE_apply_floor_to_date_differential(
        fraction_of_year_between_expiries: float, floor_date_diff: float):
    if abs(fraction_of_year_between_expiries) < floor_date_diff:
        fraction_of_year_between_expiries = \
            sign(fraction_of_year_between_expiries) * floor_date_diff

    return fraction_of_year_between_expiries
Example #9
0
def expiry_diff(carry_row, floor_date_diff=20):
    """
    Given a pandas row containing CARRY_CONTRACT and PRICE_CONTRACT, both of which represent dates

    Return the annualised difference between the dates

    :param carry_row: object with attributes CARRY_CONTRACT and PRICE_CONTRACT
    :type carry_row: pandas row, or something that quacks like it

    :param floor_date_diff: If date resolves to less than this, floor here (*default* 20)
    :type carry_row: pandas row, or something that quacks like it

    :returns: datetime.datetime or datetime.date


    """
    if carry_row.PRICE_CONTRACT == "" or carry_row.CARRY_CONTRACT == "":
        return np.nan
    ans = float((expiry_date(carry_row.CARRY_CONTRACT) -
                 expiry_date(carry_row.PRICE_CONTRACT)).days)
    if abs(ans) < floor_date_diff:
        ans = sign(ans) * floor_date_diff
    ans = ans / CALENDAR_DAYS_IN_YEAR

    return ans
Example #10
0
    def what_trade_is_possible(self, proposed_trade: int):
        abs_proposed_trade = abs(proposed_trade)
        possible_abs_trade = self.what_abs_trade_is_possible(
            abs_proposed_trade)
        # convert to same sign as proposed
        possible_trade = possible_abs_trade * sign(proposed_trade)

        return possible_trade
Example #11
0
    def _apply_reduce_only(self, original_position_no_override,
                           proposed_trade):

        desired_new_position = original_position_no_override + proposed_trade.trade
        if sign(desired_new_position) != sign(original_position_no_override):
            # Closing trade only; don't allow sign to change
            new_trade_value = -original_position_no_override

        elif abs(desired_new_position) > abs(original_position_no_override):
            # Increasing trade not allowed
            new_trade_value = 0
        else:
            # Reducing trade and sign not changing, we'll allow
            new_trade_value = proposed_trade.trade

        proposed_trade.replace_trade_only_use_for_unsubmitted_trades(
            new_trade_value)

        return proposed_trade
Example #12
0
def _apply_reduce_only(original_position_no_override: int,
                       proposed_trade: Order) -> Order:

    proposed_trade_value = proposed_trade.trade.as_single_trade_qty_or_error()
    desired_new_position = original_position_no_override + proposed_trade_value
    if sign(desired_new_position) != sign(original_position_no_override):
        # Wants sign to change, we convert into a pure closing trade
        new_trade_value = -original_position_no_override

    elif abs(desired_new_position) > abs(original_position_no_override):
        # Increasing trade not allowed, zero trade
        new_trade_value = 0
    else:
        # Reducing trade and sign not changing, we'll allow
        new_trade_value = proposed_trade_value

    proposed_trade.replace_required_trade_size_only_use_for_unsubmitted_trades(
        tradeQuantity(new_trade_value))

    return proposed_trade
Example #13
0
def apply_fixed_position(position):
    """
    Turn a variable position into one that is held constant regardless of changes in volatility

    :param position: Raw position series, without stoploss or entry / exit logic
    :return: New position series
    """

    # assume all lined up
    current_position = 0.0
    new_position = []

    for iday in range(len(position)):
        original_position_now = position[iday]

        if current_position == 0.0:
            # no position, check for signal
            if np.isnan(original_position_now):
                # no signal
                new_position.append(0.0)
                continue
            if original_position_now > 0.0 or original_position_now < 0.0:
                # go long or short
                current_position = original_position_now
                new_position.append(current_position)
                continue

        if sign(current_position) != sign(original_position_now):
            # changed sign
            current_position = original_position_now
            new_position.append(current_position)
            continue

        # already holding a position of same sign
        new_position.append(current_position)

    new_position = pd.DataFrame(new_position, position.index)

    return new_position
Example #14
0
def calculate_direction(
    optimum_weight: float,
    minimum: float = -A_VERY_LARGE_NUMBER,
    maximum: float = A_VERY_LARGE_NUMBER,
) -> float:
    if minimum >= 0:
        return 1

    if maximum <= 0:
        return -1

    if np.isnan(optimum_weight):
        return 1

    return sign(optimum_weight)
Example #15
0
    def get_spread_price(self, list_of_prices):
        assert len(self._trade_or_fill_qty) == len(list_of_prices)

        if len(self._trade_or_fill_qty) == 1:
            return list_of_prices[0]

        # spread price won't make sense otherwise
        assert sum(self._trade_or_fill_qty) == 0

        sign_to_adjust = sign(self._trade_or_fill_qty[0])
        multiplied_prices = [
            x * y * sign_to_adjust
            for x, y in zip(self._trade_or_fill_qty, list_of_prices)
        ]

        return sum(multiplied_prices)
Example #16
0
def fraction_of_year_between_price_and_carry_expiries(carry_row,
                                                      floor_date_diff: int = 1
                                                      ) -> float:
    """
    Given a pandas row containing CARRY_CONTRACT and PRICE_CONTRACT, both of
    which represent dates

    Return the difference between the dates as a fraction

    Positive means PRICE BEFORE CARRY, negative means CARRY BEFORE PRICE

    :param carry_row: object with attributes CARRY_CONTRACT and PRICE_CONTRACT
    :type carry_row: pandas row, or something that quacks like it

    :param floor_date_diff: If date resolves to less than this, floor here (*default* 20)
    :type int

    :returns: float

    >>> import pandas as pd
    >>> carry_df = pd.DataFrame(dict(PRICE_CONTRACT =["20200601", "20200601", "20200601"],\
                                    CARRY_CONTRACT = ["20200303", "20200905", "20200603"]))
    >>> fraction_of_year_between_price_and_carry_expiries(carry_df.iloc[0])
    -0.2464065708418891
    >>> fraction_of_year_between_price_and_carry_expiries(carry_df.iloc[1])
    0.26283367556468173
    >>> fraction_of_year_between_price_and_carry_expiries(carry_df.iloc[2], floor_date_diff= 50)
    0.13689253935660506

    """
    if carry_row.PRICE_CONTRACT == "" or carry_row.CARRY_CONTRACT == "":
        return np.nan
    period_between_expiries =                 get_datetime_from_datestring(carry_row.CARRY_CONTRACT) \
                                              - get_datetime_from_datestring(carry_row.PRICE_CONTRACT)

    days_between_expiries = period_between_expiries.days

    if abs(days_between_expiries) < floor_date_diff:
        days_between_expiries = sign(days_between_expiries) * floor_date_diff

    ## Annualise, ensuring float output
    fraction_of_year_between_expiries = float(
        days_between_expiries) / CALENDAR_DAYS_IN_YEAR

    return fraction_of_year_between_expiries
Example #17
0
    def get_spread_price(self, list_of_prices):
        if list_of_prices is None:
            return None
        if isinstance(list_of_prices, int) or isinstance(
                list_of_prices, float):
            list_of_prices = [list_of_prices]

        assert len(self._trade_or_fill_qty) == len(list_of_prices)

        if len(self._trade_or_fill_qty) == 1:
            return list_of_prices[0]

        # spread price won't make sense otherwise
        assert sum(self._trade_or_fill_qty) == 0

        sign_to_adjust = sign(self._trade_or_fill_qty[0])
        multiplied_prices = [
            x * y * sign_to_adjust
            for x, y in zip(self._trade_or_fill_qty, list_of_prices)
        ]

        return sum(multiplied_prices)
Example #18
0
    def what_trade_is_possible(self, trade: int) -> int:
        if self.position_limit is NO_LIMIT:
            return trade

        position = self.position
        new_position = position + trade

        # position limit should be abs, but just in case...
        abs_position_limit = abs(self.position_limit)
        signed_position_limit = int(abs_position_limit * sign(new_position))

        if abs(new_position) <= abs_position_limit:
            possible_trade = trade

        elif trade > 0 and new_position >= 0:
            possible_trade = max(0, signed_position_limit - position)

        elif trade < 0 and new_position < 0:
            possible_trade = min(0, signed_position_limit - position)
        else:
            possible_trade = 0

        return int(possible_trade)
Example #19
0
def stoploss(price, vol, position, Xfactor=4):
    """
    Apply trailing stoploss

    :param price:
    :param vol: eg system.rawdata.daily_returns_volatility("SP500")
    :param position: Raw position series, without stoploss or entry / exit logic
    :return: New position series
    """

    # assume all lined up
    current_position = 0.0
    previous_position = 0.0
    new_position = []
    price_list_since_position_held = []

    for iday in range(len(price)):
        current_price = price[iday]

        if current_position == 0.0:
            # no position, check for signal
            original_position_now = position[iday]
            if np.isnan(original_position_now):
                # no signal
                new_position.append(0.0)
                continue
            if original_position_now > 0.0 or original_position_now < 0.0:
                # potentially going long / short
                # check last position to avoid whipsaw
                if previous_position == 0.0 or sign(
                        original_position_now) != sign(previous_position):
                    # okay to do this - we don't want to enter a new position unless sign changed
                    # we set the position at the sized position at moment of inception
                    current_position = original_position_now
                    price_list_since_position_held.append(current_price)
                    new_position.append(current_position)
                    continue
            # if we've made it this far then:
            # no signal
            new_position.append(0.0)
            continue

        # already holding a position
        # calculate HWM
        sign_position = sign(current_position)
        price_list_since_position_held.append(current_price)
        current_vol = vol[iday]
        trailing_factor = current_vol * Xfactor

        if sign_position == 1:
            # long
            hwm = np.nanmax(price_list_since_position_held)
            threshold = hwm - trailing_factor
            close_trade = current_price < threshold
        else:
            # short
            hwm = np.nanmin(price_list_since_position_held)
            threshold = hwm + trailing_factor
            close_trade = current_price > threshold

        if close_trade:
            previous_position = copy(current_position)
            current_position = 0.0
            # note if we don't close the current position is maintained
            price_list_since_position_held = []

        new_position.append(current_position)

    new_position = pd.DataFrame(new_position, price.index)

    return new_position
Example #20
0
 def sign_equal(self, other):
     return all([sign(x) == sign(y) for x, y in zip(self, other)])
Example #21
0
 def buy_or_sell(self) -> int:
     # sign of trade quantity
     return sign(self[0])
def resolveBS_for_calendar_spread(trade_list):
    trade = highest_common_factor_for_list(trade_list)

    trade = sign(trade_list[0]) * trade

    return resolveBS(trade)
Example #23
0
def apply_floor_to_date_differential(days_between_expiries: float,
                                     floor_date_diff: float):
    if abs(days_between_expiries) < floor_date_diff:
        days_between_expiries = sign(days_between_expiries) * floor_date_diff

    return days_between_expiries
Example #24
0
 def buy_or_sell(self):
     return sign(self.qty[0])
Example #25
0
def what_trade_is_possible_single_leg_trade(position: int, position_limit: int, proposed_trade: int)-> int:
    """
    >>> what_trade_is_possible(1, 1, 0)
    0
    >>> what_trade_is_possible(5, 1, 0)
    0
    >>> what_trade_is_possible(0, 3, 1)
    1
    >>> what_trade_is_possible(0, 3, 2)
    2
    >>> what_trade_is_possible(0, 3, 3)
    3
    >>> what_trade_is_possible(0, 3, 4)
    3
    >>> what_trade_is_possible(0, 3, -1)
    -1
    >>> what_trade_is_possible(0, 3, -2)
    -2
    >>> what_trade_is_possible(0, 3, -3)
    -3
    >>> what_trade_is_possible(0, 3, -4)
    -3
    >>> what_trade_is_possible(2, 3, 1)
    1
    >>> what_trade_is_possible(2, 3, 2)
    1
    >>> what_trade_is_possible(2, 3, -2)
    -2
    >>> what_trade_is_possible(2, 3, -4)
    -4
    >>> what_trade_is_possible(2, 3, -5)
    -5
    >>> what_trade_is_possible(2, 3, -6)
    -5
    >>> what_trade_is_possible(5, 3, 2)
    0
    >>> what_trade_is_possible(5, 3, -1)
    -1
    >>> what_trade_is_possible(5, 3, -2)
    -2
    >>> what_trade_is_possible(5, 3, -9)
    -8
    >>> what_trade_is_possible(2, 3, -4)
    -4
    >>> what_trade_is_possible(2, 3, -5)
    -5
    >>> what_trade_is_possible(2, 3, -6)
    -5
    >>> what_trade_is_possible(0, 3, 1)
    1
    >>> what_trade_is_possible(0, 3, -4)
    -3
    >>> what_trade_is_possible(-2, 3, -1)
    -1
    >>> what_trade_is_possible(-2, 3, -2)
    -1
    >>> what_trade_is_possible(-5, 3, -2)
    0
    >>> what_trade_is_possible(-5, 3, 1)
    1
    >>> what_trade_is_possible(-5, 3, 2)
    2
    >>> what_trade_is_possible(-5, 3, 2)
    2
    >>> what_trade_is_possible(-5, 3, 7)
    7
    >>> what_trade_is_possible(-5, 3, 9)
    8
    >>> what_trade_is_possible(-3, 3, 7)
    6
    >>> what_trade_is_possible(3, 3, -7)
    -6

    """
    if proposed_trade==0:
        return proposed_trade

    new_position = position + proposed_trade

    # position limit should be abs, but just in case...
    abs_position_limit = abs(position_limit)
    signed_position_limit = int(abs_position_limit * sign(new_position))

    if abs(new_position)<=abs_position_limit:
        ## new position is within limits
        return proposed_trade

    if position>=0 and abs(position)<=abs_position_limit:
        ## Was okay, but won't be after trade
        ## We move to the limit, either long or short depending on what the trade wanted to do
        possible_new_position = signed_position_limit
        possible_trade = possible_new_position - position

        return possible_trade

    if position>=0 and abs(position)>abs_position_limit:
        ## Was already too big
        if proposed_trade>=0:
            # want to buy when already too big
            return 0
        if new_position>0:
            ## selling, but sell isn't big enough to get within limits
            ## we don't increase the size of a trade
            return proposed_trade
        else:
            ## selling and gone out the other side
            possible_new_position = signed_position_limit
            possible_trade = possible_new_position - position

            return possible_trade

    if position<0 and abs(position)<=abs_position_limit:
        ## Was okay, but won't be after trade
        ## We move to the limit, either long or short depending on what the trade wanted to do
        possible_new_position = signed_position_limit
        possible_trade = possible_new_position - position

        return possible_trade

    if position<0 and abs(position)>abs_position_limit:
        ## Was already too big
        if proposed_trade<0:
            # want to sell when already too big
            return 0
        if new_position<0:
            ## buying but not big enough to get within limits
            ## we don't increase the size of a trade
            return proposed_trade
        else:
            # buying and gone out the other side
            possible_new_position = signed_position_limit
            possible_trade = possible_new_position - position

            return possible_trade

    raise Exception("Don't know how to handle original position %f proposed trade %f limit %f" % (position, proposed_trade, abs_position_limit))